summaryrefslogtreecommitdiff
path: root/chromium/content/browser
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/browser')
-rw-r--r--chromium/content/browser/BUILD.gn139
-rw-r--r--chromium/content/browser/DEPS10
-rw-r--r--chromium/content/browser/OWNERS4
-rw-r--r--chromium/content/browser/accessibility/accessibility_event_recorder.cc11
-rw-r--r--chromium/content/browser/accessibility/accessibility_event_recorder.h25
-rw-r--r--chromium/content/browser/accessibility/accessibility_event_recorder_mac.mm20
-rw-r--r--chromium/content/browser/accessibility/accessibility_event_recorder_win.cc74
-rw-r--r--chromium/content/browser/accessibility/accessibility_ipc_error_browsertest.cc11
-rw-r--r--chromium/content/browser/accessibility/accessibility_tree_formatter.cc18
-rw-r--r--chromium/content/browser/accessibility/accessibility_tree_formatter.h4
-rw-r--r--chromium/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc51
-rw-r--r--chromium/content/browser/accessibility/accessibility_tree_formatter_win.cc6
-rw-r--r--chromium/content/browser/accessibility/accessibility_ui.cc416
-rw-r--r--chromium/content/browser/accessibility/accessibility_ui.h43
-rw-r--r--chromium/content/browser/accessibility/accessibility_win_browsertest.cc38
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility.cc56
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility.h15
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_android.cc3
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_auralinux.cc4
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_auralinux.h6
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_auralinux_unittest.cc121
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_cocoa.mm14
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_com_win.cc259
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_com_win.h208
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager.cc101
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager.h7
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_auralinux.cc20
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_auralinux.h9
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_mac.mm22
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_win.cc18
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_state_impl.cc17
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_state_impl.h14
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_win.cc2
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_win.h4
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc24
-rw-r--r--chromium/content/browser/accessibility/cross_platform_accessibility_browsertest.cc3
-rw-r--r--chromium/content/browser/accessibility/dump_accessibility_browsertest_base.cc2
-rw-r--r--chromium/content/browser/accessibility/dump_accessibility_events_browsertest.cc21
-rw-r--r--chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc39
-rw-r--r--chromium/content/browser/accessibility/web_contents_accessibility_android.cc14
-rw-r--r--chromium/content/browser/accessibility/web_contents_accessibility_android.h2
-rw-r--r--chromium/content/browser/android/dialog_overlay_impl.h2
-rw-r--r--chromium/content/browser/android/java/gin_java_bridge_dispatcher_host.h2
-rw-r--r--chromium/content/browser/android/java/gin_java_bridge_message_filter.cc13
-rw-r--r--chromium/content/browser/android/java/gin_java_bridge_message_filter.h8
-rw-r--r--chromium/content/browser/android/javascript_injector.cc2
-rw-r--r--chromium/content/browser/android/launcher_thread.cc5
-rw-r--r--chromium/content/browser/android/overscroll_controller_android_unittest.cc1
-rw-r--r--chromium/content/browser/android/scoped_surface_request_manager.cc6
-rw-r--r--chromium/content/browser/android/scoped_surface_request_manager.h4
-rw-r--r--chromium/content/browser/android/scoped_surface_request_manager_unittest.cc18
-rw-r--r--chromium/content/browser/android/select_popup.cc33
-rw-r--r--chromium/content/browser/android/select_popup.h7
-rw-r--r--chromium/content/browser/android/synchronous_compositor_host.cc22
-rw-r--r--chromium/content/browser/android/synchronous_compositor_host.h11
-rw-r--r--chromium/content/browser/android/tap_disambiguator.cc109
-rw-r--r--chromium/content/browser/android/tap_disambiguator.h57
-rw-r--r--chromium/content/browser/appcache/appcache.cc11
-rw-r--r--chromium/content/browser/appcache/appcache.h12
-rw-r--r--chromium/content/browser/appcache/appcache_database.cc8
-rw-r--r--chromium/content/browser/appcache/appcache_database.h6
-rw-r--r--chromium/content/browser/appcache/appcache_database_unittest.cc8
-rw-r--r--chromium/content/browser/appcache/appcache_disk_cache.cc109
-rw-r--r--chromium/content/browser/appcache/appcache_disk_cache.h31
-rw-r--r--chromium/content/browser/appcache/appcache_disk_cache_unittest.cc8
-rw-r--r--chromium/content/browser/appcache/appcache_dispatcher_host.cc4
-rw-r--r--chromium/content/browser/appcache/appcache_group.cc4
-rw-r--r--chromium/content/browser/appcache/appcache_group.h6
-rw-r--r--chromium/content/browser/appcache/appcache_histograms.cc15
-rw-r--r--chromium/content/browser/appcache/appcache_histograms.h3
-rw-r--r--chromium/content/browser/appcache/appcache_host.cc42
-rw-r--r--chromium/content/browser/appcache/appcache_host.h2
-rw-r--r--chromium/content/browser/appcache/appcache_host_unittest.cc76
-rw-r--r--chromium/content/browser/appcache/appcache_internals_ui.cc39
-rw-r--r--chromium/content/browser/appcache/appcache_internals_ui.h3
-rw-r--r--chromium/content/browser/appcache/appcache_job.cc4
-rw-r--r--chromium/content/browser/appcache/appcache_manifest_parser.h6
-rw-r--r--chromium/content/browser/appcache/appcache_manifest_parser_unittest.cc19
-rw-r--r--chromium/content/browser/appcache/appcache_quota_client.cc16
-rw-r--r--chromium/content/browser/appcache/appcache_quota_client.h7
-rw-r--r--chromium/content/browser/appcache/appcache_request_handler.cc41
-rw-r--r--chromium/content/browser/appcache/appcache_request_handler.h13
-rw-r--r--chromium/content/browser/appcache/appcache_response.cc208
-rw-r--r--chromium/content/browser/appcache/appcache_response.h83
-rw-r--r--chromium/content/browser/appcache/appcache_response_unittest.cc71
-rw-r--r--chromium/content/browser/appcache/appcache_service_impl.cc69
-rw-r--r--chromium/content/browser/appcache/appcache_service_impl.h27
-rw-r--r--chromium/content/browser/appcache/appcache_service_unittest.cc23
-rw-r--r--chromium/content/browser/appcache/appcache_storage.cc7
-rw-r--r--chromium/content/browser/appcache/appcache_storage.h1
-rw-r--r--chromium/content/browser/appcache/appcache_storage_impl.cc35
-rw-r--r--chromium/content/browser/appcache/appcache_storage_unittest.cc26
-rw-r--r--chromium/content/browser/appcache/appcache_subresource_url_factory.cc2
-rw-r--r--chromium/content/browser/appcache/appcache_unittest.cc4
-rw-r--r--chromium/content/browser/appcache/appcache_update_job.cc14
-rw-r--r--chromium/content/browser/appcache/appcache_update_job.h1
-rw-r--r--chromium/content/browser/appcache/appcache_update_job_unittest.cc98
-rw-r--r--chromium/content/browser/appcache/appcache_update_url_fetcher.cc7
-rw-r--r--chromium/content/browser/appcache/appcache_url_loader_job.cc77
-rw-r--r--chromium/content/browser/appcache/appcache_url_loader_job.h8
-rw-r--r--chromium/content/browser/appcache/appcache_url_loader_request.cc1
-rw-r--r--chromium/content/browser/appcache/appcache_url_request_job.cc8
-rw-r--r--chromium/content/browser/appcache/appcache_url_request_job_unittest.cc55
-rw-r--r--chromium/content/browser/appcache/mock_appcache_service.cc11
-rw-r--r--chromium/content/browser/appcache/mock_appcache_service.h5
-rw-r--r--chromium/content/browser/appcache/mock_appcache_storage.h3
-rw-r--r--chromium/content/browser/background_fetch/OWNERS3
-rw-r--r--chromium/content/browser/background_fetch/background_fetch.proto35
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_context.cc283
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_context.h105
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_data_manager.cc92
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_data_manager.h69
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_data_manager_observer.h27
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_data_manager_unittest.cc842
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_delegate_proxy.cc80
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_delegate_proxy.h28
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc32
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.cc36
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.h46
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_event_dispatcher.cc72
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_event_dispatcher.h35
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_event_dispatcher_unittest.cc172
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_job_controller.cc112
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_job_controller.h54
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_job_controller_unittest.cc169
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_request_manager.h41
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_request_match_params.cc22
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_request_match_params.h58
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_scheduler.cc136
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_scheduler.h63
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_scheduler_unittest.cc66
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_service_impl.cc83
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_service_impl.h30
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_service_unittest.cc179
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_test_base.cc12
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_test_base.h8
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_test_data_manager.cc20
-rw-r--r--chromium/content/browser/background_fetch/background_fetch_test_data_manager.h3
-rw-r--r--chromium/content/browser/background_fetch/mock_background_fetch_delegate.cc16
-rw-r--r--chromium/content/browser/background_fetch/mock_background_fetch_delegate.h9
-rw-r--r--chromium/content/browser/background_fetch/storage/README.md4
-rw-r--r--chromium/content/browser/background_fetch/storage/cleanup_task.cc8
-rw-r--r--chromium/content/browser/background_fetch/storage/cleanup_task.h2
-rw-r--r--chromium/content/browser/background_fetch/storage/create_metadata_task.cc143
-rw-r--r--chromium/content/browser/background_fetch/storage/create_metadata_task.h14
-rw-r--r--chromium/content/browser/background_fetch/storage/database_helpers.cc78
-rw-r--r--chromium/content/browser/background_fetch/storage/database_helpers.h22
-rw-r--r--chromium/content/browser/background_fetch/storage/database_task.cc73
-rw-r--r--chromium/content/browser/background_fetch/storage/database_task.h45
-rw-r--r--chromium/content/browser/background_fetch/storage/delete_registration_task.cc24
-rw-r--r--chromium/content/browser/background_fetch/storage/delete_registration_task.h6
-rw-r--r--chromium/content/browser/background_fetch/storage/get_developer_ids_task.cc8
-rw-r--r--chromium/content/browser/background_fetch/storage/get_developer_ids_task.h2
-rw-r--r--chromium/content/browser/background_fetch/storage/get_initialization_data_task.cc143
-rw-r--r--chromium/content/browser/background_fetch/storage/get_initialization_data_task.h7
-rw-r--r--chromium/content/browser/background_fetch/storage/get_registration_task.cc74
-rw-r--r--chromium/content/browser/background_fetch/storage/get_registration_task.h68
-rw-r--r--chromium/content/browser/background_fetch/storage/get_settled_fetches_task.cc145
-rw-r--r--chromium/content/browser/background_fetch/storage/get_settled_fetches_task.h26
-rw-r--r--chromium/content/browser/background_fetch/storage/image_helpers.cc72
-rw-r--r--chromium/content/browser/background_fetch/storage/image_helpers.h41
-rw-r--r--chromium/content/browser/background_fetch/storage/image_helpers_unittest.cc92
-rw-r--r--chromium/content/browser/background_fetch/storage/mark_registration_for_deletion_task.cc14
-rw-r--r--chromium/content/browser/background_fetch/storage/mark_registration_for_deletion_task.h2
-rw-r--r--chromium/content/browser/background_fetch/storage/mark_request_complete_task.cc81
-rw-r--r--chromium/content/browser/background_fetch/storage/mark_request_complete_task.h18
-rw-r--r--chromium/content/browser/background_fetch/storage/start_next_pending_request_task.cc56
-rw-r--r--chromium/content/browser/background_fetch/storage/start_next_pending_request_task.h11
-rw-r--r--chromium/content/browser/background_fetch/storage/update_registration_ui_task.cc86
-rw-r--r--chromium/content/browser/background_fetch/storage/update_registration_ui_task.h20
-rw-r--r--chromium/content/browser/bad_message.h2
-rw-r--r--chromium/content/browser/blob_storage/OWNERS4
-rw-r--r--chromium/content/browser/blob_storage/chrome_blob_storage_context.cc4
-rw-r--r--chromium/content/browser/bluetooth/bluetooth_metrics.cc3
-rw-r--r--chromium/content/browser/browser_child_process_host_impl.cc38
-rw-r--r--chromium/content/browser/browser_context.cc26
-rw-r--r--chromium/content/browser/browser_main_loop.cc69
-rw-r--r--chromium/content/browser/browser_main_loop.h5
-rw-r--r--chromium/content/browser/browser_main_loop_unittest.cc2
-rw-r--r--chromium/content/browser/browser_main_runner_impl.cc10
-rw-r--r--chromium/content/browser/browser_plugin/browser_plugin_guest.cc23
-rw-r--r--chromium/content/browser/browser_process_sub_thread.cc14
-rw-r--r--chromium/content/browser/browser_side_navigation_browsertest.cc2
-rw-r--r--chromium/content/browser/browser_thread_browsertest.cc51
-rw-r--r--chromium/content/browser/browser_thread_impl.cc81
-rw-r--r--chromium/content/browser/browser_thread_impl.h7
-rw-r--r--chromium/content/browser/browser_thread_unittest.cc91
-rw-r--r--chromium/content/browser/browsing_data/browsing_data_filter_builder_impl.cc2
-rw-r--r--chromium/content/browser/browsing_data/browsing_data_remover_impl.cc46
-rw-r--r--chromium/content/browser/browsing_data/browsing_data_remover_impl.h3
-rw-r--r--chromium/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc2
-rw-r--r--chromium/content/browser/browsing_data/clear_site_data_handler.cc449
-rw-r--r--chromium/content/browser/browsing_data/clear_site_data_handler.h162
-rw-r--r--chromium/content/browser/browsing_data/clear_site_data_handler_browsertest.cc (renamed from chromium/content/browser/browsing_data/clear_site_data_throttle_browsertest.cc)240
-rw-r--r--chromium/content/browser/browsing_data/clear_site_data_handler_unittest.cc485
-rw-r--r--chromium/content/browser/browsing_data/clear_site_data_throttle.cc63
-rw-r--r--chromium/content/browser/browsing_data/clear_site_data_throttle.h3
-rw-r--r--chromium/content/browser/browsing_data/conditional_cache_deletion_helper.cc4
-rw-r--r--chromium/content/browser/browsing_data/storage_partition_http_cache_data_remover.cc53
-rw-r--r--chromium/content/browser/browsing_data/storage_partition_http_cache_data_remover.h6
-rw-r--r--chromium/content/browser/browsing_instance.cc7
-rw-r--r--chromium/content/browser/cache_storage/OWNERS1
-rw-r--r--chromium/content/browser/cache_storage/cache_storage.cc15
-rw-r--r--chromium/content/browser/cache_storage/cache_storage.h17
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_cache.cc320
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_cache.h34
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_cache_unittest.cc779
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_context_impl.cc4
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_dispatcher_host.cc22
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_dispatcher_host.h2
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_manager.cc2
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_manager.h4
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_manager_unittest.cc75
-rw-r--r--chromium/content/browser/child_process_launcher.cc1
-rw-r--r--chromium/content/browser/child_process_launcher.h8
-rw-r--r--chromium/content/browser/child_process_launcher_helper.cc8
-rw-r--r--chromium/content/browser/child_process_launcher_helper_android.cc3
-rw-r--r--chromium/content/browser/child_process_launcher_helper_mac.cc20
-rw-r--r--chromium/content/browser/child_process_security_policy_impl.cc4
-rw-r--r--chromium/content/browser/cocoa/system_hotkey_helper_mac.mm8
-rw-r--r--chromium/content/browser/code_cache/generated_code_cache.cc179
-rw-r--r--chromium/content/browser/code_cache/generated_code_cache.h27
-rw-r--r--chromium/content/browser/code_cache/generated_code_cache_context.cc37
-rw-r--r--chromium/content/browser/code_cache/generated_code_cache_context.h51
-rw-r--r--chromium/content/browser/code_cache/generated_code_cache_unittest.cc95
-rw-r--r--chromium/content/browser/compositor/DEPS2
-rw-r--r--chromium/content/browser/compositor/browser_compositor_output_surface.cc2
-rw-r--r--chromium/content/browser/compositor/gpu_browser_compositor_output_surface.cc10
-rw-r--r--chromium/content/browser/compositor/gpu_browser_compositor_output_surface.h4
-rw-r--r--chromium/content/browser/compositor/gpu_output_surface_mac.cc4
-rw-r--r--chromium/content/browser/compositor/gpu_output_surface_mac.h2
-rw-r--r--chromium/content/browser/compositor/gpu_process_transport_factory.cc58
-rw-r--r--chromium/content/browser/compositor/gpu_process_transport_factory.h20
-rw-r--r--chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc9
-rw-r--r--chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h5
-rw-r--r--chromium/content/browser/compositor/image_transport_factory.h9
-rw-r--r--chromium/content/browser/compositor/image_transport_factory_browsertest.cc38
-rw-r--r--chromium/content/browser/compositor/offscreen_browser_compositor_output_surface.cc4
-rw-r--r--chromium/content/browser/compositor/offscreen_browser_compositor_output_surface.h4
-rw-r--r--chromium/content/browser/compositor/owned_mailbox.cc63
-rw-r--r--chromium/content/browser/compositor/owned_mailbox.h37
-rw-r--r--chromium/content/browser/compositor/reflector_impl.cc18
-rw-r--r--chromium/content/browser/compositor/reflector_impl_unittest.cc18
-rw-r--r--chromium/content/browser/compositor/reflector_texture.cc46
-rw-r--r--chromium/content/browser/compositor/reflector_texture.h11
-rw-r--r--chromium/content/browser/compositor/viz_process_transport_factory.cc50
-rw-r--r--chromium/content/browser/compositor/viz_process_transport_factory.h13
-rw-r--r--chromium/content/browser/compositor/vulkan_browser_compositor_output_surface.cc2
-rw-r--r--chromium/content/browser/cross_site_transfer_browsertest.cc24
-rw-r--r--chromium/content/browser/dedicated_worker/dedicated_worker_host.cc9
-rw-r--r--chromium/content/browser/devtools/DEPS1
-rw-r--r--chromium/content/browser/devtools/browser_devtools_agent_host.cc9
-rw-r--r--chromium/content/browser/devtools/browser_devtools_agent_host.h7
-rw-r--r--chromium/content/browser/devtools/devtools_agent_host_impl.cc14
-rw-r--r--chromium/content/browser/devtools/devtools_agent_host_impl.h7
-rw-r--r--chromium/content/browser/devtools/devtools_frame_trace_recorder.cc8
-rw-r--r--chromium/content/browser/devtools/devtools_frame_trace_recorder.h4
-rw-r--r--chromium/content/browser/devtools/devtools_http_handler.cc4
-rw-r--r--chromium/content/browser/devtools/devtools_http_handler_unittest.cc3
-rw-r--r--chromium/content/browser/devtools/devtools_pipe_handler.cc6
-rw-r--r--chromium/content/browser/devtools/devtools_session.cc64
-rw-r--r--chromium/content/browser/devtools/devtools_session.h23
-rw-r--r--chromium/content/browser/devtools/devtools_stream_file.cc8
-rw-r--r--chromium/content/browser/devtools/devtools_url_interceptor_request_job.cc31
-rw-r--r--chromium/content/browser/devtools/devtools_url_interceptor_request_job.h2
-rw-r--r--chromium/content/browser/devtools/devtools_url_loader_interceptor.cc64
-rw-r--r--chromium/content/browser/devtools/devtools_url_request_interceptor.cc28
-rw-r--r--chromium/content/browser/devtools/devtools_url_request_interceptor.h9
-rw-r--r--chromium/content/browser/devtools/devtools_video_consumer.cc38
-rw-r--r--chromium/content/browser/devtools/devtools_video_consumer.h4
-rw-r--r--chromium/content/browser/devtools/devtools_video_consumer_unittest.cc51
-rw-r--r--chromium/content/browser/devtools/protocol/browser_handler.cc133
-rw-r--r--chromium/content/browser/devtools/protocol/browser_handler.h21
-rw-r--r--chromium/content/browser/devtools/protocol/devtools_download_manager_delegate.cc2
-rw-r--r--chromium/content/browser/devtools/protocol/devtools_download_manager_helper.cc3
-rw-r--r--chromium/content/browser/devtools/protocol/devtools_protocol_browsertest.cc337
-rw-r--r--chromium/content/browser/devtools/protocol/devtools_protocol_test_support.cc285
-rw-r--r--chromium/content/browser/devtools/protocol/devtools_protocol_test_support.h150
-rw-r--r--chromium/content/browser/devtools/protocol/input_handler.cc52
-rw-r--r--chromium/content/browser/devtools/protocol/input_handler.h3
-rw-r--r--chromium/content/browser/devtools/protocol/memory_handler.cc32
-rw-r--r--chromium/content/browser/devtools/protocol/page_handler.cc83
-rw-r--r--chromium/content/browser/devtools/protocol/page_handler.h6
-rw-r--r--chromium/content/browser/devtools/protocol/service_worker_handler.cc7
-rw-r--r--chromium/content/browser/devtools/protocol/system_info_handler.cc3
-rw-r--r--chromium/content/browser/devtools/protocol/target_handler.cc108
-rw-r--r--chromium/content/browser/devtools/protocol/target_handler.h8
-rw-r--r--chromium/content/browser/devtools/protocol/tethering_handler.cc19
-rw-r--r--chromium/content/browser/devtools/protocol/tracing_handler.cc71
-rw-r--r--chromium/content/browser/devtools/protocol/tracing_handler.h6
-rw-r--r--chromium/content/browser/devtools/protocol_config.json11
-rw-r--r--chromium/content/browser/devtools/render_frame_devtools_agent_host.cc54
-rw-r--r--chromium/content/browser/devtools/render_frame_devtools_agent_host.h4
-rw-r--r--chromium/content/browser/devtools/service_worker_devtools_manager.h2
-rw-r--r--chromium/content/browser/devtools/target_registry.cc65
-rw-r--r--chromium/content/browser/devtools/target_registry.h18
-rw-r--r--chromium/content/browser/display_cutout/display_cutout_host_impl.cc37
-rw-r--r--chromium/content/browser/display_cutout/display_cutout_host_impl.h36
-rw-r--r--chromium/content/browser/do_not_track_browsertest.cc97
-rw-r--r--chromium/content/browser/dom_storage/OWNERS4
-rw-r--r--chromium/content/browser/dom_storage/README.md105
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_context_impl.h2
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_context_wrapper.cc20
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_context_wrapper.h2
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_database.cc58
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_database.h17
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_database_unittest.cc86
-rw-r--r--chromium/content/browser/dom_storage/local_storage_context_mojo.cc4
-rw-r--r--chromium/content/browser/dom_storage/local_storage_context_mojo_unittest.cc2
-rw-r--r--chromium/content/browser/dom_storage/session_storage_area_impl_unittest.cc2
-rw-r--r--chromium/content/browser/dom_storage/session_storage_context_mojo.cc87
-rw-r--r--chromium/content/browser/dom_storage/session_storage_context_mojo.h23
-rw-r--r--chromium/content/browser/dom_storage/session_storage_context_mojo_unittest.cc40
-rw-r--r--chromium/content/browser/dom_storage/session_storage_database.cc7
-rw-r--r--chromium/content/browser/dom_storage/session_storage_namespace_impl_mojo.cc53
-rw-r--r--chromium/content/browser/dom_storage/session_storage_namespace_impl_mojo.h46
-rw-r--r--chromium/content/browser/dom_storage/session_storage_namespace_impl_mojo_unittest.cc93
-rw-r--r--chromium/content/browser/dom_storage/storage_area_impl_unittest.cc157
-rw-r--r--chromium/content/browser/download/download_browsertest.cc22
-rw-r--r--chromium/content/browser/download/download_manager_impl.cc116
-rw-r--r--chromium/content/browser/download/download_manager_impl.h28
-rw-r--r--chromium/content/browser/download/download_manager_impl_unittest.cc1
-rw-r--r--chromium/content/browser/download/download_request_core.cc10
-rw-r--r--chromium/content/browser/download/download_request_core.h5
-rw-r--r--chromium/content/browser/download/download_url_loader_factory_getter_impl.cc25
-rw-r--r--chromium/content/browser/download/download_url_loader_factory_getter_impl.h39
-rw-r--r--chromium/content/browser/download/download_utils.cc2
-rw-r--r--chromium/content/browser/download/file_download_url_loader_factory_getter.cc6
-rw-r--r--chromium/content/browser/download/file_system_download_url_loader_factory_getter.cc52
-rw-r--r--chromium/content/browser/download/file_system_download_url_loader_factory_getter.h50
-rw-r--r--chromium/content/browser/download/mhtml_generation_browsertest.cc27
-rw-r--r--chromium/content/browser/download/save_package.cc6
-rw-r--r--chromium/content/browser/file_url_loader_factory.cc213
-rw-r--r--chromium/content/browser/fileapi/browser_file_system_helper.cc2
-rw-r--r--chromium/content/browser/fileapi/file_system_chooser.cc105
-rw-r--r--chromium/content/browser/fileapi/file_system_chooser.h55
-rw-r--r--chromium/content/browser/fileapi/file_system_manager_impl.cc872
-rw-r--r--chromium/content/browser/fileapi/file_system_manager_impl.h237
-rw-r--r--chromium/content/browser/fileapi/file_system_operation_runner_unittest.cc6
-rw-r--r--chromium/content/browser/fileapi/file_system_url_loader_factory.cc13
-rw-r--r--chromium/content/browser/fileapi/file_system_url_loader_factory_browsertest.cc1
-rw-r--r--chromium/content/browser/fileapi/fileapi_message_filter.cc642
-rw-r--r--chromium/content/browser/fileapi/fileapi_message_filter.h194
-rw-r--r--chromium/content/browser/fileapi/fileapi_message_filter_unittest.cc129
-rw-r--r--chromium/content/browser/find_in_page_client.cc67
-rw-r--r--chromium/content/browser/find_in_page_client.h54
-rw-r--r--chromium/content/browser/find_request_manager.cc203
-rw-r--r--chromium/content/browser/find_request_manager.h54
-rw-r--r--chromium/content/browser/find_request_manager_browsertest.cc17
-rw-r--r--chromium/content/browser/font_unique_name_lookup/OWNERS3
-rw-r--r--chromium/content/browser/font_unique_name_lookup/font_unique_name_browsertest.cc140
-rw-r--r--chromium/content/browser/font_unique_name_lookup/font_unique_name_lookup.cc347
-rw-r--r--chromium/content/browser/font_unique_name_lookup/font_unique_name_lookup.h138
-rw-r--r--chromium/content/browser/font_unique_name_lookup/font_unique_name_lookup_service.cc50
-rw-r--r--chromium/content/browser/font_unique_name_lookup/font_unique_name_lookup_service.h36
-rw-r--r--chromium/content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest.cc334
-rw-r--r--chromium/content/browser/frame_host/cross_process_frame_connector.cc37
-rw-r--r--chromium/content/browser/frame_host/cross_process_frame_connector.h7
-rw-r--r--chromium/content/browser/frame_host/debug_urls.cc12
-rw-r--r--chromium/content/browser/frame_host/frame_tree_browsertest.cc177
-rw-r--r--chromium/content/browser/frame_host/frame_tree_node.h2
-rw-r--r--chromium/content/browser/frame_host/interstitial_page_impl.cc29
-rw-r--r--chromium/content/browser/frame_host/interstitial_page_impl.h5
-rw-r--r--chromium/content/browser/frame_host/interstitial_page_impl_browsertest.cc24
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_android.cc6
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_impl_browsertest.cc728
-rw-r--r--chromium/content/browser/frame_host/navigation_entry_screenshot_manager.cc2
-rw-r--r--chromium/content/browser/frame_host/navigation_handle_impl.cc67
-rw-r--r--chromium/content/browser/frame_host/navigation_handle_impl.h34
-rw-r--r--chromium/content/browser/frame_host/navigation_handle_impl_browsertest.cc11
-rw-r--r--chromium/content/browser/frame_host/navigation_request.cc23
-rw-r--r--chromium/content/browser/frame_host/navigation_request.h1
-rw-r--r--chromium/content/browser/frame_host/navigator_impl_unittest.cc10
-rw-r--r--chromium/content/browser/frame_host/origin_policy_throttle.cc43
-rw-r--r--chromium/content/browser/frame_host/origin_policy_throttle.h11
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_android.h2
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_delegate.cc5
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_delegate.h15
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_impl.cc453
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_impl.h70
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_impl_browsertest.cc85
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_manager.cc34
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_manager_browsertest.cc398
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_manager_unittest.cc8
-rw-r--r--chromium/content/browser/frame_host/render_frame_message_filter.cc54
-rw-r--r--chromium/content/browser/frame_host/render_frame_message_filter.h5
-rw-r--r--chromium/content/browser/frame_host/render_frame_proxy_host.cc28
-rw-r--r--chromium/content/browser/frame_host/render_widget_host_view_guest.cc36
-rw-r--r--chromium/content/browser/frame_host/render_widget_host_view_guest.h12
-rw-r--r--chromium/content/browser/frame_host/render_widget_host_view_guest_unittest.cc6
-rw-r--r--chromium/content/browser/geolocation/geolocation_service_impl.cc4
-rw-r--r--chromium/content/browser/geolocation/geolocation_service_impl_unittest.cc9
-rw-r--r--chromium/content/browser/gpu/browser_gpu_channel_host_factory.cc67
-rw-r--r--chromium/content/browser/gpu/browser_gpu_channel_host_factory.h10
-rw-r--r--chromium/content/browser/gpu/browser_gpu_client_delegate.cc82
-rw-r--r--chromium/content/browser/gpu/browser_gpu_client_delegate.h30
-rw-r--r--chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.cc498
-rw-r--r--chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.h143
-rw-r--r--chromium/content/browser/gpu/compositor_util.cc20
-rw-r--r--chromium/content/browser/gpu/gpu_client.cc28
-rw-r--r--chromium/content/browser/gpu/gpu_client_impl.cc220
-rw-r--r--chromium/content/browser/gpu/gpu_client_impl.h95
-rw-r--r--chromium/content/browser/gpu/gpu_data_manager_impl_private.cc7
-rw-r--r--chromium/content/browser/gpu/gpu_internals_ui.cc3
-rw-r--r--chromium/content/browser/gpu/gpu_ipc_browsertests.cc30
-rw-r--r--chromium/content/browser/gpu/gpu_memory_buffer_manager_singleton.cc50
-rw-r--r--chromium/content/browser/gpu/gpu_memory_buffer_manager_singleton.h28
-rw-r--r--chromium/content/browser/gpu/gpu_process_host.cc522
-rw-r--r--chromium/content/browser/gpu/gpu_process_host.h161
-rw-r--r--chromium/content/browser/histogram_controller.cc2
-rw-r--r--chromium/content/browser/hyphenation/hyphenation_impl.cc2
-rw-r--r--chromium/content/browser/indexed_db/OWNERS1
-rw-r--r--chromium/content/browser/indexed_db/cursor_impl.cc10
-rw-r--r--chromium/content/browser/indexed_db/cursor_impl.h26
-rw-r--r--chromium/content/browser/indexed_db/database_impl.cc46
-rw-r--r--chromium/content/browser/indexed_db/database_impl.h74
-rw-r--r--chromium/content/browser/indexed_db/fake_indexed_db_metadata_coding.cc11
-rw-r--r--chromium/content/browser/indexed_db/fake_indexed_db_metadata_coding.h49
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_backing_store.cc162
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_backing_store.h96
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_backing_store_unittest.cc152
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_blob_info.cc29
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_blob_info.h14
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_browsertest.cc2
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_callbacks.cc85
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_callbacks.h47
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_class_factory.h2
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_context_impl.cc13
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_context_impl.h4
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_cursor.cc2
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_cursor.h17
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_data_loss_info.h2
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_database.cc52
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_database.h103
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_database_callbacks.cc16
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_database_callbacks.h7
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_database_unittest.cc7
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_dispatcher_host.cc33
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_dispatcher_host.h32
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc141
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_factory.h1
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_factory_impl.cc14
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_factory_impl.h1
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_factory_unittest.cc7
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_fake_backing_store.cc7
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_fake_backing_store.h57
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_index_writer.cc8
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_index_writer.h30
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_internals_ui.cc66
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_internals_ui.h10
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_leveldb_coding.cc4
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_leveldb_coding.h34
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc4
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_leveldb_operations.cc3
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_leveldb_operations.h4
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_metadata_coding.cc7
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_metadata_coding.h52
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_observer.h2
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_pre_close_task_queue.cc10
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_pre_close_task_queue.h15
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_pre_close_task_queue_unittest.cc4
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_reporting.h1
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_return_value.h9
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_tombstone_sweeper.cc6
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_tombstone_sweeper.h20
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_tombstone_sweeper_unittest.cc10
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_transaction.cc14
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_transaction.h10
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_transaction_coordinator.cc2
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_unittest.cc1
-rw-r--r--chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc2
-rw-r--r--chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h2
-rw-r--r--chromium/content/browser/indexed_db/mock_indexed_db_callbacks.cc5
-rw-r--r--chromium/content/browser/indexed_db/mock_indexed_db_callbacks.h11
-rw-r--r--chromium/content/browser/indexed_db/mock_indexed_db_factory.h1
-rw-r--r--chromium/content/browser/indexed_db/mock_mojo_indexed_db_callbacks.cc4
-rw-r--r--chromium/content/browser/indexed_db/mock_mojo_indexed_db_callbacks.h91
-rw-r--r--chromium/content/browser/indexed_db/mock_mojo_indexed_db_database_callbacks.cc4
-rw-r--r--chromium/content/browser/indexed_db/mock_mojo_indexed_db_database_callbacks.h12
-rw-r--r--chromium/content/browser/indexed_db/scopes/README.md184
-rw-r--r--chromium/content/browser/indexed_db/scopes/disjoint_range_lock_manager.cc166
-rw-r--r--chromium/content/browser/indexed_db/scopes/disjoint_range_lock_manager.h127
-rw-r--r--chromium/content/browser/indexed_db/scopes/disjoint_range_lock_manager_unittest.cc221
-rw-r--r--chromium/content/browser/indexed_db/scopes/scopes_lock_manager.cc61
-rw-r--r--chromium/content/browser/indexed_db/scopes/scopes_lock_manager.h103
-rw-r--r--chromium/content/browser/indexed_db/scopes/scopes_lock_manager_unittest.cc17
-rw-r--r--chromium/content/browser/isolated_origin_browsertest.cc20
-rw-r--r--chromium/content/browser/keyboard_lock/keyboard_lock_service_impl.cc18
-rw-r--r--chromium/content/browser/keyboard_lock/keyboard_lock_service_impl.h12
-rw-r--r--chromium/content/browser/loader/cross_site_document_blocking_browsertest.cc45
-rw-r--r--chromium/content/browser/loader/cross_site_document_resource_handler.cc74
-rw-r--r--chromium/content/browser/loader/cross_site_document_resource_handler.h8
-rw-r--r--chromium/content/browser/loader/cross_site_document_resource_handler_unittest.cc10
-rw-r--r--chromium/content/browser/loader/global_routing_id.h72
-rw-r--r--chromium/content/browser/loader/loader_browsertest.cc100
-rw-r--r--chromium/content/browser/loader/loader_io_thread_notifier.cc2
-rw-r--r--chromium/content/browser/loader/merkle_integrity_source_stream.cc36
-rw-r--r--chromium/content/browser/loader/merkle_integrity_source_stream.h4
-rw-r--r--chromium/content/browser/loader/merkle_integrity_source_stream_unittest.cc76
-rw-r--r--chromium/content/browser/loader/mime_sniffing_resource_handler.cc1
-rw-r--r--chromium/content/browser/loader/mime_sniffing_resource_handler_unittest.cc4
-rw-r--r--chromium/content/browser/loader/mojo_async_resource_handler.cc50
-rw-r--r--chromium/content/browser/loader/mojo_async_resource_handler.h16
-rw-r--r--chromium/content/browser/loader/mojo_async_resource_handler_unittest.cc57
-rw-r--r--chromium/content/browser/loader/navigation_loader_interceptor.h32
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_delegate.h3
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_impl.cc449
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_impl.h6
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_impl_unittest.cc14
-rw-r--r--chromium/content/browser/loader/prefetch_browsertest.cc74
-rw-r--r--chromium/content/browser/loader/resource_dispatcher_host_impl.cc62
-rw-r--r--chromium/content/browser/loader/resource_dispatcher_host_impl.h12
-rw-r--r--chromium/content/browser/loader/resource_dispatcher_host_unittest.cc20
-rw-r--r--chromium/content/browser/loader/resource_hints_impl.cc2
-rw-r--r--chromium/content/browser/loader/resource_loader.cc6
-rw-r--r--chromium/content/browser/loader/resource_request_info_impl.cc6
-rw-r--r--chromium/content/browser/loader/resource_request_info_impl.h1
-rw-r--r--chromium/content/browser/loader/resource_requester_info.cc29
-rw-r--r--chromium/content/browser/loader/url_loader_factory_impl_unittest.cc29
-rw-r--r--chromium/content/browser/locks/lock_manager.cc2
-rw-r--r--chromium/content/browser/mach_broker_mac.mm14
-rw-r--r--chromium/content/browser/mach_broker_mac_unittest.cc4
-rw-r--r--chromium/content/browser/media/android/browser_media_player_manager.h13
-rw-r--r--chromium/content/browser/media/android/media_player_renderer_web_contents_observer.cc3
-rw-r--r--chromium/content/browser/media/android/media_resource_getter_impl.cc2
-rw-r--r--chromium/content/browser/media/audio_input_stream_broker.cc3
-rw-r--r--chromium/content/browser/media/audio_input_stream_broker.h3
-rw-r--r--chromium/content/browser/media/audio_input_stream_broker_unittest.cc25
-rw-r--r--chromium/content/browser/media/audio_output_stream_broker.cc4
-rw-r--r--chromium/content/browser/media/audio_output_stream_broker.h2
-rw-r--r--chromium/content/browser/media/audio_output_stream_broker_unittest.cc10
-rw-r--r--chromium/content/browser/media/audio_stream_broker.cc8
-rw-r--r--chromium/content/browser/media/audio_stream_broker.h4
-rw-r--r--chromium/content/browser/media/audio_stream_monitor.cc7
-rw-r--r--chromium/content/browser/media/capture/OWNERS4
-rw-r--r--chromium/content/browser/media/capture/audio_mirroring_manager.cc33
-rw-r--r--chromium/content/browser/media/capture/audio_mirroring_manager.h29
-rw-r--r--chromium/content/browser/media/capture/audio_mirroring_manager_unittest.cc40
-rw-r--r--chromium/content/browser/media/capture/aura_window_video_capture_device.cc27
-rw-r--r--chromium/content/browser/media/capture/cursor_renderer.cc353
-rw-r--r--chromium/content/browser/media/capture/cursor_renderer.h204
-rw-r--r--chromium/content/browser/media/capture/cursor_renderer_aura.cc142
-rw-r--r--chromium/content/browser/media/capture/cursor_renderer_aura.h43
-rw-r--r--chromium/content/browser/media/capture/cursor_renderer_aura_unittest.cc261
-rw-r--r--chromium/content/browser/media/capture/cursor_renderer_mac.h63
-rw-r--r--chromium/content/browser/media/capture/cursor_renderer_mac.mm140
-rw-r--r--chromium/content/browser/media/capture/cursor_renderer_mac_unittest.mm227
-rw-r--r--chromium/content/browser/media/capture/desktop_capture_device.cc4
-rw-r--r--chromium/content/browser/media/capture/desktop_capture_device_unittest.cc113
-rw-r--r--chromium/content/browser/media/capture/desktop_streams_registry_impl.cc113
-rw-r--r--chromium/content/browser/media/capture/desktop_streams_registry_impl.h66
-rw-r--r--chromium/content/browser/media/capture/fake_video_capture_stack.cc33
-rw-r--r--chromium/content/browser/media/capture/frame_sink_video_capture_device.cc144
-rw-r--r--chromium/content/browser/media/capture/frame_sink_video_capture_device.h42
-rw-r--r--chromium/content/browser/media/capture/frame_sink_video_capture_device_unittest.cc56
-rw-r--r--chromium/content/browser/media/capture/lame_capture_overlay_chromeos.cc178
-rw-r--r--chromium/content/browser/media/capture/lame_capture_overlay_chromeos.h88
-rw-r--r--chromium/content/browser/media/capture/lame_capture_overlay_chromeos_unittest.cc174
-rw-r--r--chromium/content/browser/media/capture/lame_window_capturer_chromeos.cc96
-rw-r--r--chromium/content/browser/media/capture/lame_window_capturer_chromeos.h16
-rw-r--r--chromium/content/browser/media/capture/mouse_cursor_overlay_controller.cc166
-rw-r--r--chromium/content/browser/media/capture/mouse_cursor_overlay_controller.h164
-rw-r--r--chromium/content/browser/media/capture/mouse_cursor_overlay_controller_aura.cc226
-rw-r--r--chromium/content/browser/media/capture/mouse_cursor_overlay_controller_browsertest.cc260
-rw-r--r--chromium/content/browser/media/capture/mouse_cursor_overlay_controller_mac.mm198
-rw-r--r--chromium/content/browser/media/capture/screen_capture_device_android.cc11
-rw-r--r--chromium/content/browser/media/capture/screen_capture_device_android_unittest.cc8
-rw-r--r--chromium/content/browser/media/capture/web_contents_audio_input_stream.cc33
-rw-r--r--chromium/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc4
-rw-r--r--chromium/content/browser/media/capture/web_contents_audio_muter.cc25
-rw-r--r--chromium/content/browser/media/capture/web_contents_video_capture_device.cc25
-rw-r--r--chromium/content/browser/media/cdm_file_impl.cc2
-rw-r--r--chromium/content/browser/media/flinging_renderer.cc45
-rw-r--r--chromium/content/browser/media/flinging_renderer.h16
-rw-r--r--chromium/content/browser/media/flinging_renderer_unittest.cc64
-rw-r--r--chromium/content/browser/media/forwarding_audio_stream_factory.cc85
-rw-r--r--chromium/content/browser/media/forwarding_audio_stream_factory.h14
-rw-r--r--chromium/content/browser/media/forwarding_audio_stream_factory_unittest.cc43
-rw-r--r--chromium/content/browser/media/in_process_audio_loopback_stream_creator.cc44
-rw-r--r--chromium/content/browser/media/in_process_audio_loopback_stream_creator.h41
-rw-r--r--chromium/content/browser/media/media_browsertest.cc47
-rw-r--r--chromium/content/browser/media/media_canplaytype_browsertest.cc22
-rw-r--r--chromium/content/browser/media/media_color_browsertest.cc46
-rw-r--r--chromium/content/browser/media/media_devices_permission_checker.cc12
-rw-r--r--chromium/content/browser/media/media_devices_permission_checker_unittest.cc12
-rw-r--r--chromium/content/browser/media/media_internals.cc61
-rw-r--r--chromium/content/browser/media/media_internals.h17
-rw-r--r--chromium/content/browser/media/media_internals_proxy.cc5
-rw-r--r--chromium/content/browser/media/media_internals_unittest.cc151
-rw-r--r--chromium/content/browser/media/media_source_browsertest.cc7
-rw-r--r--chromium/content/browser/media/media_web_contents_observer.cc33
-rw-r--r--chromium/content/browser/media/media_web_contents_observer.h10
-rw-r--r--chromium/content/browser/media/session/audio_focus_delegate.h11
-rw-r--r--chromium/content/browser/media/session/audio_focus_delegate_android.cc15
-rw-r--r--chromium/content/browser/media/session/audio_focus_delegate_android.h9
-rw-r--r--chromium/content/browser/media/session/audio_focus_delegate_default.cc30
-rw-r--r--chromium/content/browser/media/session/audio_focus_delegate_default_browsertest.cc4
-rw-r--r--chromium/content/browser/media/session/audio_focus_manager.cc120
-rw-r--r--chromium/content/browser/media/session/audio_focus_manager.h45
-rw-r--r--chromium/content/browser/media/session/audio_focus_manager_unittest.cc217
-rw-r--r--chromium/content/browser/media/session/audio_focus_observer.cc46
-rw-r--r--chromium/content/browser/media/session/audio_focus_observer.h47
-rw-r--r--chromium/content/browser/media/session/media_session_android.cc3
-rw-r--r--chromium/content/browser/media/session/media_session_browsertest.cc24
-rw-r--r--chromium/content/browser/media/session/media_session_controller.cc25
-rw-r--r--chromium/content/browser/media/session/media_session_controller.h12
-rw-r--r--chromium/content/browser/media/session/media_session_controllers_manager.cc35
-rw-r--r--chromium/content/browser/media/session/media_session_controllers_manager.h3
-rw-r--r--chromium/content/browser/media/session/media_session_controllers_manager_unittest.cc6
-rw-r--r--chromium/content/browser/media/session/media_session_impl.cc91
-rw-r--r--chromium/content/browser/media/session/media_session_impl.h47
-rw-r--r--chromium/content/browser/media/session/media_session_impl_browsertest.cc58
-rw-r--r--chromium/content/browser/media/session/media_session_impl_visibility_browsertest.cc3
-rw-r--r--chromium/content/browser/media/session/pepper_playback_observer.cc7
-rw-r--r--chromium/content/browser/media/session/pepper_player_delegate.cc8
-rw-r--r--chromium/content/browser/media/video_decoder_proxy.cc96
-rw-r--r--chromium/content/browser/media/video_decoder_proxy.h58
-rw-r--r--chromium/content/browser/media/webaudio/OWNERS4
-rw-r--r--chromium/content/browser/media/webaudio/audio_context_manager_browsertest.cc75
-rw-r--r--chromium/content/browser/media/webaudio/audio_context_manager_impl.cc50
-rw-r--r--chromium/content/browser/media/webaudio/audio_context_manager_impl.h44
-rw-r--r--chromium/content/browser/net/quota_policy_cookie_store.cc14
-rw-r--r--chromium/content/browser/net/quota_policy_cookie_store_unittest.cc8
-rw-r--r--chromium/content/browser/net/reporting_service_proxy.cc19
-rw-r--r--chromium/content/browser/network_service_browsertest.cc25
-rw-r--r--chromium/content/browser/network_service_client.cc50
-rw-r--r--chromium/content/browser/network_service_client.h8
-rw-r--r--chromium/content/browser/network_service_instance.cc57
-rw-r--r--chromium/content/browser/network_service_restart_browsertest.cc42
-rw-r--r--chromium/content/browser/notification_service_impl.h3
-rw-r--r--chromium/content/browser/notifications/OWNERS1
-rw-r--r--chromium/content/browser/notifications/blink_notification_service_impl.cc6
-rw-r--r--chromium/content/browser/notifications/notification_database.cc29
-rw-r--r--chromium/content/browser/notifications/notification_database.h13
-rw-r--r--chromium/content/browser/notifications/notification_database_data_conversions.cc19
-rw-r--r--chromium/content/browser/notifications/notification_database_unittest.cc15
-rw-r--r--chromium/content/browser/notifications/notification_event_dispatcher_impl.cc26
-rw-r--r--chromium/content/browser/notifications/notification_storage.cc153
-rw-r--r--chromium/content/browser/notifications/notification_storage.h59
-rw-r--r--chromium/content/browser/notifications/notification_storage_unittest.cc253
-rw-r--r--chromium/content/browser/notifications/platform_notification_context_impl.cc21
-rw-r--r--chromium/content/browser/notifications/platform_notification_context_impl.h6
-rw-r--r--chromium/content/browser/notifications/platform_notification_context_unittest.cc34
-rw-r--r--chromium/content/browser/oop_browsertest.cc2
-rw-r--r--chromium/content/browser/payments/payment_app_browsertest.cc55
-rw-r--r--chromium/content/browser/payments/payment_app_content_unittest_base.h2
-rw-r--r--chromium/content/browser/payments/payment_app_context_impl.h2
-rw-r--r--chromium/content/browser/payments/payment_app_database.cc9
-rw-r--r--chromium/content/browser/payments/payment_app_database.h2
-rw-r--r--chromium/content/browser/payments/payment_app_info_fetcher.cc21
-rw-r--r--chromium/content/browser/payments/payment_app_info_fetcher.h5
-rw-r--r--chromium/content/browser/payments/payment_app_provider_impl_unittest.cc2
-rw-r--r--chromium/content/browser/payments/payment_instrument_icon_fetcher.cc21
-rw-r--r--chromium/content/browser/payments/payment_instrument_icon_fetcher.h6
-rw-r--r--chromium/content/browser/payments/payment_manager.h2
-rw-r--r--chromium/content/browser/payments/payment_manager_unittest.cc2
-rw-r--r--chromium/content/browser/permissions/permission_controller_impl.cc168
-rw-r--r--chromium/content/browser/permissions/permission_controller_impl.h21
-rw-r--r--chromium/content/browser/permissions/permission_service_context.cc7
-rw-r--r--chromium/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc31
-rw-r--r--chromium/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h10
-rw-r--r--chromium/content/browser/plugin_data_remover_impl.cc2
-rw-r--r--chromium/content/browser/plugin_service_impl.cc54
-rw-r--r--chromium/content/browser/plugin_service_impl.h17
-rw-r--r--chromium/content/browser/plugin_service_impl_unittest.cc2
-rw-r--r--chromium/content/browser/pointer_lock_browsertest.cc183
-rw-r--r--chromium/content/browser/portal/portal.cc77
-rw-r--r--chromium/content/browser/portal/portal.h78
-rw-r--r--chromium/content/browser/portal/portal_browsertest.cc255
-rw-r--r--chromium/content/browser/portal/portal_unit_test.cc35
-rw-r--r--chromium/content/browser/ppapi_plugin_process_host.cc4
-rw-r--r--chromium/content/browser/presentation/OWNERS5
-rw-r--r--chromium/content/browser/presentation/presentation_service_impl.cc71
-rw-r--r--chromium/content/browser/presentation/presentation_service_impl.h32
-rw-r--r--chromium/content/browser/presentation/presentation_service_impl_unittest.cc323
-rw-r--r--chromium/content/browser/push_messaging/push_messaging_manager.cc11
-rw-r--r--chromium/content/browser/push_messaging/push_messaging_router.cc19
-rw-r--r--chromium/content/browser/push_messaging/push_messaging_router.h10
-rw-r--r--chromium/content/browser/renderer_host/DEPS2
-rw-r--r--chromium/content/browser/renderer_host/browser_compositor_view_mac.h6
-rw-r--r--chromium/content/browser/renderer_host/browser_compositor_view_mac.mm22
-rw-r--r--chromium/content/browser/renderer_host/compositor_impl_android.cc294
-rw-r--r--chromium/content/browser/renderer_host/compositor_impl_android.h17
-rw-r--r--chromium/content/browser/renderer_host/compositor_impl_android_browsertest.cc5
-rw-r--r--chromium/content/browser/renderer_host/cursor_manager.cc2
-rw-r--r--chromium/content/browser/renderer_host/delegated_frame_host.cc131
-rw-r--r--chromium/content/browser/renderer_host/delegated_frame_host.h26
-rw-r--r--chromium/content/browser/renderer_host/delegated_frame_host_client_android.cc45
-rw-r--r--chromium/content/browser/renderer_host/delegated_frame_host_client_android.h42
-rw-r--r--chromium/content/browser/renderer_host/delegated_frame_host_client_aura.cc13
-rw-r--r--chromium/content/browser/renderer_host/delegated_frame_host_client_aura.h1
-rw-r--r--chromium/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc2
-rw-r--r--chromium/content/browser/renderer_host/frame_connector_delegate.h15
-rw-r--r--chromium/content/browser/renderer_host/input/autoscroll_browsertest.cc155
-rw-r--r--chromium/content/browser/renderer_host/input/fling_browsertest.cc309
-rw-r--r--chromium/content/browser/renderer_host/input/fling_controller.cc60
-rw-r--r--chromium/content/browser/renderer_host/input/fling_controller.h4
-rw-r--r--chromium/content/browser/renderer_host/input/fling_controller_unittest.cc148
-rw-r--r--chromium/content/browser/renderer_host/input/fling_scheduler.cc4
-rw-r--r--chromium/content/browser/renderer_host/input/fling_scheduler.h1
-rw-r--r--chromium/content/browser/renderer_host/input/fling_scheduler_android.cc8
-rw-r--r--chromium/content/browser/renderer_host/input/fling_scheduler_android.h1
-rw-r--r--chromium/content/browser/renderer_host/input/fling_scheduler_mac.mm23
-rw-r--r--chromium/content/browser/renderer_host/input/gesture_event_queue.cc3
-rw-r--r--chromium/content/browser/renderer_host/input/gesture_event_queue.h2
-rw-r--r--chromium/content/browser/renderer_host/input/gesture_event_queue_unittest.cc10
-rw-r--r--chromium/content/browser/renderer_host/input/input_router_client.h3
-rw-r--r--chromium/content/browser/renderer_host/input/input_router_impl.cc34
-rw-r--r--chromium/content/browser/renderer_host/input/input_router_impl.h4
-rw-r--r--chromium/content/browser/renderer_host/input/input_router_impl_unittest.cc154
-rw-r--r--chromium/content/browser/renderer_host/input/mock_input_router_client.cc7
-rw-r--r--chromium/content/browser/renderer_host/input/mock_input_router_client.h2
-rw-r--r--chromium/content/browser/renderer_host/input/motion_event_web.cc18
-rw-r--r--chromium/content/browser/renderer_host/input/motion_event_web.h2
-rw-r--r--chromium/content/browser/renderer_host/input/motion_event_web_unittest.cc9
-rw-r--r--chromium/content/browser/renderer_host/input/mouse_wheel_event_queue.cc6
-rw-r--r--chromium/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc26
-rw-r--r--chromium/content/browser/renderer_host/input/mouse_wheel_phase_handler.cc5
-rw-r--r--chromium/content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.cc9
-rw-r--r--chromium/content/browser/renderer_host/input/passthrough_touch_event_queue.h2
-rw-r--r--chromium/content/browser/renderer_host/input/passthrough_touch_event_queue_unittest.cc2
-rw-r--r--chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc21
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_gesture_controller_unittest.cc260
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc54
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_gesture_target_base.cc13
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_mouse_driver.cc17
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_mouse_driver.h4
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_pen_driver.cc10
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_pen_driver.h2
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_pointer_action.cc3
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_pointer_action_unittest.cc59
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_pointer_driver.h1
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc39
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.h7
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.cc4
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_touch_driver.cc27
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_touch_driver.h4
-rw-r--r--chromium/content/browser/renderer_host/input/touch_action_filter.cc114
-rw-r--r--chromium/content/browser/renderer_host/input/touch_action_filter.h22
-rw-r--r--chromium/content/browser/renderer_host/input/touch_action_filter_unittest.cc260
-rw-r--r--chromium/content/browser/renderer_host/input/touch_emulator.cc12
-rw-r--r--chromium/content/browser/renderer_host/input/touch_emulator.h2
-rw-r--r--chromium/content/browser/renderer_host/input/touch_input_browsertest.cc62
-rw-r--r--chromium/content/browser/renderer_host/input/touch_selection_controller_client_aura.h2
-rw-r--r--chromium/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc6
-rw-r--r--chromium/content/browser/renderer_host/input/touch_selection_controller_client_manager_android.h2
-rw-r--r--chromium/content/browser/renderer_host/input/touchpad_pinch_browsertest.cc27
-rw-r--r--chromium/content/browser/renderer_host/input/touchpad_pinch_event_queue.cc94
-rw-r--r--chromium/content/browser/renderer_host/input/touchpad_pinch_event_queue.h3
-rw-r--r--chromium/content/browser/renderer_host/input/touchpad_pinch_event_queue_unittest.cc301
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_builders_android.cc4
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_builders_mac.h6
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_builders_mac.mm68
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_builders_mac_unittest.mm135
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_util_unittest.cc4
-rw-r--r--chromium/content/browser/renderer_host/input/wheel_event_listener_browsertest.cc135
-rw-r--r--chromium/content/browser/renderer_host/legacy_render_widget_host_win.cc7
-rw-r--r--chromium/content/browser/renderer_host/legacy_render_widget_host_win.h6
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_delegate_impl.cc10
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_device_manager.cc2
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_device_manager.h2
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc7
-rw-r--r--chromium/content/browser/renderer_host/media/audio_output_authorization_handler.cc4
-rw-r--r--chromium/content/browser/renderer_host/media/audio_output_authorization_handler_unittest.cc2
-rw-r--r--chromium/content/browser/renderer_host/media/audio_output_delegate_impl_unittest.cc1
-rw-r--r--chromium/content/browser/renderer_host/media/audio_service_listener.cc6
-rw-r--r--chromium/content/browser/renderer_host/media/audio_service_listener_unittest.cc6
-rw-r--r--chromium/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc67
-rw-r--r--chromium/content/browser/renderer_host/media/in_process_video_capture_device_launcher.h9
-rw-r--r--chromium/content/browser/renderer_host/media/media_devices_dispatcher_host.cc2
-rw-r--r--chromium/content/browser/renderer_host/media/media_devices_dispatcher_host_unittest.cc4
-rw-r--r--chromium/content/browser/renderer_host/media/media_devices_manager.cc9
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc6
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_manager.cc324
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_manager.h31
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_manager_unittest.cc138
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_ui_proxy.cc16
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc19
-rw-r--r--chromium/content/browser/renderer_host/media/old_render_frame_audio_input_stream_factory.cc7
-rw-r--r--chromium/content/browser/renderer_host/media/old_render_frame_audio_input_stream_factory.h12
-rw-r--r--chromium/content/browser/renderer_host/media/old_render_frame_audio_input_stream_factory_unittest.cc4
-rw-r--r--chromium/content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory_unittest.cc12
-rw-r--r--chromium/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.cc18
-rw-r--r--chromium/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h14
-rw-r--r--chromium/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc13
-rw-r--r--chromium/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc5
-rw-r--r--chromium/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc5
-rw-r--r--chromium/content/browser/renderer_host/media/service_video_capture_device_launcher.cc25
-rw-r--r--chromium/content/browser/renderer_host/media/service_video_capture_device_launcher_unittest.cc16
-rw-r--r--chromium/content/browser/renderer_host/media/service_video_capture_provider.cc1
-rw-r--r--chromium/content/browser/renderer_host/media/service_video_capture_provider.h4
-rw-r--r--chromium/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc2
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_browsertest.cc5
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_controller.cc82
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_controller.h26
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_controller_event_handler.h3
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_controller_unittest.cc178
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_device_launch_observer.h4
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_host.cc25
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_host.h7
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_manager.cc32
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_manager.h9
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_manager_unittest.cc14
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_unittest.cc9
-rw-r--r--chromium/content/browser/renderer_host/p2p/DEPS3
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.cc438
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.h124
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host.cc332
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host.h183
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_tcp.cc620
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_tcp.h181
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_tcp_server.cc155
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_tcp_server.h78
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc173
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_tcp_unittest.cc581
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_test_utils.cc217
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_test_utils.h140
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_throttler.cc42
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_throttler.h41
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_udp.cc462
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_udp.h131
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_udp_unittest.cc595
-rw-r--r--chromium/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h2
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_external_file_ref_backend.cc2
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_file_io_host.cc3
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc2
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.cc2
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_gamepad_host.h8
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.cc104
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.h29
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_lookup_request.h68
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_network_monitor_host.cc4
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.cc136
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.h46
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_proxy_lookup_helper.cc106
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_proxy_lookup_helper.h70
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_proxy_lookup_helper_unittest.cc203
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_socket_utils.cc89
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_socket_utils.h6
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc6
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc174
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h28
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_truetype_font_host.cc4
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc652
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h106
-rw-r--r--chromium/content/browser/renderer_host/render_frame_metadata_provider_impl.h2
-rw-r--r--chromium/content/browser/renderer_host/render_message_filter.cc126
-rw-r--r--chromium/content/browser/renderer_host/render_message_filter.h18
-rw-r--r--chromium/content/browser/renderer_host/render_process_host_browsertest.cc60
-rw-r--r--chromium/content/browser/renderer_host/render_process_host_impl.cc363
-rw-r--r--chromium/content/browser/renderer_host/render_process_host_impl.h122
-rw-r--r--chromium/content/browser/renderer_host/render_process_host_unittest.cc12
-rw-r--r--chromium/content/browser/renderer_host/render_view_host_impl.cc14
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_delegate.cc9
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_delegate.h18
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_impl.cc153
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_impl.h52
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_input_event_router.cc87
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_input_event_router.h25
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_input_event_router_unittest.cc114
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_ns_view_client.h3
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_unittest.cc11
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_android.cc82
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_android.h37
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_aura.cc100
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_aura.h12
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc179
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_base.cc35
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_base.h39
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_child_frame.cc79
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_child_frame.h8
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc2
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc4
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_cocoa.h6
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_cocoa.mm44
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_mac.h10
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_mac.mm97
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm212
-rw-r--r--chromium/content/browser/renderer_host/render_widget_targeter.cc22
-rw-r--r--chromium/content/browser/renderer_host/render_widget_targeter.h10
-rw-r--r--chromium/content/browser/renderer_host/text_input_manager.cc5
-rw-r--r--chromium/content/browser/renderer_host/text_input_manager.h6
-rw-r--r--chromium/content/browser/renderer_host/ui_events_helper.cc5
-rw-r--r--chromium/content/browser/renderer_host/web_database_host_impl.cc61
-rw-r--r--chromium/content/browser/renderer_host/web_database_host_impl.h22
-rw-r--r--chromium/content/browser/renderer_host/web_database_host_impl_unittest.cc178
-rw-r--r--chromium/content/browser/renderer_interface_binders.cc2
-rw-r--r--chromium/content/browser/resolve_proxy_msg_helper.cc132
-rw-r--r--chromium/content/browser/resolve_proxy_msg_helper.h70
-rw-r--r--chromium/content/browser/resolve_proxy_msg_helper_unittest.cc303
-rw-r--r--chromium/content/browser/resources/accessibility/OWNERS4
-rw-r--r--chromium/content/browser/resources/accessibility/accessibility.css76
-rw-r--r--chromium/content/browser/resources/accessibility/accessibility.html147
-rw-r--r--chromium/content/browser/resources/accessibility/accessibility.js272
-rw-r--r--chromium/content/browser/resources/indexed_db/indexeddb_internals.html4
-rw-r--r--chromium/content/browser/resources/indexed_db/indexeddb_internals.js27
-rw-r--r--chromium/content/browser/resources/media/client_renderer.js32
-rw-r--r--chromium/content/browser/resources/media/main.js7
-rw-r--r--chromium/content/browser/resources/media/manager.js8
-rw-r--r--chromium/content/browser/resources/media/media_internals.css19
-rw-r--r--chromium/content/browser/resources/media/media_internals.html16
-rw-r--r--chromium/content/browser/scheduler/responsiveness/OWNERS2
-rw-r--r--chromium/content/browser/scheduler/responsiveness/README35
-rw-r--r--chromium/content/browser/scheduler/responsiveness/calculator.cc216
-rw-r--r--chromium/content/browser/scheduler/responsiveness/calculator.h130
-rw-r--r--chromium/content/browser/scheduler/responsiveness/calculator_unittest.cc235
-rw-r--r--chromium/content/browser/scheduler/responsiveness/message_loop_observer.cc34
-rw-r--r--chromium/content/browser/scheduler/responsiveness/message_loop_observer.h47
-rw-r--r--chromium/content/browser/scheduler/responsiveness/native_event_observer.cc157
-rw-r--r--chromium/content/browser/scheduler/responsiveness/native_event_observer.h99
-rw-r--r--chromium/content/browser/scheduler/responsiveness/native_event_observer_browsertest.mm72
-rw-r--r--chromium/content/browser/scheduler/responsiveness/native_event_observer_browsertest_win.cc76
-rw-r--r--chromium/content/browser/scheduler/responsiveness/native_event_observer_mac.mm36
-rw-r--r--chromium/content/browser/scheduler/responsiveness/watcher.cc257
-rw-r--r--chromium/content/browser/scheduler/responsiveness/watcher.h156
-rw-r--r--chromium/content/browser/scheduler/responsiveness/watcher_unittest.cc236
-rw-r--r--chromium/content/browser/security_exploit_browsertest.cc56
-rw-r--r--chromium/content/browser/service_manager/common_browser_interfaces.cc26
-rw-r--r--chromium/content/browser/service_manager/service_manager_context.cc26
-rw-r--r--chromium/content/browser/service_worker/README.md85
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_instance.cc145
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_instance.h4
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_registry.cc2
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_registry.h5
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_test_helper.cc150
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_test_helper.h61
-rw-r--r--chromium/content/browser/service_worker/service_worker_browsertest.cc446
-rw-r--r--chromium/content/browser/service_worker/service_worker_cache_writer.cc4
-rw-r--r--chromium/content/browser/service_worker/service_worker_cache_writer.h15
-rw-r--r--chromium/content/browser/service_worker/service_worker_cache_writer_unittest.cc61
-rw-r--r--chromium/content/browser/service_worker/service_worker_consts.cc3
-rw-r--r--chromium/content/browser/service_worker/service_worker_consts.h1
-rw-r--r--chromium/content/browser/service_worker/service_worker_content_settings_proxy_impl.cc6
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_core.cc45
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_core.h5
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_core_observer.h4
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_request_handler.cc2
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_request_handler.h2
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_request_handler_unittest.cc9
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_unittest.cc181
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_watcher.cc3
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_watcher.h3
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_wrapper.cc157
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_wrapper.h39
-rw-r--r--chromium/content/browser/service_worker/service_worker_controllee_request_handler.cc401
-rw-r--r--chromium/content/browser/service_worker/service_worker_controllee_request_handler.h47
-rw-r--r--chromium/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc155
-rw-r--r--chromium/content/browser/service_worker/service_worker_disk_cache.cc14
-rw-r--r--chromium/content/browser/service_worker/service_worker_disk_cache.h9
-rw-r--r--chromium/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc1
-rw-r--r--chromium/content/browser/service_worker/service_worker_fetch_dispatcher.cc200
-rw-r--r--chromium/content/browser/service_worker/service_worker_fetch_dispatcher.h15
-rw-r--r--chromium/content/browser/service_worker/service_worker_internals_ui.cc1
-rw-r--r--chromium/content/browser/service_worker/service_worker_job_unittest.cc6
-rw-r--r--chromium/content/browser/service_worker/service_worker_metrics.cc208
-rw-r--r--chromium/content/browser/service_worker/service_worker_metrics.h57
-rw-r--r--chromium/content/browser/service_worker/service_worker_navigation_loader.cc143
-rw-r--r--chromium/content/browser/service_worker/service_worker_navigation_loader.h80
-rw-r--r--chromium/content/browser/service_worker/service_worker_navigation_loader_unittest.cc234
-rw-r--r--chromium/content/browser/service_worker/service_worker_new_script_loader.cc7
-rw-r--r--chromium/content/browser/service_worker/service_worker_object_host.cc49
-rw-r--r--chromium/content/browser/service_worker/service_worker_provider_host.cc207
-rw-r--r--chromium/content/browser/service_worker/service_worker_provider_host.h151
-rw-r--r--chromium/content/browser/service_worker/service_worker_provider_host_unittest.cc20
-rw-r--r--chromium/content/browser/service_worker/service_worker_read_from_cache_job_unittest.cc5
-rw-r--r--chromium/content/browser/service_worker/service_worker_register_job.cc1
-rw-r--r--chromium/content/browser/service_worker/service_worker_registration.cc1
-rw-r--r--chromium/content/browser/service_worker/service_worker_registration.h11
-rw-r--r--chromium/content/browser/service_worker/service_worker_registration_object_host.cc97
-rw-r--r--chromium/content/browser/service_worker/service_worker_registration_object_host.h23
-rw-r--r--chromium/content/browser/service_worker/service_worker_registration_status.cc1
-rw-r--r--chromium/content/browser/service_worker/service_worker_registration_unittest.cc176
-rw-r--r--chromium/content/browser/service_worker/service_worker_request_handler.cc12
-rw-r--r--chromium/content/browser/service_worker/service_worker_request_handler.h7
-rw-r--r--chromium/content/browser/service_worker/service_worker_request_handler_unittest.cc38
-rw-r--r--chromium/content/browser/service_worker/service_worker_response_info.cc3
-rw-r--r--chromium/content/browser/service_worker/service_worker_script_cache_map.cc6
-rw-r--r--chromium/content/browser/service_worker/service_worker_script_loader_factory.h3
-rw-r--r--chromium/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc176
-rw-r--r--chromium/content/browser/service_worker/service_worker_storage.cc2
-rw-r--r--chromium/content/browser/service_worker/service_worker_storage_unittest.cc5
-rw-r--r--chromium/content/browser/service_worker/service_worker_test_utils.cc2
-rw-r--r--chromium/content/browser/service_worker/service_worker_url_job_wrapper.cc8
-rw-r--r--chromium/content/browser/service_worker/service_worker_url_job_wrapper.h10
-rw-r--r--chromium/content/browser/service_worker/service_worker_url_request_job.cc87
-rw-r--r--chromium/content/browser/service_worker/service_worker_url_request_job.h17
-rw-r--r--chromium/content/browser/service_worker/service_worker_url_request_job_unittest.cc125
-rw-r--r--chromium/content/browser/service_worker/service_worker_version.cc84
-rw-r--r--chromium/content/browser/service_worker/service_worker_version.h7
-rw-r--r--chromium/content/browser/service_worker/service_worker_version_unittest.cc47
-rw-r--r--chromium/content/browser/service_worker/service_worker_write_to_cache_job.cc8
-rw-r--r--chromium/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc49
-rw-r--r--chromium/content/browser/session_history_browsertest.cc41
-rw-r--r--chromium/content/browser/shared_worker/mock_shared_worker.cc2
-rw-r--r--chromium/content/browser/shared_worker/mock_shared_worker.h2
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_host.cc79
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_host.h35
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_host_unittest.cc13
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_script_loader.cc56
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_script_loader.h13
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_script_loader_factory.cc20
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_script_loader_factory.h5
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_service_impl.cc91
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_service_impl.h29
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_service_impl_unittest.cc62
-rw-r--r--chromium/content/browser/site_instance_impl.cc95
-rw-r--r--chromium/content/browser/site_instance_impl.h37
-rw-r--r--chromium/content/browser/site_instance_impl_unittest.cc112
-rw-r--r--chromium/content/browser/site_per_process_browsertest.cc1571
-rw-r--r--chromium/content/browser/site_per_process_hit_test_browsertest.cc1146
-rw-r--r--chromium/content/browser/speech/speech_recognition_dispatcher_host.cc23
-rw-r--r--chromium/content/browser/speech/speech_recognition_dispatcher_host.h6
-rw-r--r--chromium/content/browser/speech/speech_recognition_engine.cc29
-rw-r--r--chromium/content/browser/speech/speech_recognition_engine.h15
-rw-r--r--chromium/content/browser/speech/speech_recognition_engine_unittest.cc2
-rw-r--r--chromium/content/browser/speech/speech_recognition_manager_impl.cc5
-rw-r--r--chromium/content/browser/speech/speech_recognizer_impl.h1
-rw-r--r--chromium/content/browser/speech/speech_recognizer_impl_unittest.cc2
-rw-r--r--chromium/content/browser/storage_partition_impl.cc136
-rw-r--r--chromium/content/browser/storage_partition_impl.h24
-rw-r--r--chromium/content/browser/storage_partition_impl_map.cc10
-rw-r--r--chromium/content/browser/storage_partition_impl_unittest.cc83
-rw-r--r--chromium/content/browser/tracing/DEPS1
-rw-r--r--chromium/content/browser/tracing/background_startup_tracing_observer.cc130
-rw-r--r--chromium/content/browser/tracing/background_startup_tracing_observer.h69
-rw-r--r--chromium/content/browser/tracing/background_startup_tracing_observer_unittest.cc135
-rw-r--r--chromium/content/browser/tracing/background_tracing_config_impl.cc10
-rw-r--r--chromium/content/browser/tracing/background_tracing_config_impl.h1
-rw-r--r--chromium/content/browser/tracing/background_tracing_config_unittest.cc4
-rw-r--r--chromium/content/browser/tracing/background_tracing_manager_browsertest.cc133
-rw-r--r--chromium/content/browser/tracing/background_tracing_manager_impl.cc160
-rw-r--r--chromium/content/browser/tracing/background_tracing_manager_impl.h8
-rw-r--r--chromium/content/browser/tracing/background_tracing_rule.cc13
-rw-r--r--chromium/content/browser/tracing/cast_tracing_agent.cc9
-rw-r--r--chromium/content/browser/tracing/cros_tracing_agent.cc2
-rw-r--r--chromium/content/browser/tracing/power_tracing_agent.cc197
-rw-r--r--chromium/content/browser/tracing/power_tracing_agent.h98
-rw-r--r--chromium/content/browser/tracing/tracing_controller_browsertest.cc70
-rw-r--r--chromium/content/browser/tracing/tracing_controller_impl.cc15
-rw-r--r--chromium/content/browser/tracing/tracing_controller_impl_data_endpoint.cc6
-rw-r--r--chromium/content/browser/tracing/tracing_ui.cc9
-rw-r--r--chromium/content/browser/url_loader_factory_getter.cc59
-rw-r--r--chromium/content/browser/url_loader_factory_getter.h9
-rw-r--r--chromium/content/browser/utility_process_host.cc12
-rw-r--r--chromium/content/browser/web_contents/web_contents_android.cc15
-rw-r--r--chromium/content/browser/web_contents/web_contents_android.h8
-rw-r--r--chromium/content/browser/web_contents/web_contents_impl.cc209
-rw-r--r--chromium/content/browser/web_contents/web_contents_impl.h70
-rw-r--r--chromium/content/browser/web_contents/web_contents_impl_browsertest.cc200
-rw-r--r--chromium/content/browser/web_contents/web_contents_impl_unittest.cc3
-rw-r--r--chromium/content/browser/web_contents/web_contents_user_data_unittest.cc3
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_android.cc20
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_android.h5
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_aura.cc61
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_aura.h9
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_aura_unittest.cc146
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_guest.cc4
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_overscroll_animator_mac.h61
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_overscroll_animator_slider_mac.h60
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_overscroll_animator_slider_mac.mm259
-rw-r--r--chromium/content/browser/web_contents/web_drag_dest_mac.h2
-rw-r--r--chromium/content/browser/web_contents/web_drag_source_mac.mm7
-rw-r--r--chromium/content/browser/web_package/signed_exchange_cert_fetcher_unittest.cc11
-rw-r--r--chromium/content/browser/web_package/signed_exchange_certificate_chain.cc18
-rw-r--r--chromium/content/browser/web_package/signed_exchange_certificate_chain_fuzzer.cc2
-rw-r--r--chromium/content/browser/web_package/signed_exchange_certificate_chain_unittest.cc32
-rw-r--r--chromium/content/browser/web_package/signed_exchange_consts.h4
-rw-r--r--chromium/content/browser/web_package/signed_exchange_envelope.cc60
-rw-r--r--chromium/content/browser/web_package/signed_exchange_envelope.h10
-rw-r--r--chromium/content/browser/web_package/signed_exchange_envelope_unittest.cc172
-rw-r--r--chromium/content/browser/web_package/signed_exchange_handler.cc390
-rw-r--r--chromium/content/browser/web_package/signed_exchange_handler.h60
-rw-r--r--chromium/content/browser/web_package/signed_exchange_handler_unittest.cc76
-rw-r--r--chromium/content/browser/web_package/signed_exchange_loader.cc75
-rw-r--r--chromium/content/browser/web_package/signed_exchange_loader.h16
-rw-r--r--chromium/content/browser/web_package/signed_exchange_prefetch_handler.cc7
-rw-r--r--chromium/content/browser/web_package/signed_exchange_prologue.cc149
-rw-r--r--chromium/content/browser/web_package/signed_exchange_prologue.h137
-rw-r--r--chromium/content/browser/web_package/signed_exchange_prologue_unittest.cc136
-rw-r--r--chromium/content/browser/web_package/signed_exchange_request_handler.cc39
-rw-r--r--chromium/content/browser/web_package/signed_exchange_request_handler.h19
-rw-r--r--chromium/content/browser/web_package/signed_exchange_request_handler_browsertest.cc165
-rw-r--r--chromium/content/browser/web_package/signed_exchange_signature_header_field.cc4
-rw-r--r--chromium/content/browser/web_package/signed_exchange_signature_header_field_unittest.cc12
-rw-r--r--chromium/content/browser/web_package/signed_exchange_signature_verifier.cc142
-rw-r--r--chromium/content/browser/web_package/signed_exchange_signature_verifier_unittest.cc46
-rw-r--r--chromium/content/browser/webauth/authenticator_impl.cc320
-rw-r--r--chromium/content/browser/webauth/authenticator_impl.h56
-rw-r--r--chromium/content/browser/webauth/authenticator_impl_unittest.cc798
-rw-r--r--chromium/content/browser/webauth/authenticator_type_converters.cc28
-rw-r--r--chromium/content/browser/webauth/authenticator_type_converters.h11
-rw-r--r--chromium/content/browser/webauth/scoped_virtual_authenticator_environment.h2
-rw-r--r--chromium/content/browser/webauth/virtual_authenticator.cc5
-rw-r--r--chromium/content/browser/webauth/virtual_authenticator.h2
-rw-r--r--chromium/content/browser/webauth/webauth_browsertest.cc4
-rw-r--r--chromium/content/browser/webrtc/webrtc_audio_browsertest.cc38
-rw-r--r--chromium/content/browser/webrtc/webrtc_audio_debug_recordings_browsertest.cc34
-rw-r--r--chromium/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc23
-rw-r--r--chromium/content/browser/webrtc/webrtc_internals.h2
-rw-r--r--chromium/content/browser/webrtc/webrtc_video_capture_service_browsertest.cc27
-rw-r--r--chromium/content/browser/webui/content_web_ui_controller_factory.cc4
-rw-r--r--chromium/content/browser/webui/url_data_manager.cc8
-rw-r--r--chromium/content/browser/webui/url_data_manager.h2
-rw-r--r--chromium/content/browser/webui/url_data_manager_backend.cc30
-rw-r--r--chromium/content/browser/webui/url_data_source_impl.cc4
-rw-r--r--chromium/content/browser/webui/url_data_source_impl.h5
-rw-r--r--chromium/content/browser/webui/web_ui_data_source_impl.cc5
-rw-r--r--chromium/content/browser/webui/web_ui_mojo_browsertest.cc6
-rw-r--r--chromium/content/browser/webui/web_ui_url_loader_factory.cc2
-rw-r--r--chromium/content/browser/zoom_browsertest.cc9
1110 files changed, 40744 insertions, 25354 deletions
diff --git a/chromium/content/browser/BUILD.gn b/chromium/content/browser/BUILD.gn
index abaa573b8f1..02d6ebe936c 100644
--- a/chromium/content/browser/BUILD.gn
+++ b/chromium/content/browser/BUILD.gn
@@ -7,6 +7,7 @@ import("//build/config/features.gni")
import("//build/config/jumbo.gni")
import("//build/config/linux/pangocairo/pangocairo.gni")
import("//build/config/ui.gni")
+import("//chromeos/assistant/assistant.gni")
import("//gpu/vulkan/features.gni")
import("//media/media_options.gni")
import("//net/features.gni")
@@ -98,7 +99,6 @@ jumbo_source_set("browser") {
"//gpu/ipc:gl_in_process_context",
"//gpu/ipc/host",
"//gpu/vulkan:buildflags",
- "//jingle:jingle_glue",
"//media",
"//media:media_buildflags",
"//media/capture",
@@ -109,6 +109,7 @@ jumbo_source_set("browser") {
"//media/mojo/interfaces",
"//media/mojo/interfaces:constants",
"//media/mojo/services",
+ "//media/webrtc",
"//mojo/core/embedder",
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/platform",
@@ -126,6 +127,7 @@ jumbo_source_set("browser") {
"//services/catalog/public/cpp",
"//services/catalog/public/mojom:constants",
"//services/content:impl",
+ "//services/content/public/cpp",
"//services/content/public/mojom",
"//services/data_decoder/public/cpp",
"//services/data_decoder/public/mojom",
@@ -136,6 +138,8 @@ jumbo_source_set("browser") {
"//services/device/public/mojom:generic_sensor",
"//services/file:lib",
"//services/file/public/mojom",
+ "//services/media_session/public/cpp",
+ "//services/media_session/public/mojom",
"//services/metrics",
"//services/metrics/public/cpp:metrics_cpp",
"//services/network:network_service",
@@ -154,13 +158,13 @@ jumbo_source_set("browser") {
"//services/shape_detection/public/mojom",
"//services/tracing:lib",
"//services/tracing/public/cpp",
- "//services/ui/public/cpp/gpu",
"//services/video_capture:lib",
"//services/video_capture/public/cpp",
"//services/video_capture/public/mojom:constants",
"//services/video_capture/public/uma",
"//services/viz/privileged/interfaces",
"//services/viz/public/interfaces",
+ "//services/ws/public/cpp/gpu",
"//skia",
"//sql",
"//storage/browser",
@@ -178,7 +182,7 @@ jumbo_source_set("browser") {
"//third_party/icu",
"//third_party/libyuv",
"//third_party/re2",
- "//third_party/webrtc/media:rtc_media_base",
+ "//third_party/sqlite",
"//third_party/webrtc/modules/desktop_capture:primitives",
"//third_party/webrtc/rtc_base:rtc_base",
"//third_party/zlib",
@@ -273,8 +277,6 @@ jumbo_source_set("browser") {
"accessibility/accessibility_tree_formatter_utils_win.cc",
"accessibility/accessibility_tree_formatter_utils_win.h",
"accessibility/accessibility_tree_formatter_win.cc",
- "accessibility/accessibility_ui.cc",
- "accessibility/accessibility_ui.h",
"accessibility/browser_accessibility.cc",
"accessibility/browser_accessibility.h",
"accessibility/browser_accessibility_cocoa.h",
@@ -422,7 +424,8 @@ jumbo_source_set("browser") {
"background_fetch/background_fetch_registration_notifier.h",
"background_fetch/background_fetch_request_info.cc",
"background_fetch/background_fetch_request_info.h",
- "background_fetch/background_fetch_request_manager.h",
+ "background_fetch/background_fetch_request_match_params.cc",
+ "background_fetch/background_fetch_request_match_params.h",
"background_fetch/background_fetch_scheduler.cc",
"background_fetch/background_fetch_scheduler.h",
"background_fetch/background_fetch_service_impl.cc",
@@ -443,8 +446,12 @@ jumbo_source_set("browser") {
"background_fetch/storage/get_initialization_data_task.h",
"background_fetch/storage/get_metadata_task.cc",
"background_fetch/storage/get_metadata_task.h",
+ "background_fetch/storage/get_registration_task.cc",
+ "background_fetch/storage/get_registration_task.h",
"background_fetch/storage/get_settled_fetches_task.cc",
"background_fetch/storage/get_settled_fetches_task.h",
+ "background_fetch/storage/image_helpers.cc",
+ "background_fetch/storage/image_helpers.h",
"background_fetch/storage/mark_registration_for_deletion_task.cc",
"background_fetch/storage/mark_registration_for_deletion_task.h",
"background_fetch/storage/mark_request_complete_task.cc",
@@ -524,6 +531,8 @@ jumbo_source_set("browser") {
"browsing_data/browsing_data_filter_builder_impl.h",
"browsing_data/browsing_data_remover_impl.cc",
"browsing_data/browsing_data_remover_impl.h",
+ "browsing_data/clear_site_data_handler.cc",
+ "browsing_data/clear_site_data_handler.h",
"browsing_data/clear_site_data_throttle.cc",
"browsing_data/clear_site_data_throttle.h",
"browsing_data/conditional_cache_deletion_helper.cc",
@@ -575,6 +584,8 @@ jumbo_source_set("browser") {
"cocoa/system_hotkey_map.mm",
"code_cache/generated_code_cache.cc",
"code_cache/generated_code_cache.h",
+ "code_cache/generated_code_cache_context.cc",
+ "code_cache/generated_code_cache_context.h",
"startup_data_impl.cc",
"startup_data_impl.h",
@@ -747,8 +758,6 @@ jumbo_source_set("browser") {
"download/download_request_utils.cc",
"download/download_resource_handler.cc",
"download/download_resource_handler.h",
- "download/download_url_loader_factory_getter_impl.cc",
- "download/download_url_loader_factory_getter_impl.h",
"download/download_utils.cc",
"download/download_utils.h",
"download/drag_download_file.cc",
@@ -757,6 +766,8 @@ jumbo_source_set("browser") {
"download/drag_download_util.h",
"download/file_download_url_loader_factory_getter.cc",
"download/file_download_url_loader_factory_getter.h",
+ "download/file_system_download_url_loader_factory_getter.cc",
+ "download/file_system_download_url_loader_factory_getter.h",
"download/mhtml_extra_parts_impl.cc",
"download/mhtml_extra_parts_impl.h",
"download/mhtml_generation_manager.cc",
@@ -785,10 +796,14 @@ jumbo_source_set("browser") {
"file_url_loader_factory.h",
"fileapi/browser_file_system_helper.cc",
"fileapi/browser_file_system_helper.h",
+ "fileapi/file_system_chooser.cc",
+ "fileapi/file_system_chooser.h",
+ "fileapi/file_system_manager_impl.cc",
+ "fileapi/file_system_manager_impl.h",
"fileapi/file_system_url_loader_factory.cc",
"fileapi/file_system_url_loader_factory.h",
- "fileapi/fileapi_message_filter.cc",
- "fileapi/fileapi_message_filter.h",
+ "find_in_page_client.cc",
+ "find_in_page_client.h",
"find_request_manager.cc",
"find_request_manager.h",
"font_list_async.cc",
@@ -867,12 +882,11 @@ jumbo_source_set("browser") {
"geolocation/geolocation_service_impl.h",
"gpu/browser_gpu_channel_host_factory.cc",
"gpu/browser_gpu_channel_host_factory.h",
- "gpu/browser_gpu_memory_buffer_manager.cc",
- "gpu/browser_gpu_memory_buffer_manager.h",
+ "gpu/browser_gpu_client_delegate.cc",
+ "gpu/browser_gpu_client_delegate.h",
"gpu/compositor_util.cc",
"gpu/compositor_util.h",
- "gpu/gpu_client_impl.cc",
- "gpu/gpu_client_impl.h",
+ "gpu/gpu_client.cc",
"gpu/gpu_data_manager_impl.cc",
"gpu/gpu_data_manager_impl.h",
"gpu/gpu_data_manager_impl_private.cc",
@@ -883,6 +897,8 @@ jumbo_source_set("browser") {
"gpu/gpu_internals_ui.h",
"gpu/gpu_main_thread_factory.cc",
"gpu/gpu_main_thread_factory.h",
+ "gpu/gpu_memory_buffer_manager_singleton.cc",
+ "gpu/gpu_memory_buffer_manager_singleton.h",
"gpu/gpu_process_host.cc",
"gpu/gpu_process_host.h",
"gpu/shader_cache_factory.cc",
@@ -976,6 +992,10 @@ jumbo_source_set("browser") {
"indexed_db/leveldb/leveldb_write_batch.cc",
"indexed_db/leveldb/leveldb_write_batch.h",
"indexed_db/list_set.h",
+ "indexed_db/scopes/disjoint_range_lock_manager.cc",
+ "indexed_db/scopes/disjoint_range_lock_manager.h",
+ "indexed_db/scopes/scopes_lock_manager.cc",
+ "indexed_db/scopes/scopes_lock_manager.h",
"initiator_csp_context.cc",
"initiator_csp_context.h",
"installedapp/installed_app_provider_impl_default.cc",
@@ -995,7 +1015,6 @@ jumbo_source_set("browser") {
"loader/detachable_resource_handler.h",
"loader/download_utils_impl.cc",
"loader/download_utils_impl.h",
- "loader/global_routing_id.h",
"loader/intercepting_resource_handler.cc",
"loader/intercepting_resource_handler.h",
"loader/layered_resource_handler.cc",
@@ -1091,6 +1110,8 @@ jumbo_source_set("browser") {
"media/capture/audio_mirroring_manager.h",
"media/capture/desktop_capture_device_uma_types.cc",
"media/capture/desktop_capture_device_uma_types.h",
+ "media/capture/desktop_streams_registry_impl.cc",
+ "media/capture/desktop_streams_registry_impl.h",
"media/capture/web_contents_audio_input_stream.cc",
"media/capture/web_contents_audio_input_stream.h",
"media/capture/web_contents_audio_muter.cc",
@@ -1103,6 +1124,8 @@ jumbo_source_set("browser") {
"media/flinging_renderer.h",
"media/forwarding_audio_stream_factory.cc",
"media/forwarding_audio_stream_factory.h",
+ "media/in_process_audio_loopback_stream_creator.cc",
+ "media/in_process_audio_loopback_stream_creator.h",
"media/media_devices_permission_checker.cc",
"media/media_devices_permission_checker.h",
"media/media_devices_util.cc",
@@ -1127,6 +1150,8 @@ jumbo_source_set("browser") {
"media/session/audio_focus_delegate_default.cc",
"media/session/audio_focus_manager.cc",
"media/session/audio_focus_manager.h",
+ "media/session/audio_focus_observer.cc",
+ "media/session/audio_focus_observer.h",
"media/session/media_metadata_sanitizer.cc",
"media/session/media_metadata_sanitizer.h",
"media/session/media_session_android.cc",
@@ -1144,6 +1169,10 @@ jumbo_source_set("browser") {
"media/session/media_session_uma_helper.h",
"media/url_provision_fetcher.cc",
"media/url_provision_fetcher.h",
+ "media/video_decoder_proxy.cc",
+ "media/video_decoder_proxy.h",
+ "media/webaudio/audio_context_manager_impl.cc",
+ "media/webaudio/audio_context_manager_impl.h",
"memory/memory_condition_observer.cc",
"memory/memory_condition_observer.h",
"memory/memory_coordinator_default_policy.cc",
@@ -1193,6 +1222,8 @@ jumbo_source_set("browser") {
"notifications/notification_event_dispatcher_impl.h",
"notifications/notification_id_generator.cc",
"notifications/notification_id_generator.h",
+ "notifications/notification_storage.cc",
+ "notifications/notification_storage.h",
"notifications/platform_notification_context_impl.cc",
"notifications/platform_notification_context_impl.h",
"payments/payment_app_context_impl.cc",
@@ -1219,6 +1250,8 @@ jumbo_source_set("browser") {
"picture_in_picture/overlay_surface_embedder.h",
"picture_in_picture/picture_in_picture_window_controller_impl.cc",
"picture_in_picture/picture_in_picture_window_controller_impl.h",
+ "portal/portal.cc",
+ "portal/portal.h",
"presentation/presentation_service_impl.cc",
"presentation/presentation_service_impl.h",
"process_internals/process_internals_handler_impl.cc",
@@ -1432,16 +1465,6 @@ jumbo_source_set("browser") {
"renderer_host/overscroll_controller_delegate.h",
"renderer_host/p2p/socket_dispatcher_host.cc",
"renderer_host/p2p/socket_dispatcher_host.h",
- "renderer_host/p2p/socket_host.cc",
- "renderer_host/p2p/socket_host.h",
- "renderer_host/p2p/socket_host_tcp.cc",
- "renderer_host/p2p/socket_host_tcp.h",
- "renderer_host/p2p/socket_host_tcp_server.cc",
- "renderer_host/p2p/socket_host_tcp_server.h",
- "renderer_host/p2p/socket_host_throttler.cc",
- "renderer_host/p2p/socket_host_throttler.h",
- "renderer_host/p2p/socket_host_udp.cc",
- "renderer_host/p2p/socket_host_udp.h",
"renderer_host/render_frame_metadata_provider_impl.cc",
"renderer_host/render_frame_metadata_provider_impl.h",
"renderer_host/render_message_filter.cc",
@@ -1505,6 +1528,15 @@ jumbo_source_set("browser") {
"sandbox_ipc_linux.h",
"sandbox_parameters_mac.h",
"sandbox_parameters_mac.mm",
+ "scheduler/responsiveness/calculator.cc",
+ "scheduler/responsiveness/calculator.h",
+ "scheduler/responsiveness/message_loop_observer.cc",
+ "scheduler/responsiveness/message_loop_observer.h",
+ "scheduler/responsiveness/native_event_observer.cc",
+ "scheduler/responsiveness/native_event_observer.h",
+ "scheduler/responsiveness/native_event_observer_mac.mm",
+ "scheduler/responsiveness/watcher.cc",
+ "scheduler/responsiveness/watcher.h",
"scoped_active_url.cc",
"scoped_active_url.h",
"screen_orientation/screen_orientation_provider.cc",
@@ -1674,6 +1706,8 @@ jumbo_source_set("browser") {
"theme_helper_mac.mm",
"tracing/background_memory_tracing_observer.cc",
"tracing/background_memory_tracing_observer.h",
+ "tracing/background_startup_tracing_observer.cc",
+ "tracing/background_startup_tracing_observer.h",
"tracing/background_tracing_config_impl.cc",
"tracing/background_tracing_config_impl.h",
"tracing/background_tracing_manager_impl.cc",
@@ -1874,25 +1908,18 @@ jumbo_source_set("browser") {
"//content/browser/tracing:resources",
]
}
- if ((use_udev && is_posix) || is_mac || is_win) {
- deps += [ "//tools/battor_agent:battor_agent_lib" ]
- sources += [
- "tracing/power_tracing_agent.cc",
- "tracing/power_tracing_agent.h",
- ]
- }
# Desktop/Window/WebContents screen capture implementations, conditionally
# built depending on the available implementations for each platform.
if (is_linux || is_mac || is_win) {
defines += [ "ENABLE_SCREEN_CAPTURE=1" ]
sources += [
- "media/capture/cursor_renderer.cc",
- "media/capture/cursor_renderer.h",
"media/capture/desktop_capture_device.cc",
"media/capture/desktop_capture_device.h",
"media/capture/frame_sink_video_capture_device.cc",
"media/capture/frame_sink_video_capture_device.h",
+ "media/capture/mouse_cursor_overlay_controller.cc",
+ "media/capture/mouse_cursor_overlay_controller.h",
"media/capture/web_contents_video_capture_device.cc",
"media/capture/web_contents_video_capture_device.h",
]
@@ -1902,21 +1929,19 @@ jumbo_source_set("browser") {
sources += [
"media/capture/aura_window_video_capture_device.cc",
"media/capture/aura_window_video_capture_device.h",
- "media/capture/cursor_renderer_aura.cc",
- "media/capture/cursor_renderer_aura.h",
+ "media/capture/mouse_cursor_overlay_controller_aura.cc",
]
}
if (is_chromeos) {
sources += [
+ "media/capture/lame_capture_overlay_chromeos.cc",
+ "media/capture/lame_capture_overlay_chromeos.h",
"media/capture/lame_window_capturer_chromeos.cc",
"media/capture/lame_window_capturer_chromeos.h",
]
}
if (is_mac) {
- sources += [
- "media/capture/cursor_renderer_mac.h",
- "media/capture/cursor_renderer_mac.mm",
- ]
+ sources += [ "media/capture/mouse_cursor_overlay_controller_mac.mm" ]
deps += [
"//sandbox/mac:seatbelt",
"//sandbox/mac:seatbelt_extension",
@@ -1993,7 +2018,6 @@ jumbo_source_set("browser") {
"renderer_host/pepper/pepper_host_resolver_message_filter.h",
"renderer_host/pepper/pepper_internal_file_ref_backend.cc",
"renderer_host/pepper/pepper_internal_file_ref_backend.h",
- "renderer_host/pepper/pepper_lookup_request.h",
"renderer_host/pepper/pepper_message_filter.cc",
"renderer_host/pepper/pepper_message_filter.h",
"renderer_host/pepper/pepper_network_monitor_host.cc",
@@ -2004,6 +2028,8 @@ jumbo_source_set("browser") {
"renderer_host/pepper/pepper_print_settings_manager.h",
"renderer_host/pepper/pepper_printing_host.cc",
"renderer_host/pepper/pepper_printing_host.h",
+ "renderer_host/pepper/pepper_proxy_lookup_helper.cc",
+ "renderer_host/pepper/pepper_proxy_lookup_helper.h",
"renderer_host/pepper/pepper_renderer_connection.cc",
"renderer_host/pepper/pepper_renderer_connection.h",
"renderer_host/pepper/pepper_security_helper.cc",
@@ -2086,7 +2112,10 @@ jumbo_source_set("browser") {
if (use_x11) {
configs += [ "//build/config/linux:x11" ]
- deps += [ "//ui/gfx/x" ]
+ deps += [
+ "//ui/events/platform/x11",
+ "//ui/gfx/x",
+ ]
}
if (use_pangocairo) {
@@ -2154,18 +2183,22 @@ jumbo_source_set("browser") {
"android/synchronous_compositor_host.h",
"android/synchronous_compositor_sync_call_bridge.cc",
"android/synchronous_compositor_sync_call_bridge.h",
- "android/tap_disambiguator.cc",
- "android/tap_disambiguator.h",
"android/tracing_controller_android.cc",
"android/tracing_controller_android.h",
"android/web_contents_observer_proxy.cc",
"android/web_contents_observer_proxy.h",
+ "font_unique_name_lookup/font_unique_name_lookup.cc",
+ "font_unique_name_lookup/font_unique_name_lookup.h",
+ "font_unique_name_lookup/font_unique_name_lookup_service.cc",
+ "font_unique_name_lookup/font_unique_name_lookup_service.h",
"frame_host/render_frame_host_android.cc",
"frame_host/render_frame_host_android.h",
"media/capture/screen_capture_device_android.cc",
"media/capture/screen_capture_device_android.h",
"renderer_host/compositor_impl_android.cc",
"renderer_host/compositor_impl_android.h",
+ "renderer_host/delegated_frame_host_client_android.cc",
+ "renderer_host/delegated_frame_host_client_android.h",
"renderer_host/input/fling_scheduler_android.cc",
"renderer_host/input/fling_scheduler_android.h",
"renderer_host/input/synthetic_gesture_target_android.cc",
@@ -2206,11 +2239,14 @@ jumbo_source_set("browser") {
]
deps += [
":reflection_jni_headers",
+ "//build/config/freetype",
"//content/public/android:jni",
"//device/gamepad/public/mojom",
"//media",
"//media/capture/content/android",
"//media/capture/video/android",
+ "//third_party/blink/public/common:font_unique_name_table_proto",
+ "//third_party/icu",
"//ui/accessibility:ax_assistant",
"//ui/accessibility/mojom",
"//ui/android",
@@ -2297,14 +2333,18 @@ jumbo_source_set("browser") {
deps += [
"//chromeos",
"//chromeos:power_manager_proto",
+ "//chromeos/assistant:buildflags",
]
}
+ if (enable_cros_libassistant) {
+ deps += [ "//chromeos/services/assistant/public/mojom" ]
+ }
+
if (use_aura) {
deps += [
- "//services/ui:lib",
- "//services/ui/public/cpp",
- "//services/ui/public/interfaces",
+ "//services/ws/public/cpp",
+ "//services/ws/public/mojom",
"//ui/aura",
"//ui/aura_extra",
"//ui/strings",
@@ -2445,7 +2485,10 @@ if (is_android) {
# See comment at the top of //content/BUILD.gn for how this works.
group("for_content_tests") {
- visibility = [ "//content/test/*" ]
+ visibility = [
+ "//content/test/*",
+ "//content/public/test/*",
+ ]
if (!is_component_build) {
public_deps = [
":browser",
diff --git a/chromium/content/browser/DEPS b/chromium/content/browser/DEPS
index afd8cb019fb..a065eb289c4 100644
--- a/chromium/content/browser/DEPS
+++ b/chromium/content/browser/DEPS
@@ -101,9 +101,9 @@ include_rules = [
"+third_party/blink/public/platform/web_touch_event.h",
"+third_party/blink/public/platform/web_text_input_type.h",
"+third_party/blink/public/platform/mac/web_scrollbar_theme.h",
- "+third_party/blink/public/platform/modules/locks/lock_manager.mojom.h",
+ "+third_party/blink/public/platform/modules/font_unique_name_lookup/font_unique_name_lookup.mojom.h",
"+third_party/blink/public/platform/modules/indexeddb/web_idb_database_exception.h",
- "+third_party/blink/public/platform/modules/indexeddb/web_idb_types.h",
+ "+third_party/blink/public/platform/modules/locks/lock_manager.mojom.h",
"+third_party/blink/public/platform/modules/notifications/web_notification_constants.h",
"+third_party/blink/public/platform/modules/service_worker/web_service_worker_error.h",
"+third_party/blink/public/public_buildflags.h",
@@ -145,12 +145,10 @@ include_rules = [
"+third_party/blink/public/platform/modules/mediastream/media_devices.mojom.h",
"+third_party/blink/public/platform/modules/notifications/notification_service.mojom.h",
"+third_party/blink/public/platform/modules/frame_sinks/embedded_frame_sink.mojom.h",
- "+third_party/blink/public/platform/modules/payments/payment_app.mojom.h",
"+third_party/blink/public/platform/modules/permissions/permission.mojom.h",
"+third_party/blink/public/platform/modules/permissions/permission_status.mojom.h",
- "+third_party/blink/public/platform/modules/presentation/presentation.mojom.h",
- "+third_party/blink/public/platform/modules/webauth/authenticator.mojom.h",
- "+third_party/blink/public/platform/modules/webauth/virtual_authenticator.mojom.h",
+ "+third_party/blink/public/platform/modules/webauthn/authenticator.mojom.h",
+ "+third_party/blink/public/platform/modules/webauthn/virtual_authenticator.mojom.h",
"+third_party/blink/public/platform/modules/webdatabase/web_database.mojom.h",
"+third_party/blink/public/platform/modules/websockets/websocket.mojom.h",
"+third_party/blink/public/platform/oom_intervention.mojom.h",
diff --git a/chromium/content/browser/OWNERS b/chromium/content/browser/OWNERS
index 223a5fa2d14..61804ae5596 100644
--- a/chromium/content/browser/OWNERS
+++ b/chromium/content/browser/OWNERS
@@ -1,6 +1,10 @@
# For Android
boliu@chromium.org
+# These are for the common case of adding or renaming files. If you're doing
+# structural changes, please get a review from a reviewer in this file.
+per-file BUILD.gn=*
+
# For security review.
per-file child_process_security_policy_impl.*=set noparent
per-file child_process_security_policy_impl.*=creis@chromium.org
diff --git a/chromium/content/browser/accessibility/accessibility_event_recorder.cc b/chromium/content/browser/accessibility/accessibility_event_recorder.cc
index 88390e8d004..a2de95e816a 100644
--- a/chromium/content/browser/accessibility/accessibility_event_recorder.cc
+++ b/chromium/content/browser/accessibility/accessibility_event_recorder.cc
@@ -5,6 +5,7 @@
#include "content/browser/accessibility/accessibility_event_recorder.h"
#include "build/build_config.h"
+#include "content/browser/accessibility/browser_accessibility_manager.h"
namespace content {
@@ -13,19 +14,19 @@ AccessibilityEventRecorder::AccessibilityEventRecorder(
base::ProcessId pid)
: manager_(manager) {}
-AccessibilityEventRecorder::~AccessibilityEventRecorder() {
-}
+AccessibilityEventRecorder::~AccessibilityEventRecorder() = default;
#if !defined(OS_WIN) && !defined(OS_MACOSX)
// static
-AccessibilityEventRecorder* AccessibilityEventRecorder::Create(
+AccessibilityEventRecorder& AccessibilityEventRecorder::GetInstance(
BrowserAccessibilityManager* manager,
base::ProcessId pid) {
- return new AccessibilityEventRecorder(manager, pid);
+ static base::NoDestructor<AccessibilityEventRecorder> instance(manager, pid);
+ return *instance;
}
#endif
-void AccessibilityEventRecorder::OnEvent(std::string event) {
+void AccessibilityEventRecorder::OnEvent(const std::string& event) {
event_logs_.push_back(event);
if (callback_)
callback_.Run(event);
diff --git a/chromium/content/browser/accessibility/accessibility_event_recorder.h b/chromium/content/browser/accessibility/accessibility_event_recorder.h
index 7ff5879926e..4d03a1dbc01 100644
--- a/chromium/content/browser/accessibility/accessibility_event_recorder.h
+++ b/chromium/content/browser/accessibility/accessibility_event_recorder.h
@@ -10,12 +10,13 @@
#include "base/callback.h"
#include "base/macros.h"
+#include "base/no_destructor.h"
#include "base/process/process_handle.h"
-#include "content/common/content_export.h"
namespace content {
-using AccessibilityEventCallback = base::RepeatingCallback<void(std::string)>;
+using AccessibilityEventCallback =
+ base::RepeatingCallback<void(const std::string&)>;
class BrowserAccessibilityManager;
@@ -32,12 +33,14 @@ class BrowserAccessibilityManager;
//
// The implementation is highly platform-specific; a subclass is needed for
// each platform does most of the work.
+//
+// As currently designed, there should only be one instance of this class.
class AccessibilityEventRecorder {
public:
- // Construct the right platform-specific subclass.
- static AccessibilityEventRecorder* Create(
- BrowserAccessibilityManager* manager,
- base::ProcessId pid);
+ // Get the right platform-specific subclass.
+ static AccessibilityEventRecorder& GetInstance(
+ BrowserAccessibilityManager* manager = nullptr,
+ base::ProcessId pid = 0);
virtual ~AccessibilityEventRecorder();
void set_only_web_events(bool only_web_events) {
@@ -52,14 +55,16 @@ class AccessibilityEventRecorder {
const std::vector<std::string>& event_logs() { return event_logs_; }
protected:
- explicit AccessibilityEventRecorder(BrowserAccessibilityManager* manager,
- base::ProcessId pid);
+ AccessibilityEventRecorder(BrowserAccessibilityManager* manager,
+ base::ProcessId pid);
- void OnEvent(std::string event);
+ void OnEvent(const std::string& event);
- BrowserAccessibilityManager* manager_;
+ BrowserAccessibilityManager* const manager_;
bool only_web_events_ = false;
+ friend class base::NoDestructor<AccessibilityEventRecorder>;
+
private:
std::vector<std::string> event_logs_;
AccessibilityEventCallback callback_;
diff --git a/chromium/content/browser/accessibility/accessibility_event_recorder_mac.mm b/chromium/content/browser/accessibility/accessibility_event_recorder_mac.mm
index f8efd01bfc7..0245a037230 100644
--- a/chromium/content/browser/accessibility/accessibility_event_recorder_mac.mm
+++ b/chromium/content/browser/accessibility/accessibility_event_recorder_mac.mm
@@ -4,10 +4,10 @@
#include "content/browser/accessibility/accessibility_event_recorder.h"
-#include <string>
-
#import <Cocoa/Cocoa.h>
+#include <string>
+
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/strings/stringprintf.h"
@@ -20,14 +20,15 @@ namespace content {
// watch for NSAccessibility events.
class AccessibilityEventRecorderMac : public AccessibilityEventRecorder {
public:
- explicit AccessibilityEventRecorderMac(BrowserAccessibilityManager* manager,
- base::ProcessId pid);
~AccessibilityEventRecorderMac() override;
// Callback executed every time we receive an event notification.
void EventReceived(AXUIElementRef element, CFStringRef notification);
private:
+ AccessibilityEventRecorderMac(BrowserAccessibilityManager* manager,
+ base::ProcessId pid);
+
// Add one notification to the list of notifications monitored by our
// observer.
void AddNotification(NSString* notification);
@@ -43,6 +44,9 @@ class AccessibilityEventRecorderMac : public AccessibilityEventRecorder {
// The AXObserver we use to monitor AX notifications.
base::ScopedCFTypeRef<AXObserverRef> observer_ref_;
CFRunLoopSourceRef observer_run_loop_source_;
+
+ friend class base::NoDestructor<AccessibilityEventRecorderMac>;
+ DISALLOW_COPY_AND_ASSIGN(AccessibilityEventRecorderMac);
};
// Callback function registered using AXObserverCreate.
@@ -57,10 +61,12 @@ static void EventReceivedThunk(
}
// static
-AccessibilityEventRecorder* AccessibilityEventRecorder::Create(
+AccessibilityEventRecorder& AccessibilityEventRecorder::GetInstance(
BrowserAccessibilityManager* manager,
base::ProcessId pid) {
- return new AccessibilityEventRecorderMac(manager, pid);
+ static base::NoDestructor<AccessibilityEventRecorderMac> instance(manager,
+ pid);
+ return *instance;
}
AccessibilityEventRecorderMac::AccessibilityEventRecorderMac(
@@ -126,7 +132,7 @@ std::string AccessibilityEventRecorderMac::GetAXAttributeValue(
return base::SysCFStringRefToUTF8(value_string);
// TODO(dmazzoni): And if it's not a string, can we return something better?
- return std::string();
+ return {};
}
void AccessibilityEventRecorderMac::EventReceived(AXUIElementRef element,
diff --git a/chromium/content/browser/accessibility/accessibility_event_recorder_win.cc b/chromium/content/browser/accessibility/accessibility_event_recorder_win.cc
index a71a156a72e..07c26adb4c0 100644
--- a/chromium/content/browser/accessibility/accessibility_event_recorder_win.cc
+++ b/chromium/content/browser/accessibility/accessibility_event_recorder_win.cc
@@ -16,7 +16,6 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/scoped_bstr.h"
-#include "base/win/scoped_com_initializer.h"
#include "base/win/scoped_variant.h"
#include "content/browser/accessibility/accessibility_tree_formatter_utils_win.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
@@ -76,23 +75,22 @@ std::string AccessibilityEventToStringUTF8(int32_t event_id) {
class AccessibilityEventRecorderWin : public AccessibilityEventRecorder {
public:
- explicit AccessibilityEventRecorderWin(BrowserAccessibilityManager* manager,
- base::ProcessId pid);
-
~AccessibilityEventRecorderWin() override;
// Callback registered by SetWinEventHook. Just calls OnWinEventHook.
- static void CALLBACK WinEventHookThunk(
- HWINEVENTHOOK handle,
- DWORD event,
- HWND hwnd,
- LONG obj_id,
- LONG child_id,
- DWORD event_thread,
- DWORD event_time);
+ static CALLBACK void WinEventHookThunk(HWINEVENTHOOK handle,
+ DWORD event,
+ HWND hwnd,
+ LONG obj_id,
+ LONG child_id,
+ DWORD event_thread,
+ DWORD event_time);
private:
- // Called by the thunk registered by SetWinEventHook. Retrives accessibility
+ AccessibilityEventRecorderWin(BrowserAccessibilityManager* manager,
+ base::ProcessId pid);
+
+ // Called by the thunk registered by SetWinEventHook. Retrieves accessibility
// info about the node the event was fired on and appends a string to
// the event log.
void OnWinEventHook(HWINEVENTHOOK handle,
@@ -109,25 +107,22 @@ class AccessibilityEventRecorderWin : public AccessibilityEventRecorder {
HWND hwnd, DWORD dwId, REFIID riid, void **ppvObject);
HWINEVENTHOOK win_event_hook_handle_;
- static AccessibilityEventRecorderWin* instance_;
- // Initializes COM services when standalone dump events tool is used.
- base::win::ScopedCOMInitializer com_initializer;
+ friend class base::NoDestructor<AccessibilityEventRecorderWin>;
+ DISALLOW_COPY_AND_ASSIGN(AccessibilityEventRecorderWin);
};
// static
-AccessibilityEventRecorderWin*
-AccessibilityEventRecorderWin::instance_ = nullptr;
-
-// static
-AccessibilityEventRecorder* AccessibilityEventRecorder::Create(
+AccessibilityEventRecorder& AccessibilityEventRecorder::GetInstance(
BrowserAccessibilityManager* manager,
base::ProcessId pid) {
- return new AccessibilityEventRecorderWin(manager, pid);
+ static base::NoDestructor<AccessibilityEventRecorderWin> instance(manager,
+ pid);
+ return *instance;
}
// static
-void CALLBACK AccessibilityEventRecorderWin::WinEventHookThunk(
+CALLBACK void AccessibilityEventRecorderWin::WinEventHookThunk(
HWINEVENTHOOK handle,
DWORD event,
HWND hwnd,
@@ -135,20 +130,15 @@ void CALLBACK AccessibilityEventRecorderWin::WinEventHookThunk(
LONG child_id,
DWORD event_thread,
DWORD event_time) {
- if (instance_) {
- instance_->OnWinEventHook(handle, event, hwnd, obj_id, child_id,
- event_thread, event_time);
- }
+ static_cast<AccessibilityEventRecorderWin&>(GetInstance())
+ .OnWinEventHook(handle, event, hwnd, obj_id, child_id, event_thread,
+ event_time);
}
AccessibilityEventRecorderWin::AccessibilityEventRecorderWin(
BrowserAccessibilityManager* manager,
base::ProcessId pid)
: AccessibilityEventRecorder(manager, pid) {
- CHECK(!instance_) << "There can be only one instance of"
- << " WinAccessibilityEventMonitor at a time.";
- instance_ = this;
-
// For now, just use out of context events when running as a utility to watch
// events (no BrowserAccessibilityManager), because otherwise Chrome events
// are not getting reported. Being in context is better so that for
@@ -165,7 +155,6 @@ AccessibilityEventRecorderWin::AccessibilityEventRecorderWin(
AccessibilityEventRecorderWin::~AccessibilityEventRecorderWin() {
UnhookWinEvent(win_event_hook_handle_);
- instance_ = NULL;
}
void AccessibilityEventRecorderWin::OnWinEventHook(
@@ -180,7 +169,7 @@ void AccessibilityEventRecorderWin::OnWinEventHook(
HRESULT hr = AccessibleObjectFromWindowWrapper(
hwnd, obj_id, IID_IAccessible,
reinterpret_cast<void**>(browser_accessible.GetAddressOf()));
- if (!SUCCEEDED(hr)) {
+ if (FAILED(hr)) {
// Note: our event hook will pick up some superfluous events we
// don't care about, so it's safe to just ignore these failures.
// Same below for other HRESULT checks.
@@ -192,7 +181,7 @@ void AccessibilityEventRecorderWin::OnWinEventHook(
Microsoft::WRL::ComPtr<IDispatch> dispatch;
hr = browser_accessible->get_accChild(childid_variant,
dispatch.GetAddressOf());
- if (!SUCCEEDED(hr) || !dispatch) {
+ if (hr != S_OK || !dispatch) {
VLOG(1) << "Ignoring result " << hr << " and result " << dispatch.Get()
<< " from get_accChild";
return;
@@ -200,7 +189,7 @@ void AccessibilityEventRecorderWin::OnWinEventHook(
Microsoft::WRL::ComPtr<IAccessible> iaccessible;
hr = dispatch.CopyTo(iaccessible.GetAddressOf());
- if (!SUCCEEDED(hr)) {
+ if (FAILED(hr)) {
VLOG(1) << "Ignoring result " << hr << " from QueryInterface";
return;
}
@@ -212,13 +201,13 @@ void AccessibilityEventRecorderWin::OnWinEventHook(
Microsoft::WRL::ComPtr<IServiceProvider> service_provider;
hr = iaccessible->QueryInterface(service_provider.GetAddressOf());
- if (!SUCCEEDED(hr))
+ if (FAILED(hr))
return;
Microsoft::WRL::ComPtr<IAccessible> content_document;
hr = service_provider->QueryService(GUID_IAccessibleContentDocument,
content_document.GetAddressOf());
- if (!SUCCEEDED(hr))
+ if (FAILED(hr))
return;
}
@@ -301,8 +290,15 @@ void AccessibilityEventRecorderWin::OnWinEventHook(
log += base::StringPrintf(" role=%s", RoleVariantToString(role).c_str());
if (name_bstr.Length() > 0)
log += base::StringPrintf(" name=\"%s\"", BstrToUTF8(name_bstr).c_str());
- if (value_bstr.Length() > 0)
- log += base::StringPrintf(" value=\"%s\"", BstrToUTF8(value_bstr).c_str());
+ if (value_bstr.Length() > 0) {
+ bool is_document =
+ role.type() == VT_I4 && ROLE_SYSTEM_DOCUMENT == V_I4(role.ptr());
+ // Don't show actual document value, which is a URL, in order to avoid
+ // machine-based differences in tests.
+ log += is_document ? " value~=[doc-url]"
+ : base::StringPrintf(" value=\"%s\"",
+ BstrToUTF8(value_bstr).c_str());
+ }
log += " ";
log += base::UTF16ToUTF8(IAccessibleStateToString(ia_state));
log += " ";
diff --git a/chromium/content/browser/accessibility/accessibility_ipc_error_browsertest.cc b/chromium/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
index c91e712b57c..b6e8ad2423f 100644
--- a/chromium/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
+++ b/chromium/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
@@ -132,9 +132,11 @@ IN_PROC_BROWSER_TEST_F(AccessibilityIpcErrorBrowserTest,
#if defined(OS_ANDROID)
// http://crbug.com/542704
-#define MAYBE_MultipleBadAccessibilityIPCsKillsRenderer DISABLED_MultipleBadAccessibilityIPCsKillsRenderer
+#define MAYBE_MultipleBadAccessibilityIPCsKillsRenderer \
+ DISABLED_MultipleBadAccessibilityIPCsKillsRenderer
#else
-#define MAYBE_MultipleBadAccessibilityIPCsKillsRenderer MultipleBadAccessibilityIPCsKillsRenderer
+#define MAYBE_MultipleBadAccessibilityIPCsKillsRenderer \
+ MultipleBadAccessibilityIPCsKillsRenderer
#endif
IN_PROC_BROWSER_TEST_F(AccessibilityIpcErrorBrowserTest,
MAYBE_MultipleBadAccessibilityIPCsKillsRenderer) {
@@ -161,7 +163,10 @@ IN_PROC_BROWSER_TEST_F(AccessibilityIpcErrorBrowserTest,
// will reject.
AXEventNotificationDetails bad_accessibility_event;
bad_accessibility_event.updates.resize(1);
- bad_accessibility_event.updates[0].node_id_to_clear = -2;
+ bad_accessibility_event.updates[0].root_id = 1;
+ bad_accessibility_event.updates[0].nodes.resize(1);
+ bad_accessibility_event.updates[0].nodes[0].id = 1;
+ bad_accessibility_event.updates[0].nodes[0].child_ids.push_back(2);
// We should be able to reset accessibility |max_iterations-1| times
// (see render_frame_host_impl.cc - kMaxAccessibilityResets),
diff --git a/chromium/content/browser/accessibility/accessibility_tree_formatter.cc b/chromium/content/browser/accessibility/accessibility_tree_formatter.cc
index 5236a97ee06..d095d80b4fd 100644
--- a/chromium/content/browser/accessibility/accessibility_tree_formatter.cc
+++ b/chromium/content/browser/accessibility/accessibility_tree_formatter.cc
@@ -15,6 +15,7 @@
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/browser/web_contents/web_contents_impl.h"
@@ -50,6 +51,23 @@ void AccessibilityTreeFormatter::FormatAccessibilityTree(
RecursiveFormatAccessibilityTree(dict, contents);
}
+base::string16 AccessibilityTreeFormatter::DumpAccessibilityTreeFromManager(
+ BrowserAccessibilityManager* ax_mgr,
+ bool internal) {
+ std::unique_ptr<AccessibilityTreeFormatter> formatter;
+ if (internal)
+ formatter.reset(new AccessibilityTreeFormatterBlink());
+ else
+ formatter.reset(Create());
+ base::string16 accessibility_contents_utf16;
+ std::vector<Filter> filters;
+ filters.push_back(Filter(base::ASCIIToUTF16("*"), Filter::ALLOW));
+ formatter->SetFilters(filters);
+ formatter->FormatAccessibilityTree(ax_mgr->GetRoot(),
+ &accessibility_contents_utf16);
+ return accessibility_contents_utf16;
+}
+
std::unique_ptr<base::DictionaryValue>
AccessibilityTreeFormatter::FilterAccessibilityTree(
const base::DictionaryValue& dict) {
diff --git a/chromium/content/browser/accessibility/accessibility_tree_formatter.h b/chromium/content/browser/accessibility/accessibility_tree_formatter.h
index 536fcb617e7..51b8bc52c6a 100644
--- a/chromium/content/browser/accessibility/accessibility_tree_formatter.h
+++ b/chromium/content/browser/accessibility/accessibility_tree_formatter.h
@@ -99,6 +99,10 @@ class CONTENT_EXPORT AccessibilityTreeFormatter {
void FormatAccessibilityTree(const base::DictionaryValue& tree_node,
base::string16* contents);
+ static base::string16 DumpAccessibilityTreeFromManager(
+ BrowserAccessibilityManager* ax_mgr,
+ bool internal);
+
// Set regular expression filters that apply to each component of every
// line before it's output.
void SetFilters(const std::vector<Filter>& filters);
diff --git a/chromium/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc b/chromium/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc
index 568088325e4..596b7d7ebc6 100644
--- a/chromium/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc
+++ b/chromium/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc
@@ -56,6 +56,43 @@ void AccessibilityTreeFormatterAuraLinux::AddProperties(
acc_obj->GetNode()->AddAccessibilityTreeProperties(dict);
}
+const char* const ATK_OBJECT_ATTRIBUTES[] = {
+ "atomic",
+ "autocomplete",
+ "busy",
+ "checkable",
+ "class",
+ "colcount",
+ "colindex",
+ "container-atomic",
+ "container-busy",
+ "container-live",
+ "container-relevant",
+ "display",
+ "explicit-name",
+ "haspopup",
+ "id",
+ "keyshortcuts",
+ "level",
+ "live",
+ "placeholder",
+ "posinset",
+ "relevant",
+ "roledescription",
+ "rowcount",
+ "rowindex",
+ "setsize",
+ "src",
+ "table-cell-index",
+ "tag",
+ "text-input-type",
+ "valuemin",
+ "valuemax",
+ "valuenow",
+ "valuetext",
+ "xml-roles",
+};
+
base::string16 AccessibilityTreeFormatterAuraLinux::ProcessTreeForOutput(
const base::DictionaryValue& node,
base::DictionaryValue* filtered_dict_result) {
@@ -87,14 +124,24 @@ base::string16 AccessibilityTreeFormatterAuraLinux::ProcessTreeForOutput(
it != states_value->end(); ++it) {
std::string state_value;
if (it->GetAsString(&state_value))
- WriteAttribute(true, state_value, &line);
+ WriteAttribute(false, state_value, &line);
}
int id_value;
node.GetInteger("id", &id_value);
WriteAttribute(false, base::StringPrintf("id=%d", id_value), &line);
- return line + base::ASCIIToUTF16("\n");
+ for (const char* attribute_name : ATK_OBJECT_ATTRIBUTES) {
+ std::string attribute_value;
+ if (node.GetString(attribute_name, &attribute_value)) {
+ WriteAttribute(
+ false,
+ base::StringPrintf("%s:%s", attribute_name, attribute_value.c_str()),
+ &line);
+ }
+ }
+
+ return line;
}
const base::FilePath::StringType
diff --git a/chromium/content/browser/accessibility/accessibility_tree_formatter_win.cc b/chromium/content/browser/accessibility/accessibility_tree_formatter_win.cc
index 10b1967d4b5..20fd3b776fc 100644
--- a/chromium/content/browser/accessibility/accessibility_tree_formatter_win.cc
+++ b/chromium/content/browser/accessibility/accessibility_tree_formatter_win.cc
@@ -20,8 +20,8 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
+#include "base/win/com_init_util.h"
#include "base/win/scoped_bstr.h"
-#include "base/win/scoped_com_initializer.h"
#include "base/win/scoped_variant.h"
#include "content/browser/accessibility/accessibility_tree_formatter_utils_win.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
@@ -113,13 +113,11 @@ class AccessibilityTreeFormatterWin : public AccessibilityTreeFormatter {
base::string16 ProcessTreeForOutput(
const base::DictionaryValue& node,
base::DictionaryValue* filtered_dict_result = nullptr) override;
-
- // Initializes COM services when standalone dump events tool is used.
- base::win::ScopedCOMInitializer com_initializer;
};
// static
AccessibilityTreeFormatter* AccessibilityTreeFormatter::Create() {
+ base::win::AssertComInitialized();
return new AccessibilityTreeFormatterWin();
}
diff --git a/chromium/content/browser/accessibility/accessibility_ui.cc b/chromium/content/browser/accessibility/accessibility_ui.cc
deleted file mode 100644
index 4dada7363d2..00000000000
--- a/chromium/content/browser/accessibility/accessibility_ui.cc
+++ /dev/null
@@ -1,416 +0,0 @@
-// 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 "content/browser/accessibility/accessibility_ui.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/command_line.h"
-#include "base/json/json_writer.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
-#include "content/browser/accessibility/accessibility_tree_formatter.h"
-#include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
-#include "content/browser/accessibility/browser_accessibility_manager.h"
-#include "content/browser/accessibility/browser_accessibility_state_impl.h"
-#include "content/browser/renderer_host/render_view_host_impl.h"
-#include "content/browser/renderer_host/render_widget_host_impl.h"
-#include "content/browser/renderer_host/render_widget_host_view_base.h"
-#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/browser/web_contents/web_contents_view.h"
-#include "content/browser/webui/web_ui_data_source_impl.h"
-#include "content/common/view_message_enums.h"
-#include "content/grit/content_resources.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/favicon_status.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/render_widget_host.h"
-#include "content/public/browser/render_widget_host_iterator.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_ui_data_source.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/common/url_constants.h"
-#include "net/base/escape.h"
-#include "ui/accessibility/platform/ax_platform_node.h"
-#include "ui/base/webui/web_ui_util.h"
-
-static const char kTargetsDataFile[] = "targets-data.json";
-
-static const char kProcessIdField[] = "processId";
-static const char kRouteIdField[] = "routeId";
-static const char kUrlField[] = "url";
-static const char kNameField[] = "name";
-static const char kFaviconUrlField[] = "favicon_url";
-static const char kPidField[] = "pid";
-static const char kAccessibilityModeField[] = "a11y_mode";
-
-// Global flags
-static const char kInternal[] = "internal";
-static const char kNative[] = "native";
-static const char kWeb[] = "web";
-static const char kText[] = "text";
-static const char kScreenReader[] = "screenreader";
-static const char kHTML[] = "html";
-
-// Possible global flag values
-static const char kOff[]= "off";
-static const char kOn[] = "on";
-static const char kDisabled[] = "disabled";
-
-namespace content {
-
-namespace {
-
-bool g_show_internal_accessibility_tree = false;
-
-std::unique_ptr<base::DictionaryValue> BuildTargetDescriptor(
- const GURL& url,
- const std::string& name,
- const GURL& favicon_url,
- int process_id,
- int route_id,
- ui::AXMode accessibility_mode,
- base::ProcessHandle handle = base::kNullProcessHandle) {
- std::unique_ptr<base::DictionaryValue> target_data(
- new base::DictionaryValue());
- target_data->SetInteger(kProcessIdField, process_id);
- target_data->SetInteger(kRouteIdField, route_id);
- target_data->SetString(kUrlField, url.spec());
- target_data->SetString(kNameField, net::EscapeForHTML(name));
- target_data->SetInteger(kPidField, base::GetProcId(handle));
- target_data->SetString(kFaviconUrlField, favicon_url.spec());
- target_data->SetInteger(kAccessibilityModeField, accessibility_mode.mode());
- return target_data;
-}
-
-std::unique_ptr<base::DictionaryValue> BuildTargetDescriptor(
- RenderViewHost* rvh) {
- WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
- WebContents::FromRenderViewHost(rvh));
- ui::AXMode accessibility_mode;
-
- std::string title;
- GURL url;
- GURL favicon_url;
- if (web_contents) {
- // TODO(nasko): Fix the following code to use a consistent set of data
- // across the URL, title, and favicon.
- url = web_contents->GetURL();
- title = base::UTF16ToUTF8(web_contents->GetTitle());
- NavigationController& controller = web_contents->GetController();
- NavigationEntry* entry = controller.GetVisibleEntry();
- if (entry != nullptr && entry->GetURL().is_valid()) {
- gfx::Image favicon_image = entry->GetFavicon().image;
- if (!favicon_image.IsEmpty()) {
- const SkBitmap* favicon_bitmap = favicon_image.ToSkBitmap();
- favicon_url = GURL(webui::GetBitmapDataUrl(*favicon_bitmap));
- }
- }
- accessibility_mode = web_contents->GetAccessibilityMode();
- }
-
- return BuildTargetDescriptor(url,
- title,
- favicon_url,
- rvh->GetProcess()->GetID(),
- rvh->GetRoutingID(),
- accessibility_mode);
-}
-
-bool HandleAccessibilityRequestCallback(
- BrowserContext* current_context,
- const std::string& path,
- const WebUIDataSource::GotDataCallback& callback) {
- if (path != kTargetsDataFile)
- return false;
- std::unique_ptr<base::ListValue> rvh_list(new base::ListValue());
-
- std::unique_ptr<RenderWidgetHostIterator> widgets(
- RenderWidgetHost::GetRenderWidgetHosts());
-
- while (RenderWidgetHost* widget = widgets->GetNextHost()) {
- // Ignore processes that don't have a connection, such as crashed tabs.
- if (!widget->GetProcess()->IsInitializedAndNotDead())
- continue;
- RenderViewHost* rvh = RenderViewHost::From(widget);
- if (!rvh)
- continue;
- // Ignore views that are never visible, like background pages.
- if (static_cast<RenderViewHostImpl*>(rvh)->GetDelegate()->IsNeverVisible())
- continue;
- BrowserContext* context = rvh->GetProcess()->GetBrowserContext();
- if (context != current_context)
- continue;
-
- rvh_list->Append(BuildTargetDescriptor(rvh));
- }
-
- base::DictionaryValue data;
- data.Set("list", std::move(rvh_list));
- ui::AXMode mode =
- BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode();
- bool disabled = base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableRendererAccessibility);
- bool native = mode.has_mode(ui::AXMode::kNativeAPIs);
- bool web = mode.has_mode(ui::AXMode::kWebContents);
- bool text = mode.has_mode(ui::AXMode::kInlineTextBoxes);
- bool screenreader = mode.has_mode(ui::AXMode::kScreenReader);
- bool html = mode.has_mode(ui::AXMode::kHTML);
-
- // The "native" and "web" flags are disabled if
- // --disable-renderer-accessibility is set.
- data.SetString(kNative, disabled ? kDisabled : (native ? kOn : kOff));
- data.SetString(kWeb, disabled ? kDisabled : (web ? kOn : kOff));
-
- // The "text", "screenreader", and "html" flags are only meaningful if
- // "web" is enabled.
- data.SetString(kText, web ? (text ? kOn : kOff) : kDisabled);
- data.SetString(kScreenReader, web ? (screenreader ? kOn : kOff) : kDisabled);
- data.SetString(kHTML, web ? (html ? kOn : kOff) : kDisabled);
-
- data.SetString(kInternal,
- g_show_internal_accessibility_tree ? kOn : kOff);
-
- std::string json_string;
- base::JSONWriter::Write(data, &json_string);
-
- callback.Run(base::RefCountedString::TakeString(&json_string));
- return true;
-}
-
-std::string RecursiveDumpAXPlatformNodeAsString(ui::AXPlatformNode* node,
- int indent) {
- std::string str(2 * indent, '+');
- str += node->GetDelegate()->GetData().ToString() + "\n";
- for (int i = 0; i < node->GetDelegate()->GetChildCount(); i++) {
- gfx::NativeViewAccessible child = node->GetDelegate()->ChildAtIndex(i);
- ui::AXPlatformNode* child_node =
- ui::AXPlatformNode::FromNativeViewAccessible(child);
- if (child_node)
- str += RecursiveDumpAXPlatformNodeAsString(child_node, indent + 1);
- }
- return str;
-}
-
-} // namespace
-
-AccessibilityUI::AccessibilityUI(WebUI* web_ui) : WebUIController(web_ui) {
- // Set up the chrome://accessibility source.
- WebUIDataSourceImpl* html_source = static_cast<WebUIDataSourceImpl*>(
- WebUIDataSource::Create(kChromeUIAccessibilityHost));
-
- // Add required resources.
- html_source->SetJsonPath("strings.js");
- html_source->AddResourcePath("accessibility.css", IDR_ACCESSIBILITY_CSS);
- html_source->AddResourcePath("accessibility.js", IDR_ACCESSIBILITY_JS);
- html_source->SetDefaultResource(IDR_ACCESSIBILITY_HTML);
- html_source->SetRequestFilter(
- base::Bind(&HandleAccessibilityRequestCallback,
- web_ui->GetWebContents()->GetBrowserContext()));
-
- html_source->UseGzip({kTargetsDataFile});
-
- BrowserContext* browser_context =
- web_ui->GetWebContents()->GetBrowserContext();
- WebUIDataSource::Add(browser_context, html_source);
-
- web_ui->AddMessageHandler(std::make_unique<AccessibilityUIMessageHandler>());
-}
-
-AccessibilityUI::~AccessibilityUI() {}
-
-AccessibilityUIMessageHandler::AccessibilityUIMessageHandler() {}
-
-AccessibilityUIMessageHandler::~AccessibilityUIMessageHandler() {}
-
-void AccessibilityUIMessageHandler::RegisterMessages() {
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
- web_ui()->RegisterMessageCallback(
- "toggleAccessibility",
- base::BindRepeating(&AccessibilityUIMessageHandler::ToggleAccessibility,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback(
- "setGlobalFlag",
- base::BindRepeating(&AccessibilityUIMessageHandler::SetGlobalFlag,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback(
- "requestWebContentsTree",
- base::BindRepeating(
- &AccessibilityUIMessageHandler::RequestWebContentsTree,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback(
- "requestNativeUITree",
- base::BindRepeating(&AccessibilityUIMessageHandler::RequestNativeUITree,
- base::Unretained(this)));
-}
-
-void AccessibilityUIMessageHandler::ToggleAccessibility(
- const base::ListValue* args) {
- std::string process_id_str;
- std::string route_id_str;
- int process_id;
- int route_id;
- int mode;
- CHECK_EQ(3U, args->GetSize());
- CHECK(args->GetString(0, &process_id_str));
- CHECK(args->GetString(1, &route_id_str));
- // TODO(695247): We should pass each ax flag seperately
- CHECK(args->GetInteger(2, &mode));
- CHECK(base::StringToInt(process_id_str, &process_id));
- CHECK(base::StringToInt(route_id_str, &route_id));
-
- AllowJavascript();
- RenderViewHost* rvh = RenderViewHost::FromID(process_id, route_id);
- if (!rvh)
- return;
- auto* web_contents =
- static_cast<WebContentsImpl*>(WebContents::FromRenderViewHost(rvh));
- ui::AXMode current_mode = web_contents->GetAccessibilityMode();
-
- if (mode & ui::AXMode::kNativeAPIs)
- current_mode.set_mode(ui::AXMode::kNativeAPIs, true);
-
- if (mode & ui::AXMode::kWebContents)
- current_mode.set_mode(ui::AXMode::kWebContents, true);
-
- if (mode & ui::AXMode::kInlineTextBoxes)
- current_mode.set_mode(ui::AXMode::kInlineTextBoxes, true);
-
- if (mode & ui::AXMode::kScreenReader)
- current_mode.set_mode(ui::AXMode::kScreenReader, true);
-
- if (mode & ui::AXMode::kHTML)
- current_mode.set_mode(ui::AXMode::kHTML, true);
-
- web_contents->SetAccessibilityMode(current_mode);
-}
-
-void AccessibilityUIMessageHandler::SetGlobalFlag(const base::ListValue* args) {
- std::string flag_name_str;
- bool enabled;
- CHECK_EQ(2U, args->GetSize());
- CHECK(args->GetString(0, &flag_name_str));
- CHECK(args->GetBoolean(1, &enabled));
-
- AllowJavascript();
- if (flag_name_str == kInternal) {
- g_show_internal_accessibility_tree = enabled;
- LOG(ERROR) << "INTERNAL: " << g_show_internal_accessibility_tree;
- return;
- }
-
- ui::AXMode new_mode;
- if (flag_name_str == kNative) {
- new_mode = ui::AXMode::kNativeAPIs;
- } else if (flag_name_str == kWeb) {
- new_mode = ui::AXMode::kWebContents;
- } else if (flag_name_str == kText) {
- new_mode = ui::AXMode::kInlineTextBoxes;
- } else if (flag_name_str == kScreenReader) {
- new_mode = ui::AXMode::kScreenReader;
- } else if (flag_name_str == kHTML) {
- new_mode = ui::AXMode::kHTML;
- } else {
- NOTREACHED();
- return;
- }
-
- // It doesn't make sense to enable one of the flags that depends on
- // web contents without enabling web contents accessibility too.
- if (enabled && (new_mode.has_mode(ui::AXMode::kInlineTextBoxes) ||
- new_mode.has_mode(ui::AXMode::kScreenReader) ||
- new_mode.has_mode(ui::AXMode::kHTML))) {
- new_mode.set_mode(ui::AXMode::kWebContents, true);
- }
-
- // Similarly if you disable web accessibility we should remove all
- // flags that depend on it.
- if (!enabled && new_mode.has_mode(ui::AXMode::kWebContents)) {
- new_mode.set_mode(ui::AXMode::kInlineTextBoxes, true);
- new_mode.set_mode(ui::AXMode::kScreenReader, true);
- new_mode.set_mode(ui::AXMode::kHTML, true);
- }
-
- BrowserAccessibilityStateImpl* state =
- BrowserAccessibilityStateImpl::GetInstance();
- if (enabled)
- state->AddAccessibilityModeFlags(new_mode);
- else
- state->RemoveAccessibilityModeFlags(new_mode);
-}
-
-void AccessibilityUIMessageHandler::RequestWebContentsTree(
- const base::ListValue* args) {
- std::string process_id_str;
- std::string route_id_str;
- int process_id;
- int route_id;
- CHECK_EQ(2U, args->GetSize());
- CHECK(args->GetString(0, &process_id_str));
- CHECK(args->GetString(1, &route_id_str));
- CHECK(base::StringToInt(process_id_str, &process_id));
- CHECK(base::StringToInt(route_id_str, &route_id));
-
- AllowJavascript();
- RenderViewHost* rvh = RenderViewHost::FromID(process_id, route_id);
- if (!rvh) {
- std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue());
- result->SetInteger(kProcessIdField, process_id);
- result->SetInteger(kRouteIdField, route_id);
- result->SetString("error", "Renderer no longer exists.");
- CallJavascriptFunction("accessibility.showTree", *(result.get()));
- return;
- }
-
- std::unique_ptr<base::DictionaryValue> result(BuildTargetDescriptor(rvh));
- auto* web_contents =
- static_cast<WebContentsImpl*>(WebContents::FromRenderViewHost(rvh));
- // No matter the state of the current web_contents, we want to force the mode
- // because we are about to show the accessibility tree
- web_contents->SetAccessibilityMode(
- ui::AXMode(ui::AXMode::kNativeAPIs | ui::AXMode::kWebContents));
-
- std::unique_ptr<AccessibilityTreeFormatter> formatter;
- if (g_show_internal_accessibility_tree)
- formatter.reset(new AccessibilityTreeFormatterBlink());
- else
- formatter.reset(AccessibilityTreeFormatter::Create());
- base::string16 accessibility_contents_utf16;
- std::vector<AccessibilityTreeFormatter::Filter> filters;
- filters.push_back(AccessibilityTreeFormatter::Filter(
- base::ASCIIToUTF16("*"),
- AccessibilityTreeFormatter::Filter::ALLOW));
- formatter->SetFilters(filters);
- auto* ax_mgr = web_contents->GetOrCreateRootBrowserAccessibilityManager();
- DCHECK(ax_mgr);
- formatter->FormatAccessibilityTree(ax_mgr->GetRoot(),
- &accessibility_contents_utf16);
- result->SetString("tree", base::UTF16ToUTF8(accessibility_contents_utf16));
- CallJavascriptFunction("accessibility.showTree", *(result.get()));
-}
-
-void AccessibilityUIMessageHandler::RequestNativeUITree(
- const base::ListValue* args) {
- AllowJavascript();
- WebContentsImpl* web_contents =
- static_cast<WebContentsImpl*>(web_ui()->GetWebContents());
- gfx::NativeWindow native_window =
- web_contents->GetView()->GetTopLevelNativeWindow();
- ui::AXPlatformNode* node =
- ui::AXPlatformNode::FromNativeWindow(native_window);
- std::string str = RecursiveDumpAXPlatformNodeAsString(node, 0);
-
- std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue());
- result->SetString("tree", str);
- CallJavascriptFunction("accessibility.showNativeUITree", *(result.get()));
-}
-
-} // namespace content
diff --git a/chromium/content/browser/accessibility/accessibility_ui.h b/chromium/content/browser/accessibility/accessibility_ui.h
deleted file mode 100644
index a54f23d3502..00000000000
--- a/chromium/content/browser/accessibility/accessibility_ui.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// 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 CONTENT_BROWSER_ACCESSIBILITY_ACCESSIBILITY_UI_H_
-#define CONTENT_BROWSER_ACCESSIBILITY_ACCESSIBILITY_UI_H_
-
-#include "base/macros.h"
-#include "content/public/browser/web_ui_controller.h"
-#include "content/public/browser/web_ui_data_source.h"
-#include "content/public/browser/web_ui_message_handler.h"
-
-namespace base {
- class ListValue;
-} // namespace base
-
-namespace content {
-
-class AccessibilityUI : public WebUIController {
- public:
- explicit AccessibilityUI(WebUI* web_ui);
- ~AccessibilityUI() override;
-};
-
-class AccessibilityUIMessageHandler : public content::WebUIMessageHandler {
- public:
- AccessibilityUIMessageHandler();
- ~AccessibilityUIMessageHandler() override;
-
- void RegisterMessages() override;
-
- private:
- void ToggleAccessibility(const base::ListValue* args);
- void SetGlobalFlag(const base::ListValue* args);
- void RequestWebContentsTree(const base::ListValue* args);
- void RequestNativeUITree(const base::ListValue* args);
-
- DISALLOW_COPY_AND_ASSIGN(AccessibilityUIMessageHandler);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_ACCESSIBILITY_ACCESSIBILITY_UI_H_
diff --git a/chromium/content/browser/accessibility/accessibility_win_browsertest.cc b/chromium/content/browser/accessibility/accessibility_win_browsertest.cc
index 4ab51921d62..9bb5760cfdb 100644
--- a/chromium/content/browser/accessibility/accessibility_win_browsertest.cc
+++ b/chromium/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -683,7 +683,7 @@ void AccessibilityWinBrowserTest::AccessibleChecker::CheckIA2Role(
Microsoft::WRL::ComPtr<IAccessible2> accessible2;
HRESULT hr = QueryIAccessible2(accessible, accessible2.GetAddressOf());
ASSERT_EQ(S_OK, hr);
- long ia2_role = 0;
+ LONG ia2_role = 0;
hr = accessible2->role(&ia2_role);
ASSERT_EQ(S_OK, hr);
EXPECT_EQ(ia2_role_, ia2_role)
@@ -771,14 +771,14 @@ class NativeWinEventWaiter {
NativeWinEventWaiter(BrowserAccessibilityManager* manager,
const std::string& match_pattern)
: event_recorder_(
- AccessibilityEventRecorder::Create(manager,
- base::GetCurrentProcId())),
+ AccessibilityEventRecorder::GetInstance(manager,
+ base::GetCurrentProcId())),
match_pattern_(match_pattern) {
- event_recorder_->ListenToEvents(base::BindRepeating(
+ event_recorder_.ListenToEvents(base::BindRepeating(
&NativeWinEventWaiter::OnEvent, base::Unretained(this)));
}
- void OnEvent(std::string event_str) {
+ void OnEvent(const std::string& event_str) {
DLOG(INFO) << "Got event " + event_str;
if (base::MatchPattern(event_str, match_pattern_))
run_loop_.QuitClosure().Run();
@@ -787,7 +787,7 @@ class NativeWinEventWaiter {
void Wait() { run_loop_.Run(); }
private:
- std::unique_ptr<AccessibilityEventRecorder> event_recorder_;
+ AccessibilityEventRecorder& event_recorder_;
std::string match_pattern_;
base::RunLoop run_loop_;
};
@@ -1290,16 +1290,12 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
EXPECT_EQ(previous_height, height) << "at offset " << offset;
}
- // Vertically offscreen objects should have a height of 1px so that if an
- // assistive aid ignores the offscreen state, they will still be too small
- // to be visible and thus not appear outside the window. Note that a height
- // of 0 is not used because it signifies an invalid size.
EXPECT_HRESULT_SUCCEEDED(editable_container->get_characterExtents(
last_line_start, coordinate_type, &x, &y, &width, &height));
EXPECT_LT(0, x) << "at offset " << last_line_start;
EXPECT_LT(previous_y, y) << "at offset " << last_line_start;
EXPECT_LT(1, width) << "at offset " << last_line_start;
- EXPECT_EQ(1, height) << "at offset " << last_line_start;
+ EXPECT_EQ(previous_height, height) << "at offset " << last_line_start;
for (LONG offset = last_line_start + 1; offset < n_characters; ++offset) {
previous_x = x;
@@ -1310,7 +1306,7 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
EXPECT_LT(previous_x, x) << "at offset " << offset;
EXPECT_EQ(previous_y, y) << "at offset " << offset;
EXPECT_LT(1, width) << "at offset " << offset;
- EXPECT_EQ(1, height) << "at offset " << offset;
+ EXPECT_EQ(previous_height, height) << "at offset " << offset;
}
}
}
@@ -1334,21 +1330,13 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
coordinate <= IA2_COORDTYPE_PARENT_RELATIVE; ++coordinate) {
auto coordinate_type = static_cast<IA2CoordinateType>(coordinate);
- // Horizontally offscreen objects should have a width of 1px so that if an
- // assistive aid ignores the offscreen state, they will still be too small
- // to be visible and thus not appear outside the window. Note that a width
- // of 0 is not used because it signifies an invalid size.
EXPECT_HRESULT_SUCCEEDED(input_text->get_characterExtents(
0, coordinate_type, &x, &y, &width, &height));
- EXPECT_LT(0, x + width) << "at offset 0";
+ EXPECT_GT(0, x + width) << "at offset 0";
EXPECT_LT(0, y) << "at offset 0";
- EXPECT_EQ(1, width) << "at offset 0";
+ EXPECT_LT(1, width) << "at offset 0";
EXPECT_LT(1, height) << "at offset 0";
- // Test that characters at the start of the input field are offscreen by
- // checking that their x coordinate is at the start of the field and their
- // width is 1.
- // Exclude the character that is partly visible.
for (LONG offset = 1; offset < (visible_characters_start - 1); ++offset) {
previous_x = x;
previous_y = y;
@@ -1356,9 +1344,9 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
EXPECT_HRESULT_SUCCEEDED(input_text->get_characterExtents(
offset, coordinate_type, &x, &y, &width, &height));
- EXPECT_EQ(previous_x, x) << "at offset " << offset;
+ EXPECT_LT(previous_x, x) << "at offset " << offset;
EXPECT_EQ(previous_y, y) << "at offset " << offset;
- EXPECT_EQ(1, width) << "at offset " << offset;
+ EXPECT_LT(1, width) << "at offset " << offset;
EXPECT_EQ(previous_height, height) << "at offset " << offset;
}
@@ -1366,7 +1354,7 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
// width that is greater than 1px.
EXPECT_HRESULT_SUCCEEDED(input_text->get_characterExtents(
visible_characters_start, coordinate_type, &x, &y, &width, &height));
- EXPECT_EQ(previous_x, x) << "at offset " << visible_characters_start;
+ EXPECT_LT(previous_x, x) << "at offset " << visible_characters_start;
EXPECT_EQ(previous_y, y) << "at offset " << visible_characters_start;
EXPECT_LT(1, width) << "at offset " << visible_characters_start;
EXPECT_EQ(previous_height, height)
diff --git a/chromium/content/browser/accessibility/browser_accessibility.cc b/chromium/content/browser/accessibility/browser_accessibility.cc
index 68e62b1db86..10485315e69 100644
--- a/chromium/content/browser/accessibility/browser_accessibility.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility.cc
@@ -343,8 +343,9 @@ gfx::Rect BrowserAccessibility::GetPageBoundsRect(bool* offscreen,
return RelativeToAbsoluteBounds(gfx::RectF(), false, offscreen, clip_bounds);
}
-gfx::Rect BrowserAccessibility::GetPageBoundsForRange(int start, int len)
- const {
+gfx::Rect BrowserAccessibility::GetPageBoundsForRange(int start,
+ int len,
+ bool clipped) const {
DCHECK_GE(start, 0);
DCHECK_GE(len, 0);
@@ -464,9 +465,11 @@ gfx::Rect BrowserAccessibility::GetPageBoundsForRange(int start, int len)
}
}
+ // Don't clip bounds. Some screen magnifiers (e.g. ZoomText) prefer to
+ // get unclipped bounds so that they can make smooth scrolling calculations.
gfx::Rect absolute_child_rect = child->RelativeToAbsoluteBounds(
child_overlap_rect, false /* frame_only */, nullptr /* offscreen */,
- true /* clip_bounds */);
+ clipped /* clip_bounds */);
if (bounds.width() == 0 && bounds.height() == 0) {
bounds = absolute_child_rect;
} else {
@@ -477,9 +480,10 @@ gfx::Rect BrowserAccessibility::GetPageBoundsForRange(int start, int len)
return bounds;
}
-gfx::Rect BrowserAccessibility::GetScreenBoundsForRange(int start, int len)
- const {
- gfx::Rect bounds = GetPageBoundsForRange(start, len);
+gfx::Rect BrowserAccessibility::GetScreenBoundsForRange(int start,
+ int len,
+ bool clipped) const {
+ gfx::Rect bounds = GetPageBoundsForRange(start, len, clipped);
// Adjust the bounds by the top left corner of the containing view's bounds
// in screen coordinates.
@@ -687,20 +691,24 @@ bool BrowserAccessibility::HasAction(ax::mojom::Action action_enum) const {
return GetData().HasAction(action_enum);
}
-bool BrowserAccessibility::HasCaret() const {
- if (IsPlainTextField() &&
- HasIntAttribute(ax::mojom::IntAttribute::kTextSelStart) &&
- HasIntAttribute(ax::mojom::IntAttribute::kTextSelEnd)) {
- return true;
- }
-
- // The caret is always at the focus of the selection.
+bool BrowserAccessibility::HasVisibleCaretOrSelection() const {
int32_t focus_id = manager()->GetTreeData().sel_focus_object_id;
BrowserAccessibility* focus_object = manager()->GetFromID(focus_id);
if (!focus_object)
return false;
- return focus_object->IsDescendantOf(this);
+ // Selection or caret will be visible in a focused editable area.
+ if (HasState(ax::mojom::State::kEditable)) {
+ return IsPlainTextField() ? focus_object == this
+ : focus_object->IsDescendantOf(this);
+ }
+
+ // The selection will be visible in non-editable content only if it is not
+ // collapsed into a caret.
+ return (focus_id != manager()->GetTreeData().sel_anchor_object_id ||
+ manager()->GetTreeData().sel_focus_offset !=
+ manager()->GetTreeData().sel_anchor_offset) &&
+ focus_object->IsDescendantOf(this);
}
bool BrowserAccessibility::IsWebAreaForPresentationalIframe() const {
@@ -764,6 +772,24 @@ std::string BrowserAccessibility::ComputeAccessibleNameFromDescendants() const {
return name;
}
+std::string BrowserAccessibility::GetLiveRegionText() const {
+ if (GetRole() == ax::mojom::Role::kIgnored)
+ return "";
+
+ std::string text = GetStringAttribute(ax::mojom::StringAttribute::kName);
+ if (!text.empty())
+ return text;
+
+ for (size_t i = 0; i < InternalChildCount(); ++i) {
+ BrowserAccessibility* child = InternalGetChild(i);
+ if (!child)
+ continue;
+
+ text += child->GetLiveRegionText();
+ }
+ return text;
+}
+
std::vector<int> BrowserAccessibility::GetLineStartOffsets() const {
if (!instance_active())
return std::vector<int>();
diff --git a/chromium/content/browser/accessibility/browser_accessibility.h b/chromium/content/browser/accessibility/browser_accessibility.h
index f3d85b39061..b66d5e86384 100644
--- a/chromium/content/browser/accessibility/browser_accessibility.h
+++ b/chromium/content/browser/accessibility/browser_accessibility.h
@@ -160,10 +160,14 @@ class CONTENT_EXPORT BrowserAccessibility : public ui::AXPlatformNodeDelegate {
// Returns the bounds of the given range in coordinates relative to the
// top-left corner of the overall web area. Only valid when the
// role is WebAXRoleStaticText.
- gfx::Rect GetPageBoundsForRange(int start, int len) const;
+ gfx::Rect GetPageBoundsForRange(int start,
+ int len,
+ bool clipped = false) const;
// Same as |GetPageBoundsForRange| but in screen coordinates.
- gfx::Rect GetScreenBoundsForRange(int start, int len) const;
+ gfx::Rect GetScreenBoundsForRange(int start,
+ int len,
+ bool clipped = false) const;
// Convert a bounding rectangle from this node's coordinate system
// (which is relative to its nearest scrollable ancestor) to
@@ -299,8 +303,8 @@ class CONTENT_EXPORT BrowserAccessibility : public ui::AXPlatformNodeDelegate {
bool HasState(ax::mojom::State state_enum) const;
bool HasAction(ax::mojom::Action action_enum) const;
- // Returns true if the caret is active on this object.
- bool HasCaret() const;
+ // Returns true if the caret or selection is visible on this object.
+ bool HasVisibleCaretOrSelection() const;
// True if this is a web area, and its grandparent is a presentational iframe.
bool IsWebAreaForPresentationalIframe() const;
@@ -316,6 +320,9 @@ class CONTENT_EXPORT BrowserAccessibility : public ui::AXPlatformNodeDelegate {
// to compute a name from its descendants.
std::string ComputeAccessibleNameFromDescendants() const;
+ // Get text to announce for a live region change if AT does not implement.
+ std::string GetLiveRegionText() const;
+
// Creates a text position rooted at this object.
BrowserAccessibilityPosition::AXPositionInstance CreatePositionAt(
int offset,
diff --git a/chromium/content/browser/accessibility/browser_accessibility_android.cc b/chromium/content/browser/accessibility/browser_accessibility_android.cc
index 3dd224bd18d..95b60d9f0d0 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_android.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_android.cc
@@ -761,6 +761,9 @@ base::string16 BrowserAccessibilityAndroid::GetRoleDescription() const {
case ax::mojom::Role::kInputTime:
message_id = IDS_AX_ROLE_INPUT_TIME;
break;
+ case ax::mojom::Role::kKeyboard:
+ // No role description.
+ break;
case ax::mojom::Role::kLabelText:
// No role description.
break;
diff --git a/chromium/content/browser/accessibility/browser_accessibility_auralinux.cc b/chromium/content/browser/accessibility/browser_accessibility_auralinux.cc
index 3921dd72764..3d63387ab0e 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_auralinux.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_auralinux.cc
@@ -46,6 +46,10 @@ void BrowserAccessibilityAuraLinux::OnDataChanged() {
node_->DataChanged();
}
+void BrowserAccessibilityAuraLinux::UpdatePlatformAttributes() {
+ GetNode()->UpdateHypertext();
+}
+
bool BrowserAccessibilityAuraLinux::IsNative() const {
return true;
}
diff --git a/chromium/content/browser/accessibility/browser_accessibility_auralinux.h b/chromium/content/browser/accessibility/browser_accessibility_auralinux.h
index 6ba7d6f6b31..ba263d95bdf 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_auralinux.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_auralinux.h
@@ -22,7 +22,11 @@ class BrowserAccessibilityAuraLinux : public BrowserAccessibility {
~BrowserAccessibilityAuraLinux() override;
- ui::AXPlatformNodeAuraLinux* GetNode() const;
+ CONTENT_EXPORT ui::AXPlatformNodeAuraLinux* GetNode() const;
+
+ // This is used to call UpdateHypertext, when a node needs to be
+ // updated for some other reason other than via OnAtomicUpdateFinished.
+ void UpdatePlatformAttributes() override;
// BrowserAccessibility methods.
void OnDataChanged() override;
diff --git a/chromium/content/browser/accessibility/browser_accessibility_auralinux_unittest.cc b/chromium/content/browser/accessibility/browser_accessibility_auralinux_unittest.cc
new file mode 100644
index 00000000000..3d31036acac
--- /dev/null
+++ b/chromium/content/browser/accessibility/browser_accessibility_auralinux_unittest.cc
@@ -0,0 +1,121 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/accessibility/browser_accessibility_auralinux.h"
+
+#include <atk/atk.h>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/accessibility/platform/ax_platform_node_auralinux.h"
+
+namespace content {
+
+class BrowserAccessibilityAuraLinuxTest : public testing::Test {
+ public:
+ BrowserAccessibilityAuraLinuxTest();
+ ~BrowserAccessibilityAuraLinuxTest() override;
+
+ private:
+ void SetUp() override;
+
+ content::TestBrowserThreadBundle thread_bundle_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityAuraLinuxTest);
+};
+
+BrowserAccessibilityAuraLinuxTest::BrowserAccessibilityAuraLinuxTest() {}
+
+BrowserAccessibilityAuraLinuxTest::~BrowserAccessibilityAuraLinuxTest() {}
+
+void BrowserAccessibilityAuraLinuxTest::SetUp() {}
+
+TEST_F(BrowserAccessibilityAuraLinuxTest, TestSimpleAtkText) {
+ ui::AXNodeData root_data;
+ root_data.id = 1;
+ root_data.role = ax::mojom::Role::kStaticText;
+ root_data.SetName("\xE2\x98\xBA Multiple Words");
+
+ std::unique_ptr<BrowserAccessibilityManager> manager(
+ BrowserAccessibilityManager::Create(MakeAXTreeUpdate(root_data), nullptr,
+ new BrowserAccessibilityFactory()));
+
+ ui::AXPlatformNodeAuraLinux* root_obj =
+ ToBrowserAccessibilityAuraLinux(manager->GetRoot())->GetNode();
+ AtkObject* root_atk_object(root_obj->GetNativeViewAccessible());
+ ASSERT_TRUE(ATK_IS_OBJECT(root_atk_object));
+ ASSERT_TRUE(ATK_IS_TEXT(root_atk_object));
+ g_object_ref(root_atk_object);
+
+ AtkText* atk_text = ATK_TEXT(root_atk_object);
+
+ auto verify_atk_text_contents = [&](const char* expected_text,
+ int start_offset, int end_offset) {
+ gchar* text = atk_text_get_text(atk_text, start_offset, end_offset);
+ EXPECT_STREQ(expected_text, text);
+ g_free(text);
+ };
+
+ verify_atk_text_contents("\xE2\x98\xBA Multiple Words", 0, -1);
+ verify_atk_text_contents("Multiple Words", 2, -1);
+ verify_atk_text_contents("\xE2\x98\xBA", 0, 1);
+
+ EXPECT_EQ(16, atk_text_get_character_count(atk_text));
+
+ g_object_unref(root_atk_object);
+
+ manager.reset();
+}
+
+TEST_F(BrowserAccessibilityAuraLinuxTest, TestCompositeAtkText) {
+ const std::string text1_name = "One two three.";
+ const std::string text2_name = " Four five six.";
+ const int text_name_len = text1_name.length() + text2_name.length();
+
+ ui::AXNodeData text1;
+ text1.id = 11;
+ text1.role = ax::mojom::Role::kStaticText;
+ text1.SetName(text1_name);
+
+ ui::AXNodeData text2;
+ text2.id = 12;
+ text2.role = ax::mojom::Role::kStaticText;
+ text2.SetName(text2_name);
+
+ ui::AXNodeData root;
+ root.id = 1;
+ root.role = ax::mojom::Role::kRootWebArea;
+ root.child_ids.push_back(text1.id);
+ root.child_ids.push_back(text2.id);
+
+ std::unique_ptr<BrowserAccessibilityManager> manager(
+ BrowserAccessibilityManager::Create(MakeAXTreeUpdate(root, text1, text2),
+ nullptr,
+ new BrowserAccessibilityFactory()));
+
+ ui::AXPlatformNodeAuraLinux* root_obj =
+ ToBrowserAccessibilityAuraLinux(manager->GetRoot())->GetNode();
+ AtkObject* root_atk_object(root_obj->GetNativeViewAccessible());
+
+ ASSERT_TRUE(ATK_IS_OBJECT(root_atk_object));
+ ASSERT_TRUE(ATK_IS_TEXT(root_atk_object));
+ g_object_ref(root_atk_object);
+ AtkText* atk_text = ATK_TEXT(root_atk_object);
+
+ EXPECT_EQ(text_name_len, atk_text_get_character_count(atk_text));
+
+ gchar* text = atk_text_get_text(atk_text, 0, -1);
+ EXPECT_STREQ((text1_name + text2_name).c_str(), text);
+ g_free(text);
+
+ g_object_unref(root_atk_object);
+
+ manager.reset();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/accessibility/browser_accessibility_cocoa.mm b/chromium/content/browser/accessibility/browser_accessibility_cocoa.mm
index 07e9862b76a..06db282cd74 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/chromium/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -833,7 +833,9 @@ NSString* const NSAccessibilityRequiredAttributeChrome = @"AXRequired";
if (![self isIgnored]) {
children_.reset();
} else {
- [ToBrowserAccessibilityCocoa(owner_->PlatformGetParent()) childrenChanged];
+ auto* parent = owner_->PlatformGetParent();
+ if (parent)
+ [ToBrowserAccessibilityCocoa(parent) childrenChanged];
}
}
@@ -1720,8 +1722,11 @@ NSString* const NSAccessibilityRequiredAttributeChrome = @"AXRequired";
std::string role_attribute;
if (owner_->GetHtmlAttribute("role", &role_attribute)) {
ax::mojom::Role internalRole = [self internalRole];
- if ((internalRole != ax::mojom::Role::kGroup &&
- internalRole != ax::mojom::Role::kListItem) ||
+ if ((internalRole != ax::mojom::Role::kBlockquote &&
+ internalRole != ax::mojom::Role::kCaption &&
+ internalRole != ax::mojom::Role::kGroup &&
+ internalRole != ax::mojom::Role::kListItem &&
+ internalRole != ax::mojom::Role::kParagraph) ||
internalRole == ax::mojom::Role::kTab) {
// TODO(dtseng): This is not localized; see crbug/84814.
return base::SysUTF8ToNSString(role_attribute);
@@ -2276,6 +2281,7 @@ NSString* const NSAccessibilityRequiredAttributeChrome = @"AXRequired";
return base::SysUTF16ToNSString(owner_->GetValue());
}
+// TODO(crbug.com/865101) Remove this once the autofill state works.
- (BOOL)isFocusedInputWithSuggestions {
if (!owner_->IsPlainTextField())
return false;
@@ -2288,6 +2294,8 @@ NSString* const NSAccessibilityRequiredAttributeChrome = @"AXRequired";
- (NSNumber*)valueAutofillAvailable {
if (![self instanceActive])
return nil;
+ // TODO(crbug.com/865101) Use this instead:
+ // return owner_->HasState(ax::mojom::State::kAutofillAvailable) ? @YES : @NO;
return [self isFocusedInputWithSuggestions] ? @YES : @NO;
}
diff --git a/chromium/content/browser/accessibility/browser_accessibility_com_win.cc b/chromium/content/browser/accessibility/browser_accessibility_com_win.cc
index ce687913fb2..c874c05dd94 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_com_win.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_com_win.cc
@@ -70,12 +70,12 @@ BrowserAccessibilityComWin::~BrowserAccessibilityComWin() {
// IAccessible2 overrides:
//
-STDMETHODIMP BrowserAccessibilityComWin::get_attributes(BSTR* attributes) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_attributes(BSTR* attributes) {
// This can be removed once ISimpleDOMNode is migrated
return AXPlatformNodeWin::get_attributes(attributes);
}
-STDMETHODIMP BrowserAccessibilityComWin::scrollTo(IA2ScrollType scroll_type) {
+IFACEMETHODIMP BrowserAccessibilityComWin::scrollTo(IA2ScrollType scroll_type) {
// This can be removed once ISimpleDOMNode is migrated
return AXPlatformNodeWin::scrollTo(scroll_type);
}
@@ -84,7 +84,7 @@ STDMETHODIMP BrowserAccessibilityComWin::scrollTo(IA2ScrollType scroll_type) {
// IAccessibleApplication methods.
//
-STDMETHODIMP BrowserAccessibilityComWin::get_appName(BSTR* app_name) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_appName(BSTR* app_name) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_APP_NAME);
if (!app_name)
@@ -103,7 +103,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_appName(BSTR* app_name) {
return *app_name ? S_OK : E_FAIL;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_appVersion(BSTR* app_version) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_appVersion(BSTR* app_version) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_APP_VERSION);
if (!app_version)
@@ -123,7 +123,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_appVersion(BSTR* app_version) {
return *app_version ? S_OK : E_FAIL;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_toolkitName(BSTR* toolkit_name) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_toolkitName(BSTR* toolkit_name) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_TOOLKIT_NAME);
if (!toolkit_name)
return E_INVALIDARG;
@@ -136,7 +136,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_toolkitName(BSTR* toolkit_name) {
return *toolkit_name ? S_OK : E_FAIL;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_toolkitVersion(
+IFACEMETHODIMP BrowserAccessibilityComWin::get_toolkitVersion(
BSTR* toolkit_version) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_TOOLKIT_VERSION);
if (!toolkit_version)
@@ -152,7 +152,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_toolkitVersion(
// IAccessibleImage methods.
//
-STDMETHODIMP BrowserAccessibilityComWin::get_description(BSTR* desc) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_description(BSTR* desc) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_DESCRIPTION);
if (!owner())
return E_FAIL;
@@ -169,7 +169,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_description(BSTR* desc) {
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_imagePosition(
+IFACEMETHODIMP BrowserAccessibilityComWin::get_imagePosition(
IA2CoordinateType coordinate_type,
LONG* x,
LONG* y) {
@@ -199,8 +199,8 @@ STDMETHODIMP BrowserAccessibilityComWin::get_imagePosition(
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_imageSize(LONG* height,
- LONG* width) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_imageSize(LONG* height,
+ LONG* width) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_IMAGE_SIZE);
if (!owner())
return E_FAIL;
@@ -217,15 +217,15 @@ STDMETHODIMP BrowserAccessibilityComWin::get_imageSize(LONG* height,
// IAccessibleText methods.
//
-STDMETHODIMP BrowserAccessibilityComWin::get_nCharacters(LONG* n_characters) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_nCharacters(LONG* n_characters) {
return AXPlatformNodeWin::get_nCharacters(n_characters);
}
-STDMETHODIMP BrowserAccessibilityComWin::get_caretOffset(LONG* offset) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_caretOffset(LONG* offset) {
return AXPlatformNodeWin::get_caretOffset(offset);
}
-STDMETHODIMP BrowserAccessibilityComWin::get_characterExtents(
+IFACEMETHODIMP BrowserAccessibilityComWin::get_characterExtents(
LONG offset,
IA2CoordinateType coordinate_type,
LONG* out_x,
@@ -241,7 +241,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_characterExtents(
if (!out_x || !out_y || !out_width || !out_height)
return E_INVALIDARG;
- const base::string16& text_str = GetText();
+ const base::string16& text_str = GetTextAsString16();
HandleSpecialTextOffset(&offset);
if (offset < 0 || offset > static_cast<LONG>(text_str.size()))
return E_INVALIDARG;
@@ -267,20 +267,20 @@ STDMETHODIMP BrowserAccessibilityComWin::get_characterExtents(
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_nSelections(LONG* n_selections) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_nSelections(LONG* n_selections) {
return AXPlatformNodeWin::get_nSelections(n_selections);
}
-STDMETHODIMP BrowserAccessibilityComWin::get_selection(LONG selection_index,
- LONG* start_offset,
- LONG* end_offset) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_selection(LONG selection_index,
+ LONG* start_offset,
+ LONG* end_offset) {
return AXPlatformNodeWin::get_selection(selection_index, start_offset,
end_offset);
}
-STDMETHODIMP BrowserAccessibilityComWin::get_text(LONG start_offset,
- LONG end_offset,
- BSTR* text) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_text(LONG start_offset,
+ LONG end_offset,
+ BSTR* text) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_TEXT);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
if (!owner())
@@ -289,7 +289,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_text(LONG start_offset,
if (!text)
return E_INVALIDARG;
- const base::string16& text_str = GetText();
+ const base::string16& text_str = GetTextAsString16();
HandleSpecialTextOffset(&start_offset);
HandleSpecialTextOffset(&end_offset);
@@ -313,7 +313,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_text(LONG start_offset,
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_textAtOffset(
+IFACEMETHODIMP BrowserAccessibilityComWin::get_textAtOffset(
LONG offset,
IA2TextBoundaryType boundary_type,
LONG* start_offset,
@@ -336,7 +336,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_textAtOffset(
if (offset < 0)
return E_INVALIDARG;
- const base::string16& text_str = GetText();
+ const base::string16& text_str = GetTextAsString16();
LONG text_len = text_str.length();
if (offset > text_len)
return E_INVALIDARG;
@@ -361,7 +361,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_textAtOffset(
return get_text(start, end, text);
}
-STDMETHODIMP BrowserAccessibilityComWin::get_textBeforeOffset(
+IFACEMETHODIMP BrowserAccessibilityComWin::get_textBeforeOffset(
LONG offset,
IA2TextBoundaryType boundary_type,
LONG* start_offset,
@@ -380,7 +380,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_textBeforeOffset(
*end_offset = 0;
*text = NULL;
- const base::string16& text_str = GetText();
+ const base::string16& text_str = GetTextAsString16();
LONG text_len = text_str.length();
if (offset > text_len)
return E_INVALIDARG;
@@ -395,7 +395,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_textBeforeOffset(
return get_text(*start_offset, *end_offset, text);
}
-STDMETHODIMP BrowserAccessibilityComWin::get_textAfterOffset(
+IFACEMETHODIMP BrowserAccessibilityComWin::get_textAfterOffset(
LONG offset,
IA2TextBoundaryType boundary_type,
LONG* start_offset,
@@ -414,7 +414,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_textAfterOffset(
*end_offset = 0;
*text = NULL;
- const base::string16& text_str = GetText();
+ const base::string16& text_str = GetTextAsString16();
LONG text_len = text_str.length();
if (offset > text_len)
return E_INVALIDARG;
@@ -429,7 +429,8 @@ STDMETHODIMP BrowserAccessibilityComWin::get_textAfterOffset(
return get_text(*start_offset, *end_offset, text);
}
-STDMETHODIMP BrowserAccessibilityComWin::get_newText(IA2TextSegment* new_text) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_newText(
+ IA2TextSegment* new_text) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_NEW_TEXT);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
if (!owner())
@@ -441,19 +442,20 @@ STDMETHODIMP BrowserAccessibilityComWin::get_newText(IA2TextSegment* new_text) {
if (!old_win_attributes_)
return E_FAIL;
- int start, old_len, new_len;
+ size_t start, old_len, new_len;
ComputeHypertextRemovedAndInserted(&start, &old_len, &new_len);
if (new_len == 0)
return E_FAIL;
- base::string16 substr = GetText().substr(start, new_len);
+ base::string16 substr = GetTextAsString16().substr(start, new_len);
new_text->text = SysAllocString(substr.c_str());
- new_text->start = static_cast<long>(start);
- new_text->end = static_cast<long>(start + new_len);
+ new_text->start = static_cast<LONG>(start);
+ new_text->end = static_cast<LONG>(start + new_len);
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_oldText(IA2TextSegment* old_text) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_oldText(
+ IA2TextSegment* old_text) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_OLD_TEXT);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
if (!owner())
@@ -465,7 +467,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_oldText(IA2TextSegment* old_text) {
if (!old_win_attributes_)
return E_FAIL;
- int start, old_len, new_len;
+ size_t start, old_len, new_len;
ComputeHypertextRemovedAndInserted(&start, &old_len, &new_len);
if (old_len == 0)
return E_FAIL;
@@ -473,12 +475,12 @@ STDMETHODIMP BrowserAccessibilityComWin::get_oldText(IA2TextSegment* old_text) {
base::string16 old_hypertext = old_hypertext_.hypertext;
base::string16 substr = old_hypertext.substr(start, old_len);
old_text->text = SysAllocString(substr.c_str());
- old_text->start = static_cast<long>(start);
- old_text->end = static_cast<long>(start + old_len);
+ old_text->start = static_cast<LONG>(start);
+ old_text->end = static_cast<LONG>(start + old_len);
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_offsetAtPoint(
+IFACEMETHODIMP BrowserAccessibilityComWin::get_offsetAtPoint(
LONG x,
LONG y,
IA2CoordinateType coord_type,
@@ -499,7 +501,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_offsetAtPoint(
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::scrollSubstringTo(
+IFACEMETHODIMP BrowserAccessibilityComWin::scrollSubstringTo(
LONG start_index,
LONG end_index,
IA2ScrollType scroll_type) {
@@ -510,7 +512,7 @@ STDMETHODIMP BrowserAccessibilityComWin::scrollSubstringTo(
return scrollTo(scroll_type);
}
-STDMETHODIMP BrowserAccessibilityComWin::scrollSubstringToPoint(
+IFACEMETHODIMP BrowserAccessibilityComWin::scrollSubstringToPoint(
LONG start_index,
LONG end_index,
IA2CoordinateType coordinate_type,
@@ -535,16 +537,17 @@ STDMETHODIMP BrowserAccessibilityComWin::scrollSubstringToPoint(
return scrollToPoint(coordinate_type, x, y);
}
-STDMETHODIMP BrowserAccessibilityComWin::addSelection(LONG start_offset,
- LONG end_offset) {
+IFACEMETHODIMP BrowserAccessibilityComWin::addSelection(LONG start_offset,
+ LONG end_offset) {
return AXPlatformNodeWin::addSelection(start_offset, end_offset);
}
-STDMETHODIMP BrowserAccessibilityComWin::removeSelection(LONG selection_index) {
+IFACEMETHODIMP BrowserAccessibilityComWin::removeSelection(
+ LONG selection_index) {
return AXPlatformNodeWin::removeSelection(selection_index);
}
-STDMETHODIMP BrowserAccessibilityComWin::setCaretOffset(LONG offset) {
+IFACEMETHODIMP BrowserAccessibilityComWin::setCaretOffset(LONG offset) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_SET_CARET_OFFSET);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
if (!owner())
@@ -553,9 +556,9 @@ STDMETHODIMP BrowserAccessibilityComWin::setCaretOffset(LONG offset) {
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::setSelection(LONG selection_index,
- LONG start_offset,
- LONG end_offset) {
+IFACEMETHODIMP BrowserAccessibilityComWin::setSelection(LONG selection_index,
+ LONG start_offset,
+ LONG end_offset) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_SET_SELECTION);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
if (!owner())
@@ -566,10 +569,11 @@ STDMETHODIMP BrowserAccessibilityComWin::setSelection(LONG selection_index,
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_attributes(LONG offset,
- LONG* start_offset,
- LONG* end_offset,
- BSTR* text_attributes) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_attributes(
+ LONG offset,
+ LONG* start_offset,
+ LONG* end_offset,
+ BSTR* text_attributes) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_IATEXT_GET_ATTRIBUTES);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
if (!start_offset || !end_offset || !text_attributes)
@@ -580,7 +584,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_attributes(LONG offset,
if (!owner())
return E_FAIL;
- const base::string16 text = GetText();
+ const base::string16 text = GetTextAsString16();
HandleSpecialTextOffset(&offset);
if (offset < 0 || offset > static_cast<LONG>(text.size()))
return E_INVALIDARG;
@@ -608,8 +612,8 @@ STDMETHODIMP BrowserAccessibilityComWin::get_attributes(LONG offset,
// IAccessibleHypertext methods.
//
-STDMETHODIMP BrowserAccessibilityComWin::get_nHyperlinks(
- long* hyperlink_count) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_nHyperlinks(
+ LONG* hyperlink_count) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_N_HYPERLINKS);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
if (!owner())
@@ -622,8 +626,8 @@ STDMETHODIMP BrowserAccessibilityComWin::get_nHyperlinks(
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_hyperlink(
- long index,
+IFACEMETHODIMP BrowserAccessibilityComWin::get_hyperlink(
+ LONG index,
IAccessibleHyperlink** hyperlink) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_HYPERLINK);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
@@ -631,7 +635,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_hyperlink(
return E_FAIL;
if (!hyperlink || index < 0 ||
- index >= static_cast<long>(hypertext_.hyperlinks.size())) {
+ index >= static_cast<LONG>(hypertext_.hyperlinks.size())) {
return E_INVALIDARG;
}
@@ -645,9 +649,9 @@ STDMETHODIMP BrowserAccessibilityComWin::get_hyperlink(
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_hyperlinkIndex(
- long char_index,
- long* hyperlink_index) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_hyperlinkIndex(
+ LONG char_index,
+ LONG* hyperlink_index) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_HYPERLINK_INDEX);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
if (!owner())
@@ -656,7 +660,8 @@ STDMETHODIMP BrowserAccessibilityComWin::get_hyperlinkIndex(
if (!hyperlink_index)
return E_INVALIDARG;
- if (char_index < 0 || char_index >= static_cast<long>(GetText().size())) {
+ if (char_index < 0 ||
+ char_index >= static_cast<LONG>(GetTextAsString16().size())) {
return E_INVALIDARG;
}
@@ -676,8 +681,8 @@ STDMETHODIMP BrowserAccessibilityComWin::get_hyperlinkIndex(
//
// Currently, only text links are supported.
-STDMETHODIMP BrowserAccessibilityComWin::get_anchor(long index,
- VARIANT* anchor) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_anchor(LONG index,
+ VARIANT* anchor) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_ANCHOR);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
if (!owner() || !IsHyperlink())
@@ -687,7 +692,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_anchor(long index,
if (index != 0 || !anchor)
return E_INVALIDARG;
- BSTR ia2_hypertext = SysAllocString(GetText().c_str());
+ BSTR ia2_hypertext = SysAllocString(GetTextAsString16().c_str());
DCHECK(ia2_hypertext);
anchor->vt = VT_BSTR;
anchor->bstrVal = ia2_hypertext;
@@ -701,8 +706,8 @@ STDMETHODIMP BrowserAccessibilityComWin::get_anchor(long index,
}
// Currently, only text links are supported.
-STDMETHODIMP BrowserAccessibilityComWin::get_anchorTarget(
- long index,
+IFACEMETHODIMP BrowserAccessibilityComWin::get_anchorTarget(
+ LONG index,
VARIANT* anchor_target) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_ANCHOR_TARGET);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
@@ -732,7 +737,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_anchorTarget(
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_startIndex(long* index) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_startIndex(LONG* index) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_START_INDEX);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
if (!owner() || !IsHyperlink())
@@ -751,7 +756,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_startIndex(long* index) {
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_endIndex(long* index) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_endIndex(LONG* index) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_END_INDEX);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
LONG start_index;
@@ -762,7 +767,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_endIndex(long* index) {
}
// This method is deprecated in the IA2 Spec.
-STDMETHODIMP BrowserAccessibilityComWin::get_valid(boolean* valid) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_valid(boolean* valid) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_VALID);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
return E_NOTIMPL;
@@ -772,7 +777,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_valid(boolean* valid) {
// IAccessibleAction partly implemented.
//
-STDMETHODIMP BrowserAccessibilityComWin::nActions(long* n_actions) {
+IFACEMETHODIMP BrowserAccessibilityComWin::nActions(LONG* n_actions) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_N_ACTIONS);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
if (!owner())
@@ -794,7 +799,7 @@ STDMETHODIMP BrowserAccessibilityComWin::nActions(long* n_actions) {
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::doAction(long action_index) {
+IFACEMETHODIMP BrowserAccessibilityComWin::doAction(LONG action_index) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_DO_ACTION);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
if (!owner())
@@ -808,25 +813,25 @@ STDMETHODIMP BrowserAccessibilityComWin::doAction(long action_index) {
return S_OK;
}
-STDMETHODIMP
-BrowserAccessibilityComWin::get_description(long action_index,
+IFACEMETHODIMP
+BrowserAccessibilityComWin::get_description(LONG action_index,
BSTR* description) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_IAACTION_GET_DESCRIPTION);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
return E_NOTIMPL;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_keyBinding(long action_index,
- long n_max_bindings,
- BSTR** key_bindings,
- long* n_bindings) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_keyBinding(LONG action_index,
+ LONG n_max_bindings,
+ BSTR** key_bindings,
+ LONG* n_bindings) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_KEY_BINDING);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
return E_NOTIMPL;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_name(long action_index,
- BSTR* name) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_name(LONG action_index,
+ BSTR* name) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_NAME);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
if (!owner())
@@ -855,8 +860,8 @@ STDMETHODIMP BrowserAccessibilityComWin::get_name(long action_index,
return S_OK;
}
-STDMETHODIMP
-BrowserAccessibilityComWin::get_localizedName(long action_index,
+IFACEMETHODIMP
+BrowserAccessibilityComWin::get_localizedName(LONG action_index,
BSTR* localized_name) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_LOCALIZED_NAME);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
@@ -890,7 +895,7 @@ BrowserAccessibilityComWin::get_localizedName(long action_index,
// IAccessibleValue methods.
//
-STDMETHODIMP BrowserAccessibilityComWin::get_currentValue(VARIANT* value) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_currentValue(VARIANT* value) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_CURRENT_VALUE);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
if (!owner())
@@ -911,7 +916,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_currentValue(VARIANT* value) {
return S_FALSE;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_minimumValue(VARIANT* value) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_minimumValue(VARIANT* value) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_MINIMUM_VALUE);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
if (!owner())
@@ -932,7 +937,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_minimumValue(VARIANT* value) {
return S_FALSE;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_maximumValue(VARIANT* value) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_maximumValue(VARIANT* value) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_MAXIMUM_VALUE);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
if (!owner())
@@ -953,7 +958,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_maximumValue(VARIANT* value) {
return S_FALSE;
}
-STDMETHODIMP BrowserAccessibilityComWin::setCurrentValue(VARIANT new_value) {
+IFACEMETHODIMP BrowserAccessibilityComWin::setCurrentValue(VARIANT new_value) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_SET_CURRENT_VALUE);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
// TODO(dmazzoni): Implement this.
@@ -964,7 +969,7 @@ STDMETHODIMP BrowserAccessibilityComWin::setCurrentValue(VARIANT new_value) {
// ISimpleDOMDocument methods.
//
-STDMETHODIMP BrowserAccessibilityComWin::get_URL(BSTR* url) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_URL(BSTR* url) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_URL);
if (!owner())
return E_FAIL;
@@ -989,7 +994,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_URL(BSTR* url) {
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_title(BSTR* title) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_title(BSTR* title) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_TITLE);
if (!owner())
return E_FAIL;
@@ -1011,7 +1016,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_title(BSTR* title) {
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_mimeType(BSTR* mime_type) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_mimeType(BSTR* mime_type) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_MIME_TYPE);
if (!owner())
return E_FAIL;
@@ -1033,7 +1038,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_mimeType(BSTR* mime_type) {
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_docType(BSTR* doc_type) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_docType(BSTR* doc_type) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_DOC_TYPE);
if (!owner())
return E_FAIL;
@@ -1055,14 +1060,14 @@ STDMETHODIMP BrowserAccessibilityComWin::get_docType(BSTR* doc_type) {
return S_OK;
}
-STDMETHODIMP
+IFACEMETHODIMP
BrowserAccessibilityComWin::get_nameSpaceURIForID(short name_space_id,
BSTR* name_space_uri) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_NAMESPACE_URI_FOR_ID);
return E_NOTIMPL;
}
-STDMETHODIMP
+IFACEMETHODIMP
BrowserAccessibilityComWin::put_alternateViewMediaTypes(
BSTR* comma_separated_media_types) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_PUT_ALTERNATE_VIEW_MEDIA_TYPES);
@@ -1073,7 +1078,7 @@ BrowserAccessibilityComWin::put_alternateViewMediaTypes(
// ISimpleDOMNode methods.
//
-STDMETHODIMP BrowserAccessibilityComWin::get_nodeInfo(
+IFACEMETHODIMP BrowserAccessibilityComWin::get_nodeInfo(
BSTR* node_name,
short* name_space_id,
BSTR* node_value,
@@ -1112,7 +1117,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_nodeInfo(
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_attributes(
+IFACEMETHODIMP BrowserAccessibilityComWin::get_attributes(
unsigned short max_attribs,
BSTR* attrib_names,
short* name_space_id,
@@ -1140,7 +1145,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_attributes(
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_attributesForNames(
+IFACEMETHODIMP BrowserAccessibilityComWin::get_attributesForNames(
unsigned short num_attribs,
BSTR* attrib_names,
short* name_space_id,
@@ -1172,7 +1177,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_attributesForNames(
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_computedStyle(
+IFACEMETHODIMP BrowserAccessibilityComWin::get_computedStyle(
unsigned short max_style_properties,
boolean use_alternate_view,
BSTR* style_properties,
@@ -1203,7 +1208,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_computedStyle(
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_computedStyleForProperties(
+IFACEMETHODIMP BrowserAccessibilityComWin::get_computedStyleForProperties(
unsigned short num_style_properties,
boolean use_alternate_view,
BSTR* style_properties,
@@ -1233,13 +1238,14 @@ STDMETHODIMP BrowserAccessibilityComWin::get_computedStyleForProperties(
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::scrollTo(boolean placeTopLeft) {
+IFACEMETHODIMP BrowserAccessibilityComWin::scrollTo(boolean placeTopLeft) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_ISIMPLEDOMNODE_SCROLL_TO);
return scrollTo(placeTopLeft ? IA2_SCROLL_TYPE_TOP_LEFT
: IA2_SCROLL_TYPE_ANYWHERE);
}
-STDMETHODIMP BrowserAccessibilityComWin::get_parentNode(ISimpleDOMNode** node) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_parentNode(
+ ISimpleDOMNode** node) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_PARENT_NODE);
if (!owner())
return E_FAIL;
@@ -1252,7 +1258,8 @@ STDMETHODIMP BrowserAccessibilityComWin::get_parentNode(ISimpleDOMNode** node) {
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_firstChild(ISimpleDOMNode** node) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_firstChild(
+ ISimpleDOMNode** node) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_FIRST_CHILD);
if (!owner())
return E_FAIL;
@@ -1270,7 +1277,8 @@ STDMETHODIMP BrowserAccessibilityComWin::get_firstChild(ISimpleDOMNode** node) {
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_lastChild(ISimpleDOMNode** node) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_lastChild(
+ ISimpleDOMNode** node) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_LAST_CHILD);
if (!owner())
return E_FAIL;
@@ -1289,7 +1297,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_lastChild(ISimpleDOMNode** node) {
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_previousSibling(
+IFACEMETHODIMP BrowserAccessibilityComWin::get_previousSibling(
ISimpleDOMNode** node) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_PREVIOUS_SIBLING);
if (!owner())
@@ -1310,7 +1318,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_previousSibling(
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_nextSibling(
+IFACEMETHODIMP BrowserAccessibilityComWin::get_nextSibling(
ISimpleDOMNode** node) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_NEXT_SIBLING);
if (!owner())
@@ -1334,8 +1342,8 @@ STDMETHODIMP BrowserAccessibilityComWin::get_nextSibling(
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_childAt(unsigned int child_index,
- ISimpleDOMNode** node) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_childAt(unsigned int child_index,
+ ISimpleDOMNode** node) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_CHILD_AT);
if (!owner())
return E_FAIL;
@@ -1357,7 +1365,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_childAt(unsigned int child_index,
}
// We only support this method for retrieving MathML content.
-STDMETHODIMP BrowserAccessibilityComWin::get_innerHTML(BSTR* innerHTML) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_innerHTML(BSTR* innerHTML) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_INNER_HTML);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
if (!owner())
@@ -1372,14 +1380,14 @@ STDMETHODIMP BrowserAccessibilityComWin::get_innerHTML(BSTR* innerHTML) {
return S_OK;
}
-STDMETHODIMP
+IFACEMETHODIMP
BrowserAccessibilityComWin::get_localInterface(void** local_interface) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_LOCAL_INTERFACE);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
return E_NOTIMPL;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_language(BSTR* language) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_language(BSTR* language) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_LANGUAGE);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
if (!language)
@@ -1403,7 +1411,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_language(BSTR* language) {
// ISimpleDOMText methods.
//
-STDMETHODIMP BrowserAccessibilityComWin::get_domText(BSTR* dom_text) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_domText(BSTR* dom_text) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_DOM_TEXT);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
if (!owner())
@@ -1415,7 +1423,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_domText(BSTR* dom_text) {
return GetStringAttributeAsBstr(ax::mojom::StringAttribute::kName, dom_text);
}
-STDMETHODIMP BrowserAccessibilityComWin::get_clippedSubstringBounds(
+IFACEMETHODIMP BrowserAccessibilityComWin::get_clippedSubstringBounds(
unsigned int start_index,
unsigned int end_index,
int* out_x,
@@ -1431,7 +1439,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_clippedSubstringBounds(
out_width, out_height);
}
-STDMETHODIMP BrowserAccessibilityComWin::get_unclippedSubstringBounds(
+IFACEMETHODIMP BrowserAccessibilityComWin::get_unclippedSubstringBounds(
unsigned int start_index,
unsigned int end_index,
int* out_x,
@@ -1447,7 +1455,8 @@ STDMETHODIMP BrowserAccessibilityComWin::get_unclippedSubstringBounds(
if (!out_x || !out_y || !out_width || !out_height)
return E_INVALIDARG;
- unsigned int text_length = static_cast<unsigned int>(GetText().size());
+ unsigned int text_length =
+ static_cast<unsigned int>(GetTextAsString16().size());
if (start_index > text_length || end_index > text_length ||
start_index > end_index) {
return E_INVALIDARG;
@@ -1462,7 +1471,7 @@ STDMETHODIMP BrowserAccessibilityComWin::get_unclippedSubstringBounds(
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::scrollToSubstring(
+IFACEMETHODIMP BrowserAccessibilityComWin::scrollToSubstring(
unsigned int start_index,
unsigned int end_index) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_SCROLL_TO_SUBSTRING);
@@ -1475,7 +1484,8 @@ STDMETHODIMP BrowserAccessibilityComWin::scrollToSubstring(
if (!manager)
return E_FAIL;
- unsigned int text_length = static_cast<unsigned int>(GetText().size());
+ unsigned int text_length =
+ static_cast<unsigned int>(GetTextAsString16().size());
if (start_index > text_length || end_index > text_length ||
start_index > end_index) {
return E_INVALIDARG;
@@ -1488,7 +1498,7 @@ STDMETHODIMP BrowserAccessibilityComWin::scrollToSubstring(
return S_OK;
}
-STDMETHODIMP BrowserAccessibilityComWin::get_fontFamily(BSTR* font_family) {
+IFACEMETHODIMP BrowserAccessibilityComWin::get_fontFamily(BSTR* font_family) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_FONT_FAMILY);
AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes);
if (!font_family)
@@ -1512,9 +1522,9 @@ STDMETHODIMP BrowserAccessibilityComWin::get_fontFamily(BSTR* font_family) {
// IServiceProvider methods.
//
-STDMETHODIMP BrowserAccessibilityComWin::QueryService(REFGUID guid_service,
- REFIID riid,
- void** object) {
+IFACEMETHODIMP BrowserAccessibilityComWin::QueryService(REFGUID guid_service,
+ REFIID riid,
+ void** object) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_QUERY_SERVICE);
if (!owner())
return E_FAIL;
@@ -1556,7 +1566,7 @@ STDMETHODIMP BrowserAccessibilityComWin::QueryService(REFGUID guid_service,
//
// static
-HRESULT WINAPI BrowserAccessibilityComWin::InternalQueryInterface(
+STDMETHODIMP BrowserAccessibilityComWin::InternalQueryInterface(
void* this_ptr,
const _ATL_INTMAP_ENTRY* entries,
REFIID iid,
@@ -1648,7 +1658,7 @@ void BrowserAccessibilityComWin::ComputeStylesIfNeeded() {
child->GetSpellingAttributes();
MergeSpellingIntoTextAttributes(spelling_attributes, start_offset,
&attributes_map);
- start_offset += child->GetText().length();
+ start_offset += child->GetTextAsString16().length();
} else {
start_offset += 1;
}
@@ -1790,7 +1800,7 @@ void BrowserAccessibilityComWin::UpdateStep3FireEvents(
// they are providing redundant information and will lead to duplicate
// announcements.
if (!did_fire_namechange) {
- int start, old_len, new_len;
+ size_t start, old_len, new_len;
ComputeHypertextRemovedAndInserted(&start, &old_len, &new_len);
if (old_len > 0) {
// In-process screen readers may call IAccessibleText::get_oldText
@@ -2068,7 +2078,8 @@ BrowserAccessibilityComWin::GetSpellingAttributes() {
spelling_attributes[start_offset + attribute.first] =
std::move(attribute.second);
}
- start_offset += static_cast<int>(text_win->GetText().length());
+ start_offset +=
+ static_cast<int>(text_win->GetTextAsString16().length());
}
}
}
@@ -2242,14 +2253,14 @@ LONG BrowserAccessibilityComWin::FindBoundary(
// TODO(nektar): |AXPosition| can handle other types of boundaries as well.
ui::TextBoundaryType boundary = IA2TextBoundaryToTextBoundary(ia2_boundary);
return ui::FindAccessibleTextBoundary(
- GetText(), owner()->GetLineStartOffsets(), boundary, start_offset,
- direction, affinity);
+ GetTextAsString16(), owner()->GetLineStartOffsets(), boundary,
+ start_offset, direction, affinity);
}
LONG BrowserAccessibilityComWin::FindStartOfStyle(
LONG start_offset,
ui::TextBoundaryDirection direction) {
- LONG text_length = static_cast<LONG>(GetText().length());
+ LONG text_length = static_cast<LONG>(GetTextAsString16().length());
DCHECK_GE(start_offset, 0);
DCHECK_LE(start_offset, text_length);
diff --git a/chromium/content/browser/accessibility/browser_accessibility_com_win.h b/chromium/content/browser/accessibility/browser_accessibility_com_win.h
index 4ce9c39ccf7..775cbb6ccfd 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_com_win.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_com_win.h
@@ -5,8 +5,6 @@
#ifndef CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_COM_WIN_H_
#define CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_COM_WIN_H_
-#include <atlbase.h>
-#include <atlcom.h>
#include <oleacc.h>
#include <stddef.h>
#include <stdint.h>
@@ -15,6 +13,7 @@
#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
+#include "base/win/atl.h"
#include "content/browser/accessibility/browser_accessibility.h"
#include "content/browser/accessibility/browser_accessibility_win.h"
#include "content/common/content_export.h"
@@ -100,43 +99,45 @@ class __declspec(uuid("562072fe-3390-43b1-9e2c-dd4118f5ac79"))
//
// IAccessible2 methods.
//
- CONTENT_EXPORT STDMETHODIMP get_attributes(BSTR* attributes) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_attributes(BSTR* attributes) override;
- CONTENT_EXPORT STDMETHODIMP scrollTo(enum IA2ScrollType scroll_type) override;
+ CONTENT_EXPORT IFACEMETHODIMP
+ scrollTo(enum IA2ScrollType scroll_type) override;
//
// IAccessibleApplication methods.
//
- CONTENT_EXPORT STDMETHODIMP get_appName(BSTR* app_name) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_appName(BSTR* app_name) override;
- CONTENT_EXPORT STDMETHODIMP get_appVersion(BSTR* app_version) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_appVersion(BSTR* app_version) override;
- CONTENT_EXPORT STDMETHODIMP get_toolkitName(BSTR* toolkit_name) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_toolkitName(BSTR* toolkit_name) override;
- CONTENT_EXPORT STDMETHODIMP
+ CONTENT_EXPORT IFACEMETHODIMP
get_toolkitVersion(BSTR* toolkit_version) override;
//
// IAccessibleImage methods.
//
- CONTENT_EXPORT STDMETHODIMP get_description(BSTR* description) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_description(BSTR* description) override;
- CONTENT_EXPORT STDMETHODIMP
+ CONTENT_EXPORT IFACEMETHODIMP
get_imagePosition(enum IA2CoordinateType coordinate_type,
LONG* x,
LONG* y) override;
- CONTENT_EXPORT STDMETHODIMP get_imageSize(LONG* height, LONG* width) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_imageSize(LONG* height,
+ LONG* width) override;
//
// IAccessibleText methods.
//
- CONTENT_EXPORT STDMETHODIMP get_nCharacters(LONG* n_characters) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_nCharacters(LONG* n_characters) override;
- CONTENT_EXPORT STDMETHODIMP get_caretOffset(LONG* offset) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_caretOffset(LONG* offset) override;
- CONTENT_EXPORT STDMETHODIMP
+ CONTENT_EXPORT IFACEMETHODIMP
get_characterExtents(LONG offset,
enum IA2CoordinateType coord_type,
LONG* out_x,
@@ -144,206 +145,209 @@ class __declspec(uuid("562072fe-3390-43b1-9e2c-dd4118f5ac79"))
LONG* out_width,
LONG* out_height) override;
- CONTENT_EXPORT STDMETHODIMP get_nSelections(LONG* n_selections) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_nSelections(LONG* n_selections) override;
- CONTENT_EXPORT STDMETHODIMP get_selection(LONG selection_index,
- LONG* start_offset,
- LONG* end_offset) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_selection(LONG selection_index,
+ LONG* start_offset,
+ LONG* end_offset) override;
- CONTENT_EXPORT STDMETHODIMP get_text(LONG start_offset,
- LONG end_offset,
- BSTR* text) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_text(LONG start_offset,
+ LONG end_offset,
+ BSTR* text) override;
- CONTENT_EXPORT STDMETHODIMP
+ CONTENT_EXPORT IFACEMETHODIMP
get_textAtOffset(LONG offset,
enum IA2TextBoundaryType boundary_type,
LONG* start_offset,
LONG* end_offset,
BSTR* text) override;
- CONTENT_EXPORT STDMETHODIMP
+ CONTENT_EXPORT IFACEMETHODIMP
get_textBeforeOffset(LONG offset,
enum IA2TextBoundaryType boundary_type,
LONG* start_offset,
LONG* end_offset,
BSTR* text) override;
- CONTENT_EXPORT STDMETHODIMP
+ CONTENT_EXPORT IFACEMETHODIMP
get_textAfterOffset(LONG offset,
enum IA2TextBoundaryType boundary_type,
LONG* start_offset,
LONG* end_offset,
BSTR* text) override;
- CONTENT_EXPORT STDMETHODIMP get_newText(IA2TextSegment* new_text) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_newText(IA2TextSegment* new_text) override;
- CONTENT_EXPORT STDMETHODIMP get_oldText(IA2TextSegment* old_text) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_oldText(IA2TextSegment* old_text) override;
- CONTENT_EXPORT STDMETHODIMP
+ CONTENT_EXPORT IFACEMETHODIMP
get_offsetAtPoint(LONG x,
LONG y,
enum IA2CoordinateType coord_type,
LONG* offset) override;
- CONTENT_EXPORT STDMETHODIMP
+ CONTENT_EXPORT IFACEMETHODIMP
scrollSubstringTo(LONG start_index,
LONG end_index,
enum IA2ScrollType scroll_type) override;
- CONTENT_EXPORT STDMETHODIMP
+ CONTENT_EXPORT IFACEMETHODIMP
scrollSubstringToPoint(LONG start_index,
LONG end_index,
enum IA2CoordinateType coordinate_type,
LONG x,
LONG y) override;
- CONTENT_EXPORT STDMETHODIMP addSelection(LONG start_offset,
- LONG end_offset) override;
+ CONTENT_EXPORT IFACEMETHODIMP addSelection(LONG start_offset,
+ LONG end_offset) override;
- CONTENT_EXPORT STDMETHODIMP removeSelection(LONG selection_index) override;
+ CONTENT_EXPORT IFACEMETHODIMP removeSelection(LONG selection_index) override;
- CONTENT_EXPORT STDMETHODIMP setCaretOffset(LONG offset) override;
+ CONTENT_EXPORT IFACEMETHODIMP setCaretOffset(LONG offset) override;
- CONTENT_EXPORT STDMETHODIMP setSelection(LONG selection_index,
- LONG start_offset,
- LONG end_offset) override;
+ CONTENT_EXPORT IFACEMETHODIMP setSelection(LONG selection_index,
+ LONG start_offset,
+ LONG end_offset) override;
// IAccessibleText methods not implemented.
- CONTENT_EXPORT STDMETHODIMP get_attributes(LONG offset,
- LONG* start_offset,
- LONG* end_offset,
- BSTR* text_attributes) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_attributes(LONG offset,
+ LONG* start_offset,
+ LONG* end_offset,
+ BSTR* text_attributes) override;
//
// IAccessibleHypertext methods.
//
- CONTENT_EXPORT STDMETHODIMP get_nHyperlinks(long* hyperlink_count) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_nHyperlinks(LONG* hyperlink_count) override;
- CONTENT_EXPORT STDMETHODIMP
- get_hyperlink(long index, IAccessibleHyperlink** hyperlink) override;
+ CONTENT_EXPORT IFACEMETHODIMP
+ get_hyperlink(LONG index, IAccessibleHyperlink** hyperlink) override;
- CONTENT_EXPORT STDMETHODIMP
- get_hyperlinkIndex(long char_index, long* hyperlink_index) override;
+ CONTENT_EXPORT IFACEMETHODIMP
+ get_hyperlinkIndex(LONG char_index, LONG* hyperlink_index) override;
// IAccessibleHyperlink methods.
- CONTENT_EXPORT STDMETHODIMP get_anchor(long index, VARIANT* anchor) override;
- CONTENT_EXPORT STDMETHODIMP get_anchorTarget(long index,
- VARIANT* anchor_target) override;
- CONTENT_EXPORT STDMETHODIMP get_startIndex(long* index) override;
- CONTENT_EXPORT STDMETHODIMP get_endIndex(long* index) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_anchor(LONG index,
+ VARIANT* anchor) override;
+ CONTENT_EXPORT IFACEMETHODIMP
+ get_anchorTarget(LONG index, VARIANT* anchor_target) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_startIndex(LONG* index) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_endIndex(LONG* index) override;
// This method is deprecated in the IA2 Spec and so we don't implement it.
- CONTENT_EXPORT STDMETHODIMP get_valid(boolean* valid) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_valid(boolean* valid) override;
// IAccessibleAction mostly not implemented.
- CONTENT_EXPORT STDMETHODIMP nActions(long* n_actions) override;
- CONTENT_EXPORT STDMETHODIMP doAction(long action_index) override;
- CONTENT_EXPORT STDMETHODIMP get_description(long action_index,
- BSTR* description) override;
- CONTENT_EXPORT STDMETHODIMP get_keyBinding(long action_index,
- long n_max_bindings,
- BSTR** key_bindings,
- long* n_bindings) override;
- CONTENT_EXPORT STDMETHODIMP get_name(long action_index, BSTR* name) override;
- CONTENT_EXPORT STDMETHODIMP get_localizedName(long action_index,
- BSTR* localized_name) override;
+ CONTENT_EXPORT IFACEMETHODIMP nActions(LONG* n_actions) override;
+ CONTENT_EXPORT IFACEMETHODIMP doAction(LONG action_index) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_description(LONG action_index,
+ BSTR* description) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_keyBinding(LONG action_index,
+ LONG n_max_bindings,
+ BSTR** key_bindings,
+ LONG* n_bindings) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_name(LONG action_index,
+ BSTR* name) override;
+ CONTENT_EXPORT IFACEMETHODIMP
+ get_localizedName(LONG action_index, BSTR* localized_name) override;
//
// IAccessibleValue methods.
//
- CONTENT_EXPORT STDMETHODIMP get_currentValue(VARIANT* value) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_currentValue(VARIANT* value) override;
- CONTENT_EXPORT STDMETHODIMP get_minimumValue(VARIANT* value) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_minimumValue(VARIANT* value) override;
- CONTENT_EXPORT STDMETHODIMP get_maximumValue(VARIANT* value) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_maximumValue(VARIANT* value) override;
- CONTENT_EXPORT STDMETHODIMP setCurrentValue(VARIANT new_value) override;
+ CONTENT_EXPORT IFACEMETHODIMP setCurrentValue(VARIANT new_value) override;
//
// ISimpleDOMDocument methods.
//
- CONTENT_EXPORT STDMETHODIMP get_URL(BSTR* url) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_URL(BSTR* url) override;
- CONTENT_EXPORT STDMETHODIMP get_title(BSTR* title) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_title(BSTR* title) override;
- CONTENT_EXPORT STDMETHODIMP get_mimeType(BSTR* mime_type) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_mimeType(BSTR* mime_type) override;
- CONTENT_EXPORT STDMETHODIMP get_docType(BSTR* doc_type) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_docType(BSTR* doc_type) override;
- CONTENT_EXPORT STDMETHODIMP
+ CONTENT_EXPORT IFACEMETHODIMP
get_nameSpaceURIForID(short name_space_id, BSTR* name_space_uri) override;
- CONTENT_EXPORT STDMETHODIMP
+ CONTENT_EXPORT IFACEMETHODIMP
put_alternateViewMediaTypes(BSTR* comma_separated_media_types) override;
//
// ISimpleDOMNode methods.
//
- CONTENT_EXPORT STDMETHODIMP get_nodeInfo(BSTR* node_name,
- short* name_space_id,
- BSTR* node_value,
- unsigned int* num_children,
- unsigned int* unique_id,
- unsigned short* node_type) override;
+ CONTENT_EXPORT IFACEMETHODIMP
+ get_nodeInfo(BSTR* node_name,
+ short* name_space_id,
+ BSTR* node_value,
+ unsigned int* num_children,
+ unsigned int* unique_id,
+ unsigned short* node_type) override;
- CONTENT_EXPORT STDMETHODIMP
+ CONTENT_EXPORT IFACEMETHODIMP
get_attributes(unsigned short max_attribs,
BSTR* attrib_names,
short* name_space_id,
BSTR* attrib_values,
unsigned short* num_attribs) override;
- CONTENT_EXPORT STDMETHODIMP
+ CONTENT_EXPORT IFACEMETHODIMP
get_attributesForNames(unsigned short num_attribs,
BSTR* attrib_names,
short* name_space_id,
BSTR* attrib_values) override;
- CONTENT_EXPORT STDMETHODIMP
+ CONTENT_EXPORT IFACEMETHODIMP
get_computedStyle(unsigned short max_style_properties,
boolean use_alternate_view,
BSTR* style_properties,
BSTR* style_values,
unsigned short* num_style_properties) override;
- CONTENT_EXPORT STDMETHODIMP
+ CONTENT_EXPORT IFACEMETHODIMP
get_computedStyleForProperties(unsigned short num_style_properties,
boolean use_alternate_view,
BSTR* style_properties,
BSTR* style_values) override;
- CONTENT_EXPORT STDMETHODIMP scrollTo(boolean placeTopLeft) override;
+ CONTENT_EXPORT IFACEMETHODIMP scrollTo(boolean placeTopLeft) override;
- CONTENT_EXPORT STDMETHODIMP get_parentNode(ISimpleDOMNode** node) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_parentNode(ISimpleDOMNode** node) override;
- CONTENT_EXPORT STDMETHODIMP get_firstChild(ISimpleDOMNode** node) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_firstChild(ISimpleDOMNode** node) override;
- CONTENT_EXPORT STDMETHODIMP get_lastChild(ISimpleDOMNode** node) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_lastChild(ISimpleDOMNode** node) override;
- CONTENT_EXPORT STDMETHODIMP
+ CONTENT_EXPORT IFACEMETHODIMP
get_previousSibling(ISimpleDOMNode** node) override;
- CONTENT_EXPORT STDMETHODIMP get_nextSibling(ISimpleDOMNode** node) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_nextSibling(ISimpleDOMNode** node) override;
- CONTENT_EXPORT STDMETHODIMP get_childAt(unsigned int child_index,
- ISimpleDOMNode** node) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_childAt(unsigned int child_index,
+ ISimpleDOMNode** node) override;
- CONTENT_EXPORT STDMETHODIMP get_innerHTML(BSTR* innerHTML) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_innerHTML(BSTR* innerHTML) override;
- CONTENT_EXPORT STDMETHODIMP
+ CONTENT_EXPORT IFACEMETHODIMP
get_localInterface(void** local_interface) override;
- CONTENT_EXPORT STDMETHODIMP get_language(BSTR* language) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_language(BSTR* language) override;
//
// ISimpleDOMText methods.
//
- CONTENT_EXPORT STDMETHODIMP get_domText(BSTR* dom_text) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_domText(BSTR* dom_text) override;
- CONTENT_EXPORT STDMETHODIMP
+ CONTENT_EXPORT IFACEMETHODIMP
get_clippedSubstringBounds(unsigned int start_index,
unsigned int end_index,
int* out_x,
@@ -351,7 +355,7 @@ class __declspec(uuid("562072fe-3390-43b1-9e2c-dd4118f5ac79"))
int* out_width,
int* out_height) override;
- CONTENT_EXPORT STDMETHODIMP
+ CONTENT_EXPORT IFACEMETHODIMP
get_unclippedSubstringBounds(unsigned int start_index,
unsigned int end_index,
int* out_x,
@@ -359,25 +363,25 @@ class __declspec(uuid("562072fe-3390-43b1-9e2c-dd4118f5ac79"))
int* out_width,
int* out_height) override;
- CONTENT_EXPORT STDMETHODIMP
+ CONTENT_EXPORT IFACEMETHODIMP
scrollToSubstring(unsigned int start_index, unsigned int end_index) override;
- CONTENT_EXPORT STDMETHODIMP get_fontFamily(BSTR* font_family) override;
+ CONTENT_EXPORT IFACEMETHODIMP get_fontFamily(BSTR* font_family) override;
//
// IServiceProvider methods.
//
- CONTENT_EXPORT STDMETHODIMP QueryService(REFGUID guidService,
- REFIID riid,
- void** object) override;
+ CONTENT_EXPORT IFACEMETHODIMP QueryService(REFGUID guidService,
+ REFIID riid,
+ void** object) override;
//
// CComObjectRootEx methods.
//
// Called by BEGIN_COM_MAP() / END_COM_MAP().
- static CONTENT_EXPORT HRESULT WINAPI
+ static CONTENT_EXPORT STDMETHODIMP
InternalQueryInterface(void* this_ptr,
const _ATL_INTMAP_ENTRY* entries,
REFIID iid,
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager.cc b/chromium/content/browser/accessibility/browser_accessibility_manager.cc
index 2cfe76080a1..3ab440e85ad 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager.cc
@@ -20,27 +20,6 @@ namespace content {
namespace {
-// Search the tree recursively from |node| and return any node that has
-// a child tree ID of |ax_tree_id|.
-BrowserAccessibility* FindNodeWithChildTreeId(BrowserAccessibility* node,
- int ax_tree_id) {
- if (!node)
- return nullptr;
-
- if (node->GetIntAttribute(ax::mojom::IntAttribute::kChildTreeId) ==
- ax_tree_id)
- return node;
-
- for (unsigned int i = 0; i < node->InternalChildCount(); ++i) {
- BrowserAccessibility* child = node->InternalGetChild(i);
- BrowserAccessibility* result = FindNodeWithChildTreeId(child, ax_tree_id);
- if (result)
- return result;
- }
-
- return nullptr;
-}
-
// Map from AXTreeID to BrowserAccessibilityManager
using AXTreeIDMap = base::hash_map<ui::AXTreeIDRegistry::AXTreeID,
BrowserAccessibilityManager*>;
@@ -145,7 +124,6 @@ BrowserAccessibilityManager::BrowserAccessibilityManager(
last_focused_manager_(nullptr),
connected_to_parent_tree_node_(false),
ax_tree_id_(ui::AXTreeIDRegistry::kNoAXTreeID),
- parent_node_id_from_parent_tree_(0),
device_scale_factor_(1.0f),
use_custom_device_scale_factor_for_testing_(false) {
SetTree(tree_.get());
@@ -163,7 +141,6 @@ BrowserAccessibilityManager::BrowserAccessibilityManager(
last_focused_node_(nullptr),
last_focused_manager_(nullptr),
ax_tree_id_(ui::AXTreeIDRegistry::kNoAXTreeID),
- parent_node_id_from_parent_tree_(0),
device_scale_factor_(1.0f),
use_custom_device_scale_factor_for_testing_(false) {
SetTree(tree_.get());
@@ -286,27 +263,23 @@ BrowserAccessibilityManager::GetParentNodeFromParentTree() {
if (!parent_manager)
return nullptr;
- // Try to use the cached parent node from the most recent time this
- // was called.
- if (parent_node_id_from_parent_tree_) {
- BrowserAccessibility* parent_node = parent_manager->GetFromID(
- parent_node_id_from_parent_tree_);
+ std::set<int32_t> host_node_ids =
+ parent_manager->ax_tree()->GetNodeIdsForChildTreeId(ax_tree_id_);
+
+#if !defined(NDEBUG)
+ if (host_node_ids.size() > 1)
+ DLOG(WARNING) << "Multiple nodes claim the same child tree id.";
+#endif
+
+ for (int32_t host_node_id : host_node_ids) {
+ BrowserAccessibility* parent_node = parent_manager->GetFromID(host_node_id);
if (parent_node) {
- int parent_child_tree_id =
- parent_node->GetIntAttribute(ax::mojom::IntAttribute::kChildTreeId);
- if (parent_child_tree_id == ax_tree_id_)
- return parent_node;
+ DCHECK_EQ(ax_tree_id_, parent_node->GetIntAttribute(
+ ax::mojom::IntAttribute::kChildTreeId));
+ return parent_node;
}
}
- // If that fails, search for it and cache it for next time.
- BrowserAccessibility* parent_node = FindNodeWithChildTreeId(
- parent_manager->GetRoot(), ax_tree_id_);
- if (parent_node) {
- parent_node_id_from_parent_tree_ = parent_node->GetId();
- return parent_node;
- }
-
return nullptr;
}
@@ -493,11 +466,16 @@ BrowserAccessibility* BrowserAccessibilityManager::GetActiveDescendant(
if (focus->GetRole() == ax::mojom::Role::kPopUpButton) {
BrowserAccessibility* child = focus->InternalGetChild(0);
- if (child && child->GetRole() == ax::mojom::Role::kMenuListPopup) {
+ if (child && child->GetRole() == ax::mojom::Role::kMenuListPopup &&
+ !child->GetData().HasState(ax::mojom::State::kInvisible)) {
// The active descendant is found on the menu list popup, i.e. on the
// actual list and not on the button that opens it.
// If there is no active descendant, focus should stay on the button so
// that Windows screen readers would enable their virtual cursor.
+ // Do not expose an activedescendant in a hidden/collapsed list, as
+ // screen readers expect the focus event to go to the button itself.
+ // Note that the AX hierarchy in this case is strange -- the active
+ // option is the only visible option, and is inside an invisible list.
if (child->GetIntAttribute(ax::mojom::IntAttribute::kActivedescendantId,
&active_descendant_id)) {
active_descendant = child->manager()->GetFromID(active_descendant_id);
@@ -505,7 +483,8 @@ BrowserAccessibility* BrowserAccessibilityManager::GetActiveDescendant(
}
}
- if (active_descendant)
+ if (active_descendant &&
+ !active_descendant->GetData().HasState(ax::mojom::State::kInvisible))
return active_descendant;
return focus;
@@ -1101,32 +1080,6 @@ void BrowserAccessibilityManager::OnSubtreeWillBeDeleted(ui::AXTree* tree,
obj->OnSubtreeWillBeDeleted();
}
-void BrowserAccessibilityManager::OnNodeWillBeReparented(ui::AXTree* tree,
- ui::AXNode* node) {
- AXEventGenerator::OnNodeWillBeReparented(tree, node);
- // BrowserAccessibility should probably ask the tree source for the AXNode via
- // an id rather than weakly holding a pointer to a AXNode that might have been
- // destroyed under the hood and re-created later on. Treat this as a delete to
- // make things work.
- if (id_wrapper_map_.find(node->id()) == id_wrapper_map_.end())
- return;
- GetFromAXNode(node)->Destroy();
- id_wrapper_map_.erase(node->id());
-}
-
-void BrowserAccessibilityManager::OnSubtreeWillBeReparented(ui::AXTree* tree,
- ui::AXNode* node) {
- AXEventGenerator::OnSubtreeWillBeReparented(tree, node);
- // BrowserAccessibility should probably ask the tree source for the AXNode via
- // an id rather than weakly holding a pointer to a AXNode that might have been
- // destroyed under the hood and re-created later on. Treat this as a delete to
- // make things work.
- DCHECK(node);
- BrowserAccessibility* obj = GetFromAXNode(node);
- if (obj)
- obj->OnSubtreeWillBeDeleted();
-}
-
void BrowserAccessibilityManager::OnNodeCreated(ui::AXTree* tree,
ui::AXNode* node) {
AXEventGenerator::OnNodeCreated(tree, node);
@@ -1139,13 +1092,13 @@ void BrowserAccessibilityManager::OnNodeCreated(ui::AXTree* tree,
void BrowserAccessibilityManager::OnNodeReparented(ui::AXTree* tree,
ui::AXNode* node) {
AXEventGenerator::OnNodeReparented(tree, node);
- // BrowserAccessibility should probably ask the tree source for the AXNode via
- // an id rather than weakly holding a pointer to a AXNode that might have been
- // destroyed under the hood and re-created later on. Treat this as a create to
- // make things work.
- BrowserAccessibility* wrapper = factory_->Create();
+ BrowserAccessibility* wrapper = GetFromID(node->id());
+ if (!wrapper) {
+ wrapper = factory_->Create();
+ id_wrapper_map_[node->id()] = wrapper;
+ }
+
wrapper->Init(this, node);
- id_wrapper_map_[node->id()] = wrapper;
wrapper->OnDataChanged();
}
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager.h b/chromium/content/browser/accessibility/browser_accessibility_manager.h
index 6279fdbe5f5..397df50cb4b 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager.h
@@ -347,8 +347,6 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXEventGenerator {
// AXTreeDelegate implementation.
void OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
void OnSubtreeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
- void OnNodeWillBeReparented(ui::AXTree* tree, ui::AXNode* node) override;
- void OnSubtreeWillBeReparented(ui::AXTree* tree, ui::AXNode* node) override;
void OnNodeCreated(ui::AXTree* tree, ui::AXNode* node) override;
void OnNodeReparented(ui::AXTree* tree, ui::AXNode* node) override;
void OnNodeChanged(ui::AXTree* tree, ui::AXNode* node) override;
@@ -455,11 +453,6 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXEventGenerator {
// The global ID of this accessibility tree.
ui::AXTreeIDRegistry::AXTreeID ax_tree_id_;
- // If this tree has a parent tree, this is the cached ID of the parent
- // node within that parent tree. It's computed as needed and cached for
- // speed so that it can be accessed quickly if it hasn't changed.
- int parent_node_id_from_parent_tree_;
-
// The device scale factor for the view associated with this frame,
// cached each time there's any update to the accessibility tree.
float device_scale_factor_;
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_auralinux.cc b/chromium/content/browser/accessibility/browser_accessibility_manager_auralinux.cc
index f57d21a1195..1caa0621b77 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_auralinux.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_auralinux.cc
@@ -4,6 +4,8 @@
#include "content/browser/accessibility/browser_accessibility_manager_auralinux.h"
+#include <vector>
+
#include "content/browser/accessibility/browser_accessibility_auralinux.h"
#include "content/common/accessibility_messages.h"
#include "ui/accessibility/platform/ax_platform_node_auralinux.h"
@@ -72,4 +74,22 @@ void BrowserAccessibilityManagerAuraLinux::FireGeneratedEvent(
// Need to implement.
}
+void BrowserAccessibilityManagerAuraLinux::OnAtomicUpdateFinished(
+ ui::AXTree* tree,
+ bool root_changed,
+ const std::vector<ui::AXTreeDelegate::Change>& changes) {
+ BrowserAccessibilityManager::OnAtomicUpdateFinished(tree, root_changed,
+ changes);
+
+ // This is the second step in what will be a three step process mirroring that
+ // used in BrowserAccessibilityManagerWin.
+ for (const auto& change : changes) {
+ const ui::AXNode* changed_node = change.node;
+ DCHECK(changed_node);
+ BrowserAccessibility* obj = GetFromAXNode(changed_node);
+ if (obj && obj->IsNative())
+ ToBrowserAccessibilityAuraLinux(obj)->GetNode()->UpdateHypertext();
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_auralinux.h b/chromium/content/browser/accessibility/browser_accessibility_manager_auralinux.h
index c7537427ff1..7de682076c4 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_auralinux.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_auralinux.h
@@ -5,6 +5,8 @@
#ifndef CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_AURALINUX_H_
#define CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_AURALINUX_H_
+#include <vector>
+
#include "base/macros.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
@@ -34,6 +36,13 @@ class CONTENT_EXPORT BrowserAccessibilityManagerAuraLinux
AtkObject* parent_object() { return parent_object_; }
+ protected:
+ // AXTreeDelegate methods.
+ void OnAtomicUpdateFinished(
+ ui::AXTree* tree,
+ bool root_changed,
+ const std::vector<ui::AXTreeDelegate::Change>& changes) override;
+
private:
AtkObject* parent_object_;
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_mac.mm b/chromium/content/browser/accessibility/browser_accessibility_manager_mac.mm
index 8e32a082260..09cb7f8a55d 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_mac.mm
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_mac.mm
@@ -180,6 +180,16 @@ void BrowserAccessibilityManagerMac::FireBlinkEvent(
FireNativeMacNotification(mac_notification, node);
}
+void PostAnnouncementNotification(NSString* announcement) {
+ NSDictionary* notification_info = @{
+ NSAccessibilityAnnouncementKey : announcement,
+ NSAccessibilityPriorityKey : @(NSAccessibilityPriorityLow)
+ };
+ NSAccessibilityPostNotificationWithUserInfo(
+ [NSApp mainWindow], NSAccessibilityAnnouncementRequestedNotification,
+ notification_info);
+}
+
void BrowserAccessibilityManagerMac::FireGeneratedEvent(
AXEventGenerator::Event event_type,
BrowserAccessibility* node) {
@@ -313,6 +323,18 @@ void BrowserAccessibilityManagerMac::FireGeneratedEvent(
return;
}
+ if (base::mac::IsAtMostOS10_13()) {
+ // Use the announcement API to get around OS <= 10.13 VoiceOver bug
+ // where it stops announcing live regions after the first time focus
+ // leaves any content area.
+ // Unfortunately this produces an annoying boing sound with each live
+ // announcement, but the alternative is almost no live region support.
+ PostAnnouncementNotification(
+ base::SysUTF8ToNSString(node->GetLiveRegionText()));
+ return;
+ }
+
+ // Use native VoiceOver support for live regions.
base::scoped_nsobject<BrowserAccessibilityCocoa> retained_node(
[native_node retain]);
BrowserThread::PostDelayedTask(
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_win.cc b/chromium/content/browser/accessibility/browser_accessibility_manager_win.cc
index f6179284bb4..1a3eecf5de2 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_win.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_win.cc
@@ -179,10 +179,18 @@ void BrowserAccessibilityManagerWin::FireGeneratedEvent(
FireWinAccessibilityEvent(EVENT_OBJECT_REORDER, node);
break;
case Event::LIVE_REGION_CHANGED:
- // NVDA and JAWS are inconsistent about speaking this event in content.
- // Because of this, and because Firefox does not currently fire it, we
- // are avoiding this event for now.
- // FireWinAccessibilityEvent(EVENT_OBJECT_LIVEREGIONCHANGED, node);
+ // This event is redundant with the IA2_EVENT_TEXT_INSERTED events;
+ // however, JAWS 2018 and earlier do not process the text inserted
+ // events when "virtual cursor mode" is turned off (Insert+Z).
+ // Fortunately, firing the redudant event does not cause duplicate
+ // verbalizations in either screen reader.
+ // Future versions of JAWS may process the text inserted event when
+ // in focus mode, and so at some point the live region
+ // changed events may truly become redundant with the text inserted
+ // events. Note: Firefox does not fire this event, but JAWS processes
+ // Firefox live region events differently (utilizes MSAA's
+ // EVENT_OBJECT_SHOW).
+ FireWinAccessibilityEvent(EVENT_OBJECT_LIVEREGIONCHANGED, node);
break;
case Event::LOAD_COMPLETE:
FireWinAccessibilityEvent(IA2_EVENT_DOCUMENT_LOAD_COMPLETE, node);
@@ -197,7 +205,7 @@ void BrowserAccessibilityManagerWin::FireGeneratedEvent(
// Fire the event on the object where the focus of the selection is.
int32_t focus_id = GetTreeData().sel_focus_object_id;
BrowserAccessibility* focus_object = GetFromID(focus_id);
- if (focus_object)
+ if (focus_object && focus_object->HasVisibleCaretOrSelection())
FireWinAccessibilityEvent(IA2_EVENT_TEXT_CARET_MOVED, focus_object);
break;
}
diff --git a/chromium/content/browser/accessibility/browser_accessibility_state_impl.cc b/chromium/content/browser/accessibility/browser_accessibility_state_impl.cc
index 0c5ec83a271..15faf68df8a 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_state_impl.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_state_impl.cc
@@ -8,7 +8,7 @@
#include "base/command_line.h"
#include "base/metrics/histogram_macros.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "build/build_config.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
@@ -72,7 +72,7 @@ BrowserAccessibilityStateImpl::BrowserAccessibilityStateImpl()
// detected until after the user interacts in some way, so a reasonable delay
// gives us better numbers.
base::PostDelayedTaskWithTraits(
- FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
base::Bind(&BrowserAccessibilityStateImpl::UpdateHistograms, this),
base::TimeDelta::FromSeconds(ACCESSIBILITY_HISTOGRAM_DELAY_SECS));
#else
@@ -106,6 +106,11 @@ void BrowserAccessibilityStateImpl::DisableAccessibility() {
ResetAccessibilityMode();
}
+bool BrowserAccessibilityStateImpl::IsRendererAccessibilityEnabled() {
+ return !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableRendererAccessibility);
+}
+
void BrowserAccessibilityStateImpl::ResetAccessibilityModeValue() {
accessibility_mode_ = ui::AXMode();
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -120,7 +125,7 @@ void BrowserAccessibilityStateImpl::ResetAccessibilityMode() {
std::vector<WebContentsImpl*> web_contents_vector =
WebContentsImpl::GetAllWebContents();
for (size_t i = 0; i < web_contents_vector.size(); ++i)
- web_contents_vector[i]->SetAccessibilityMode(accessibility_mode());
+ web_contents_vector[i]->SetAccessibilityMode(accessibility_mode_);
}
bool BrowserAccessibilityStateImpl::IsAccessibleBrowser() {
@@ -157,6 +162,10 @@ void BrowserAccessibilityStateImpl::OnAXModeAdded(ui::AXMode mode) {
AddAccessibilityModeFlags(mode);
}
+ui::AXMode BrowserAccessibilityStateImpl::GetAccessibilityMode() const {
+ return accessibility_mode_;
+}
+
#if !defined(OS_WIN) && !defined(OS_MACOSX)
void BrowserAccessibilityStateImpl::UpdatePlatformSpecificHistograms() {
}
@@ -207,7 +216,7 @@ void BrowserAccessibilityStateImpl::RemoveAccessibilityModeFlags(
std::vector<WebContentsImpl*> web_contents_vector =
WebContentsImpl::GetAllWebContents();
for (size_t i = 0; i < web_contents_vector.size(); ++i)
- web_contents_vector[i]->SetAccessibilityMode(accessibility_mode());
+ web_contents_vector[i]->SetAccessibilityMode(accessibility_mode_);
}
} // namespace content
diff --git a/chromium/content/browser/accessibility/browser_accessibility_state_impl.h b/chromium/content/browser/accessibility/browser_accessibility_state_impl.h
index 1eb3033e6d8..9b57bbd68d8 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_state_impl.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_state_impl.h
@@ -44,6 +44,10 @@ class CONTENT_EXPORT BrowserAccessibilityStateImpl
void EnableAccessibility() override;
void DisableAccessibility() override;
+ bool IsRendererAccessibilityEnabled() override;
+ ui::AXMode GetAccessibilityMode() const override;
+ void AddAccessibilityModeFlags(ui::AXMode mode) override;
+ void RemoveAccessibilityModeFlags(ui::AXMode mode) override;
void ResetAccessibilityMode() override;
void OnScreenReaderDetected() override;
bool IsAccessibleBrowser() override;
@@ -54,16 +58,6 @@ class CONTENT_EXPORT BrowserAccessibilityStateImpl
// AXModeObserver
void OnAXModeAdded(ui::AXMode mode) override;
- ui::AXMode accessibility_mode() const { return accessibility_mode_; };
-
- // Adds the given accessibility mode flags to the current accessibility
- // mode bitmap.
- void AddAccessibilityModeFlags(ui::AXMode mode);
-
- // Remove the given accessibility mode flags from the current accessibility
- // mode bitmap.
- void RemoveAccessibilityModeFlags(ui::AXMode mode);
-
// Accessibility objects can have the "hot tracked" state set when
// the mouse is hovering over them, but this makes tests flaky because
// the test behaves differently when the mouse happens to be over an
diff --git a/chromium/content/browser/accessibility/browser_accessibility_win.cc b/chromium/content/browser/accessibility/browser_accessibility_win.cc
index 5b1585a981c..fbeb12c539e 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_win.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_win.cc
@@ -53,7 +53,7 @@ void BrowserAccessibilityWin::OnLocationChanged() {
}
base::string16 BrowserAccessibilityWin::GetText() const {
- return GetCOM()->AXPlatformNodeWin::GetText();
+ return GetCOM()->AXPlatformNodeWin::GetTextAsString16();
}
gfx::NativeViewAccessible BrowserAccessibilityWin::GetNativeViewAccessible() {
diff --git a/chromium/content/browser/accessibility/browser_accessibility_win.h b/chromium/content/browser/accessibility/browser_accessibility_win.h
index ec38830ef55..b8cf5cd5380 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_win.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_win.h
@@ -5,9 +5,7 @@
#ifndef CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_WIN_H_
#define CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_WIN_H_
-#include <atlbase.h>
-#include <atlcom.h>
-
+#include "base/win/atl.h"
#include "content/browser/accessibility/browser_accessibility.h"
#include "content/browser/accessibility/browser_accessibility_com_win.h"
#include "content/common/content_export.h"
diff --git a/chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc b/chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc
index 611d6959723..2950d2d28e4 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc
@@ -326,7 +326,7 @@ TEST_F(BrowserAccessibilityTest, TestTextBoundaries) {
ToBrowserAccessibilityWin(root_obj->PlatformGetChild(0))->GetCOM();
ASSERT_NE(nullptr, text_field_obj);
- long text_len;
+ LONG text_len;
EXPECT_EQ(S_OK, text_field_obj->get_nCharacters(&text_len));
base::win::ScopedBstr text;
@@ -338,8 +338,8 @@ TEST_F(BrowserAccessibilityTest, TestTextBoundaries) {
EXPECT_STREQ(L"One ", text);
text.Reset();
- long start;
- long end;
+ LONG start;
+ LONG end;
EXPECT_EQ(S_OK, text_field_obj->get_textAtOffset(
1, IA2_TEXT_BOUNDARY_CHAR, &start, &end, text.Receive()));
EXPECT_EQ(1, start);
@@ -408,7 +408,7 @@ TEST_F(BrowserAccessibilityTest, TestTextBoundaries) {
TEST_F(BrowserAccessibilityTest, TestSimpleHypertext) {
const std::string text1_name = "One two three.";
const std::string text2_name = " Four five six.";
- const long text_name_len = text1_name.length() + text2_name.length();
+ const LONG text_name_len = text1_name.length() + text2_name.length();
ui::AXNodeData text1;
text1.id = 11;
@@ -434,7 +434,7 @@ TEST_F(BrowserAccessibilityTest, TestSimpleHypertext) {
BrowserAccessibilityComWin* root_obj =
ToBrowserAccessibilityWin(manager->GetRoot())->GetCOM();
- long text_len;
+ LONG text_len;
EXPECT_EQ(S_OK, root_obj->get_nCharacters(&text_len));
EXPECT_EQ(text_name_len, text_len);
@@ -442,7 +442,7 @@ TEST_F(BrowserAccessibilityTest, TestSimpleHypertext) {
EXPECT_EQ(S_OK, root_obj->get_text(0, text_name_len, text.Receive()));
EXPECT_EQ(text1_name + text2_name, base::UTF16ToUTF8(base::string16(text)));
- long hyperlink_count;
+ LONG hyperlink_count;
EXPECT_EQ(S_OK, root_obj->get_nHyperlinks(&hyperlink_count));
EXPECT_EQ(0, hyperlink_count);
@@ -455,7 +455,7 @@ TEST_F(BrowserAccessibilityTest, TestSimpleHypertext) {
EXPECT_EQ(E_INVALIDARG, root_obj->get_hyperlink(text_name_len + 1,
hyperlink.GetAddressOf()));
- long hyperlink_index;
+ LONG hyperlink_index;
EXPECT_EQ(S_FALSE, root_obj->get_hyperlinkIndex(0, &hyperlink_index));
EXPECT_EQ(-1, hyperlink_index);
// Invalid arguments should not be modified.
@@ -486,7 +486,7 @@ TEST_F(BrowserAccessibilityTest, TestComplexHypertext) {
const base::string16 embed(1, BrowserAccessibilityComWin::kEmbeddedCharacter);
const base::string16 root_hypertext =
text1_name + embed + text2_name + embed + embed + embed;
- const long root_hypertext_len = root_hypertext.length();
+ const LONG root_hypertext_len = root_hypertext.length();
ui::AXNodeData text1;
text1.id = 11;
@@ -547,7 +547,7 @@ TEST_F(BrowserAccessibilityTest, TestComplexHypertext) {
BrowserAccessibilityComWin* root_obj =
ToBrowserAccessibilityWin(manager->GetRoot())->GetCOM();
- long text_len;
+ LONG text_len;
EXPECT_EQ(S_OK, root_obj->get_nCharacters(&text_len));
EXPECT_EQ(root_hypertext_len, text_len);
@@ -556,7 +556,7 @@ TEST_F(BrowserAccessibilityTest, TestComplexHypertext) {
EXPECT_STREQ(root_hypertext.c_str(), text);
text.Reset();
- long hyperlink_count;
+ LONG hyperlink_count;
EXPECT_EQ(S_OK, root_obj->get_nHyperlinks(&hyperlink_count));
EXPECT_EQ(4, hyperlink_count);
@@ -607,7 +607,7 @@ TEST_F(BrowserAccessibilityTest, TestComplexHypertext) {
hyperlink.Reset();
hypertext.Reset();
- long hyperlink_index;
+ LONG hyperlink_index;
EXPECT_EQ(S_FALSE, root_obj->get_hyperlinkIndex(0, &hyperlink_index));
EXPECT_EQ(-1, hyperlink_index);
// Invalid arguments should not be modified.
@@ -937,7 +937,7 @@ TEST_F(BrowserAccessibilityTest, TestValueAttributeInTextControls) {
}
TEST_F(BrowserAccessibilityTest, TestWordBoundariesInTextControls) {
- const base::string16 line1(L"This is a very long line of text that ");
+ const base::string16 line1(L"This is a very LONG line of text that ");
const base::string16 line2(L"should wrap on more than one lines ");
const base::string16 text(line1 + line2);
diff --git a/chromium/content/browser/accessibility/cross_platform_accessibility_browsertest.cc b/chromium/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
index 4541b57ade6..b1942ea3546 100644
--- a/chromium/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
+++ b/chromium/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
@@ -23,8 +23,7 @@
#include "ui/accessibility/ax_tree.h"
#if defined(OS_WIN)
-#include <atlbase.h>
-#include <atlcom.h>
+#include "base/win/atl.h"
#include "base/win/scoped_com_initializer.h"
#include "ui/base/win/atl_module.h"
#endif
diff --git a/chromium/content/browser/accessibility/dump_accessibility_browsertest_base.cc b/chromium/content/browser/accessibility/dump_accessibility_browsertest_base.cc
index c97d5c92642..76f0ccee205 100644
--- a/chromium/content/browser/accessibility/dump_accessibility_browsertest_base.cc
+++ b/chromium/content/browser/accessibility/dump_accessibility_browsertest_base.cc
@@ -213,7 +213,7 @@ void DumpAccessibilityTestBase::RunTestForPlatform(
base::FilePath expected_file;
std::string expected_contents_raw;
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_test_setup;
+ base::ScopedAllowBlockingForTesting allow_blocking;
base::ReadFileToString(file_path, &html_contents);
// Read the expected file.
diff --git a/chromium/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/chromium/content/browser/accessibility/dump_accessibility_events_browsertest.cc
index bc91d524e85..b914cec0d63 100644
--- a/chromium/content/browser/accessibility/dump_accessibility_events_browsertest.cc
+++ b/chromium/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -83,10 +83,9 @@ std::vector<std::string> DumpAccessibilityEventsTest::Dump() {
WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
shell()->web_contents());
base::ProcessId pid = base::GetCurrentProcId();
- std::unique_ptr<AccessibilityEventRecorder> event_recorder(
- AccessibilityEventRecorder::Create(
- web_contents->GetRootBrowserAccessibilityManager(), pid));
- event_recorder->set_only_web_events(true);
+ auto& event_recorder = AccessibilityEventRecorder::GetInstance(
+ web_contents->GetRootBrowserAccessibilityManager(), pid);
+ event_recorder.set_only_web_events(true);
// Save a copy of the accessibility tree (as a text dump); we'll
// log this for the user later if the test fails.
@@ -124,7 +123,7 @@ std::vector<std::string> DumpAccessibilityEventsTest::Dump() {
// Dump the event logs, running them through any filters specified
// in the HTML file.
- std::vector<std::string> event_logs = event_recorder->event_logs();
+ std::vector<std::string> event_logs = event_recorder.event_logs();
std::vector<std::string> result;
for (size_t i = 0; i < event_logs.size(); ++i) {
if (AccessibilityTreeFormatter::MatchesFilters(
@@ -156,7 +155,7 @@ void DumpAccessibilityEventsTest::RunEventTest(
base::FilePath test_path = GetTestFilePath("accessibility", "event");
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_test_verification;
+ base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(base::PathExists(test_path)) << test_path.LossyDisplayName();
}
@@ -340,6 +339,11 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsLiveRegionElemReparent) {
+ RunEventTest(FILE_PATH_LITERAL("live-region-elem-reparent.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
AccessibilityEventsLiveRegionIgnoresClick) {
RunEventTest(FILE_PATH_LITERAL("live-region-ignores-click.html"));
}
@@ -355,6 +359,11 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
RunEventTest(FILE_PATH_LITERAL("menulist-collapse.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+ AccessibilityEventsMenuListCollapseNext) {
+ RunEventTest(FILE_PATH_LITERAL("menulist-collapse-next.html"));
+}
+
// https://crbug.com/719030
IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
DISABLED_AccessibilityEventsMenuListExpand) {
diff --git a/chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index b0c2af3f667..6de78219107 100644
--- a/chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -77,7 +77,7 @@ class DumpAccessibilityTreeTest : public DumpAccessibilityTestBase {
void RunAriaTest(const base::FilePath::CharType* file_path) {
base::FilePath test_path = GetTestFilePath("accessibility", "aria");
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_test_setup;
+ base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(base::PathExists(test_path)) << test_path.LossyDisplayName();
}
base::FilePath aria_file = test_path.Append(base::FilePath(file_path));
@@ -88,7 +88,7 @@ class DumpAccessibilityTreeTest : public DumpAccessibilityTestBase {
void RunAomTest(const base::FilePath::CharType* file_path) {
base::FilePath test_path = GetTestFilePath("accessibility", "aom");
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_test_setup;
+ base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(base::PathExists(test_path)) << test_path.LossyDisplayName();
}
base::FilePath aom_file = test_path.Append(base::FilePath(file_path));
@@ -99,7 +99,7 @@ class DumpAccessibilityTreeTest : public DumpAccessibilityTestBase {
void RunCSSTest(const base::FilePath::CharType* file_path) {
base::FilePath test_path = GetTestFilePath("accessibility", "css");
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_test_setup;
+ base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(base::PathExists(test_path)) << test_path.LossyDisplayName();
}
base::FilePath css_file = test_path.Append(base::FilePath(file_path));
@@ -110,7 +110,7 @@ class DumpAccessibilityTreeTest : public DumpAccessibilityTestBase {
void RunHtmlTest(const base::FilePath::CharType* file_path) {
base::FilePath test_path = GetTestFilePath("accessibility", "html");
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_test_setup;
+ base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(base::PathExists(test_path)) << test_path.LossyDisplayName();
}
base::FilePath html_file = test_path.Append(base::FilePath(file_path));
@@ -412,6 +412,10 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaBanner) {
RunAriaTest(FILE_PATH_LITERAL("aria-banner.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaBlockquote) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-blockquote.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaBusy) {
RunAriaTest(FILE_PATH_LITERAL("aria-busy.html"));
}
@@ -420,6 +424,10 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaButton) {
RunAriaTest(FILE_PATH_LITERAL("aria-button.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaCaption) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-caption.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaCell) {
RunAriaTest(FILE_PATH_LITERAL("aria-cell.html"));
}
@@ -733,6 +741,10 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaOption) {
RunAriaTest(FILE_PATH_LITERAL("aria-option.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaParagraph) {
+ RunAriaTest(FILE_PATH_LITERAL("aria-paragraph.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaPosinset) {
RunAriaTest(FILE_PATH_LITERAL("aria-posinset.html"));
}
@@ -991,6 +1003,10 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityBody) {
RunHtmlTest(FILE_PATH_LITERAL("body.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityBodyTabIndex) {
+ RunHtmlTest(FILE_PATH_LITERAL("body-tabindex.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityBoundsInherits) {
RunHtmlTest(FILE_PATH_LITERAL("bounds-inherits.html"));
}
@@ -1414,6 +1430,21 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputSearch) {
RunHtmlTest(FILE_PATH_LITERAL("input-search.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityScrollableInput) {
+ RunHtmlTest(FILE_PATH_LITERAL("scrollable-input.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityScrollableOverflow) {
+ RunHtmlTest(FILE_PATH_LITERAL("scrollable-overflow.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityScrollableTextarea) {
+ RunHtmlTest(FILE_PATH_LITERAL("scrollable-textarea.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySmall) {
RunHtmlTest(FILE_PATH_LITERAL("small.html"));
}
diff --git a/chromium/content/browser/accessibility/web_contents_accessibility_android.cc b/chromium/content/browser/accessibility/web_contents_accessibility_android.cc
index ee2bfb27fd3..8007c45a720 100644
--- a/chromium/content/browser/accessibility/web_contents_accessibility_android.cc
+++ b/chromium/content/browser/accessibility/web_contents_accessibility_android.cc
@@ -350,6 +350,7 @@ WebContentsAccessibilityAndroid::WebContentsAccessibilityAndroid(
: java_ref_(env, obj),
web_contents_(static_cast<WebContentsImpl*>(web_contents)),
frame_info_initialized_(false),
+ use_zoom_for_dsf_enabled_(IsUseZoomForDSFEnabled()),
root_manager_(nullptr),
connector_(new Connector(web_contents, this)) {
CollectStats();
@@ -550,7 +551,7 @@ bool WebContentsAccessibilityAndroid::OnHoverEvent(
if (event.GetAction() != ui::MotionEvent::Action::HOVER_EXIT &&
root_manager_) {
gfx::PointF point =
- IsUseZoomForDSFEnabled() ? event.GetPointPix() : event.GetPoint();
+ use_zoom_for_dsf_enabled_ ? event.GetPointPix() : event.GetPoint();
point.Scale(1 / page_scale_);
root_manager_->HitTest(gfx::ToFlooredPoint(point));
}
@@ -694,10 +695,15 @@ jboolean WebContentsAccessibilityAndroid::PopulateAccessibilityNodeInfo(
base::android::ConvertUTF16ToJavaString(env, element_id));
}
- gfx::Rect absolute_rect = node->GetPageBoundsRect();
+ float dip_scale = use_zoom_for_dsf_enabled_
+ ? 1 / root_manager_->device_scale_factor()
+ : 1.0;
+ gfx::Rect absolute_rect = gfx::ScaleToEnclosingRect(node->GetPageBoundsRect(),
+ dip_scale, dip_scale);
gfx::Rect parent_relative_rect = absolute_rect;
if (node->PlatformGetParent()) {
- gfx::Rect parent_rect = node->PlatformGetParent()->GetPageBoundsRect();
+ gfx::Rect parent_rect = gfx::ScaleToEnclosingRect(
+ node->PlatformGetParent()->GetPageBoundsRect(), dip_scale, dip_scale);
parent_relative_rect.Offset(-parent_rect.OffsetFromOrigin());
}
bool is_root = node->PlatformGetParent() == NULL;
@@ -1189,7 +1195,7 @@ WebContentsAccessibilityAndroid::GetCharacterBoundingBoxes(
gfx::Rect object_bounds = node->GetPageBoundsRect();
int coords[4 * len];
for (int i = 0; i < len; i++) {
- gfx::Rect char_bounds = node->GetPageBoundsForRange(start + i, 1);
+ gfx::Rect char_bounds = node->GetPageBoundsForRange(start + i, 1, false);
if (char_bounds.IsEmpty())
char_bounds = object_bounds;
coords[4 * i + 0] = char_bounds.x();
diff --git a/chromium/content/browser/accessibility/web_contents_accessibility_android.h b/chromium/content/browser/accessibility/web_contents_accessibility_android.h
index 51343b13f97..de47526f888 100644
--- a/chromium/content/browser/accessibility/web_contents_accessibility_android.h
+++ b/chromium/content/browser/accessibility/web_contents_accessibility_android.h
@@ -261,6 +261,8 @@ class CONTENT_EXPORT WebContentsAccessibilityAndroid
float page_scale_ = 1.f;
+ bool use_zoom_for_dsf_enabled_;
+
BrowserAccessibilityManagerAndroid* root_manager_;
// Manages the connection between web contents and the RenderFrameHost that
diff --git a/chromium/content/browser/android/dialog_overlay_impl.h b/chromium/content/browser/android/dialog_overlay_impl.h
index 51e40678668..4cb4cbef524 100644
--- a/chromium/content/browser/android/dialog_overlay_impl.h
+++ b/chromium/content/browser/android/dialog_overlay_impl.h
@@ -16,7 +16,7 @@
namespace content {
// Native counterpart to DialogOverlayImpl java class. This is created by the
-// java side. When the ContentViewCore for the provided token is attached or
+// java side. When the WebContents for the provided token is attached or
// detached from a WindowAndroid, we get the Android window token and notify the
// java side.
class DialogOverlayImpl : public ui::ViewAndroidObserver,
diff --git a/chromium/content/browser/android/java/gin_java_bridge_dispatcher_host.h b/chromium/content/browser/android/java/gin_java_bridge_dispatcher_host.h
index 7404fcfeba5..8e55c6434e9 100644
--- a/chromium/content/browser/android/java/gin_java_bridge_dispatcher_host.h
+++ b/chromium/content/browser/android/java/gin_java_bridge_dispatcher_host.h
@@ -25,7 +25,7 @@ class ListValue;
namespace content {
-// This class handles injecting Java objects into a single ContentViewCore /
+// This class handles injecting Java objects into a single WebContents /
// WebView. The Java object itself lives in the browser process on a background
// thread, while multiple JavaScript wrapper objects (one per frame) are created
// on the renderer side. The injected Java objects are identified by ObjectID,
diff --git a/chromium/content/browser/android/java/gin_java_bridge_message_filter.cc b/chromium/content/browser/android/java/gin_java_bridge_message_filter.cc
index 33051e165fa..9c2feb1a847 100644
--- a/chromium/content/browser/android/java/gin_java_bridge_message_filter.cc
+++ b/chromium/content/browser/android/java/gin_java_bridge_message_filter.cc
@@ -102,7 +102,8 @@ scoped_refptr<GinJavaBridgeMessageFilter> GinJavaBridgeMessageFilter::FromHost(
return filter;
}
-GinJavaBridgeDispatcherHost* GinJavaBridgeMessageFilter::FindHost() {
+scoped_refptr<GinJavaBridgeDispatcherHost>
+GinJavaBridgeMessageFilter::FindHost() {
base::AutoLock locker(hosts_lock_);
auto iter = hosts_.find(current_routing_id_);
if (iter != hosts_.end())
@@ -110,7 +111,7 @@ GinJavaBridgeDispatcherHost* GinJavaBridgeMessageFilter::FindHost() {
// Not being able to find a host is OK -- we can receive messages from
// RenderFrames for which the corresponding host part has already been
// destroyed. That means, any references to Java objects that the host was
- // holding were already released (with the death of ContentViewCore), so we
+ // holding were already released (with the death of WebContents), so we
// can just ignore such messages.
// RenderProcessHostImpl does the same -- if it can't find a listener
// for the message's routing id, it just drops the message silently.
@@ -124,7 +125,7 @@ void GinJavaBridgeMessageFilter::OnGetMethods(
GinJavaBoundObject::ObjectID object_id,
std::set<std::string>* returned_method_names) {
DCHECK(JavaBridgeThread::CurrentlyOn());
- GinJavaBridgeDispatcherHost* host = FindHost();
+ scoped_refptr<GinJavaBridgeDispatcherHost> host = FindHost();
if (host) {
host->OnGetMethods(object_id, returned_method_names);
} else {
@@ -137,7 +138,7 @@ void GinJavaBridgeMessageFilter::OnHasMethod(
const std::string& method_name,
bool* result) {
DCHECK(JavaBridgeThread::CurrentlyOn());
- GinJavaBridgeDispatcherHost* host = FindHost();
+ scoped_refptr<GinJavaBridgeDispatcherHost> host = FindHost();
if (host) {
host->OnHasMethod(object_id, method_name, result);
} else {
@@ -152,7 +153,7 @@ void GinJavaBridgeMessageFilter::OnInvokeMethod(
base::ListValue* wrapped_result,
content::GinJavaBridgeError* error_code) {
DCHECK(JavaBridgeThread::CurrentlyOn());
- GinJavaBridgeDispatcherHost* host = FindHost();
+ scoped_refptr<GinJavaBridgeDispatcherHost> host = FindHost();
if (host) {
host->OnInvokeMethod(current_routing_id_, object_id, method_name, arguments,
wrapped_result, error_code);
@@ -165,7 +166,7 @@ void GinJavaBridgeMessageFilter::OnInvokeMethod(
void GinJavaBridgeMessageFilter::OnObjectWrapperDeleted(
GinJavaBoundObject::ObjectID object_id) {
DCHECK(JavaBridgeThread::CurrentlyOn());
- GinJavaBridgeDispatcherHost* host = FindHost();
+ scoped_refptr<GinJavaBridgeDispatcherHost> host = FindHost();
if (host)
host->OnObjectWrapperDeleted(current_routing_id_, object_id);
}
diff --git a/chromium/content/browser/android/java/gin_java_bridge_message_filter.h b/chromium/content/browser/android/java/gin_java_bridge_message_filter.h
index 5a269664f7e..b117d2d5d53 100644
--- a/chromium/content/browser/android/java/gin_java_bridge_message_filter.h
+++ b/chromium/content/browser/android/java/gin_java_bridge_message_filter.h
@@ -54,10 +54,6 @@ class GinJavaBridgeMessageFilter : public BrowserMessageFilter {
friend class BrowserThread;
friend class base::DeleteHelper<GinJavaBridgeMessageFilter>;
- // GinJavaBridgeDispatcherHost removes itself from the map on
- // WebContents destruction, so there is no risk that the pointer would become
- // stale.
- //
// The filter keeps its own routing map of RenderFrames for two reasons:
// 1. Message dispatching must be done on the background thread,
// without resorting to the UI thread, which can be in fact currently
@@ -65,13 +61,13 @@ class GinJavaBridgeMessageFilter : public BrowserMessageFilter {
// 2. As RenderFrames pass away earlier than JavaScript wrappers,
// messages from the latter can arrive after the RenderFrame has been
// removed from the WebContents' routing table.
- typedef std::map<int32_t, GinJavaBridgeDispatcherHost*> HostMap;
+ typedef std::map<int32_t, scoped_refptr<GinJavaBridgeDispatcherHost>> HostMap;
GinJavaBridgeMessageFilter();
~GinJavaBridgeMessageFilter() override;
// Called on the background thread.
- GinJavaBridgeDispatcherHost* FindHost();
+ scoped_refptr<GinJavaBridgeDispatcherHost> FindHost();
void OnGetMethods(GinJavaBoundObject::ObjectID object_id,
std::set<std::string>* returned_method_names);
void OnHasMethod(GinJavaBoundObject::ObjectID object_id,
diff --git a/chromium/content/browser/android/javascript_injector.cc b/chromium/content/browser/android/javascript_injector.cc
index a4585487f4a..2c60177e40f 100644
--- a/chromium/content/browser/android/javascript_injector.cc
+++ b/chromium/content/browser/android/javascript_injector.cc
@@ -15,8 +15,6 @@ using base::android::ScopedJavaLocalRef;
namespace content {
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(JavascriptInjector);
-
JavascriptInjector::JavascriptInjector(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
diff --git a/chromium/content/browser/android/launcher_thread.cc b/chromium/content/browser/android/launcher_thread.cc
index 06a7f234fc1..995bc5a6117 100644
--- a/chromium/content/browser/android/launcher_thread.cc
+++ b/chromium/content/browser/android/launcher_thread.cc
@@ -18,8 +18,9 @@ base::MessageLoop* LauncherThread::GetMessageLoop() {
}
LauncherThread::LauncherThread()
- : java_handler_thread_(Java_LauncherThread_getHandlerThread(
- base::android::AttachCurrentThread())) {
+ : java_handler_thread_(nullptr,
+ Java_LauncherThread_getHandlerThread(
+ base::android::AttachCurrentThread())) {
java_handler_thread_.Start();
}
diff --git a/chromium/content/browser/android/overscroll_controller_android_unittest.cc b/chromium/content/browser/android/overscroll_controller_android_unittest.cc
index 29fb140cdb0..707084f673e 100644
--- a/chromium/content/browser/android/overscroll_controller_android_unittest.cc
+++ b/chromium/content/browser/android/overscroll_controller_android_unittest.cc
@@ -48,6 +48,7 @@ class MockCompositor : public WindowAndroidCompositor {
return nullptr;
}
bool IsDrawingFirstVisibleFrame() const override { return false; }
+ void SetVSyncPaused(bool paused) override {}
};
class MockGlowClient : public OverscrollGlowClient {
diff --git a/chromium/content/browser/android/scoped_surface_request_manager.cc b/chromium/content/browser/android/scoped_surface_request_manager.cc
index 0a092c5aa18..6d67c9f810d 100644
--- a/chromium/content/browser/android/scoped_surface_request_manager.cc
+++ b/chromium/content/browser/android/scoped_surface_request_manager.cc
@@ -52,11 +52,11 @@ ScopedSurfaceRequestManager::GetAndUnregisterInternal(
return request;
}
-void ScopedSurfaceRequestManager::ForwardSurfaceTextureForSurfaceRequest(
+void ScopedSurfaceRequestManager::ForwardSurfaceOwnerForSurfaceRequest(
const base::UnguessableToken& request_token,
- const gl::SurfaceTexture* surface_texture) {
+ const gpu::SurfaceOwner* surface_owner) {
FulfillScopedSurfaceRequest(request_token,
- gl::ScopedJavaSurface(surface_texture));
+ surface_owner->CreateJavaSurface());
}
void ScopedSurfaceRequestManager::FulfillScopedSurfaceRequest(
diff --git a/chromium/content/browser/android/scoped_surface_request_manager.h b/chromium/content/browser/android/scoped_surface_request_manager.h
index aee96e95796..2030ec86f01 100644
--- a/chromium/content/browser/android/scoped_surface_request_manager.h
+++ b/chromium/content/browser/android/scoped_surface_request_manager.h
@@ -49,9 +49,9 @@ class CONTENT_EXPORT ScopedSurfaceRequestManager
// Implementation of ScopedSurfaceRequestConduit.
// To be used in the single process case.
// Can be called from any thread.
- void ForwardSurfaceTextureForSurfaceRequest(
+ void ForwardSurfaceOwnerForSurfaceRequest(
const base::UnguessableToken& request_token,
- const gl::SurfaceTexture* surface_texture) override;
+ const gpu::SurfaceOwner* surface_owner) override;
void clear_requests_for_testing() { request_callbacks_.clear(); }
diff --git a/chromium/content/browser/android/scoped_surface_request_manager_unittest.cc b/chromium/content/browser/android/scoped_surface_request_manager_unittest.cc
index 30e8fa3e4b6..bdff6917a0e 100644
--- a/chromium/content/browser/android/scoped_surface_request_manager_unittest.cc
+++ b/chromium/content/browser/android/scoped_surface_request_manager_unittest.cc
@@ -8,6 +8,7 @@
#include "base/callback_forward.h"
#include "base/run_loop.h"
#include "content/public/test/test_browser_thread_bundle.h"
+#include "gpu/ipc/common/android/surface_owner_android.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gl/android/scoped_java_surface.h"
#include "ui/gl/android/surface_texture.h"
@@ -26,7 +27,7 @@ class ScopedSurfaceRequestManagerUnitTest : public testing::Test {
last_received_request_ = 0;
dummy_token_ = base::UnguessableToken::Deserialize(123, 456);
- surface_texture = gl::SurfaceTexture::Create(0);
+ surface_owner = gpu::SurfaceOwner::Create(0);
dummy_request_ =
base::Bind(&ScopedSurfaceRequestManagerUnitTest::DummyCallback,
base::Unretained(this));
@@ -46,7 +47,7 @@ class ScopedSurfaceRequestManagerUnitTest : public testing::Test {
ScopedSurfaceRequestManager::ScopedSurfaceRequestCB dummy_request_;
ScopedSurfaceRequestManager::ScopedSurfaceRequestCB specific_logging_request_;
- scoped_refptr<gl::SurfaceTexture> surface_texture;
+ std::unique_ptr<gpu::SurfaceOwner> surface_owner;
int last_received_request_;
const int kSpecificCallbackId = 1357;
@@ -139,8 +140,8 @@ TEST_F(ScopedSurfaceRequestManagerUnitTest,
FulfillUnregisteredRequest_ShouldDoNothing) {
manager_->RegisterScopedSurfaceRequest(specific_logging_request_);
- manager_->FulfillScopedSurfaceRequest(
- dummy_token_, gl::ScopedJavaSurface(surface_texture.get()));
+ manager_->FulfillScopedSurfaceRequest(dummy_token_,
+ surface_owner->CreateJavaSurface());
EXPECT_EQ(1, manager_->request_count_for_testing());
EXPECT_NE(kSpecificCallbackId, last_received_request_);
@@ -158,8 +159,8 @@ TEST_F(ScopedSurfaceRequestManagerUnitTest,
base::Bind(&ScopedSurfaceRequestManagerUnitTest::LoggingCallback,
base::Unretained(this), kOtherCallbackId));
- manager_->FulfillScopedSurfaceRequest(
- specific_token, gl::ScopedJavaSurface(surface_texture.get()));
+ manager_->FulfillScopedSurfaceRequest(specific_token,
+ surface_owner->CreateJavaSurface());
base::RunLoop().RunUntilIdle();
@@ -170,12 +171,11 @@ TEST_F(ScopedSurfaceRequestManagerUnitTest,
// Makes sure that the ScopedSurfaceRequestConduit implementation properly
// fulfills requests.
TEST_F(ScopedSurfaceRequestManagerUnitTest,
- ForwardSurfaceTexture_ShouldFulfillRequest) {
+ ForwardSurfaceOwner_ShouldFulfillRequest) {
base::UnguessableToken token =
manager_->RegisterScopedSurfaceRequest(specific_logging_request_);
- manager_->ForwardSurfaceTextureForSurfaceRequest(token,
- surface_texture.get());
+ manager_->ForwardSurfaceOwnerForSurfaceRequest(token, surface_owner.get());
base::RunLoop().RunUntilIdle();
diff --git a/chromium/content/browser/android/select_popup.cc b/chromium/content/browser/android/select_popup.cc
index 1ec666da9e6..44d187ced2e 100644
--- a/chromium/content/browser/android/select_popup.cc
+++ b/chromium/content/browser/android/select_popup.cc
@@ -13,7 +13,6 @@
#include "content/public/common/menu_item.h"
#include "content/public/common/use_zoom_for_dsf_policy.h"
#include "jni/SelectPopup_jni.h"
-#include "ui/android/window_android.h"
#include "ui/gfx/geometry/rect_f.h"
using base::android::AttachCurrentThread;
@@ -41,27 +40,14 @@ enum PopupItemType {
} // namespace
-jlong JNI_SelectPopup_Init(JNIEnv* env,
- const JavaParamRef<jobject>& obj,
- const JavaParamRef<jobject>& jweb_contents) {
- WebContents* web_contents = WebContents::FromJavaWebContents(jweb_contents);
- DCHECK(web_contents);
-
- auto* wc_impl = static_cast<WebContentsImpl*>(web_contents);
- auto* wcv = static_cast<WebContentsViewAndroid*>(wc_impl->GetView());
-
- // Owned by |WebContentsViewAndroid|.
- auto select_popup = std::make_unique<SelectPopup>(env, obj, wc_impl);
- SelectPopup* select_popup_ptr = select_popup.get();
- wcv->SetSelectPopup(std::move(select_popup));
- return reinterpret_cast<intptr_t>(select_popup_ptr);
+SelectPopup::SelectPopup(WebContentsImpl* web_contents)
+ : web_contents_(web_contents) {
+ JNIEnv* env = AttachCurrentThread();
+ java_obj_ = JavaObjectWeakGlobalRef(
+ env, Java_SelectPopup_create(env, web_contents_->GetJavaWebContents(),
+ reinterpret_cast<intptr_t>(this)));
}
-SelectPopup::SelectPopup(JNIEnv* env,
- const JavaParamRef<jobject>& obj,
- WebContentsImpl* web_contents)
- : web_contents_(web_contents), java_obj_(env, obj) {}
-
SelectPopup::~SelectPopup() {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> j_obj = java_obj_.get(env);
@@ -162,11 +148,4 @@ void SelectPopup::SelectMenuItems(JNIEnv* env,
rfhi->DidSelectPopupMenuItems(selected_indices);
}
-base::android::ScopedJavaLocalRef<jobject> SelectPopup::GetWindowAndroid(
- JNIEnv* env,
- const JavaParamRef<jobject>& obj) {
- auto* window = web_contents_->GetNativeView()->GetWindowAndroid();
- return window ? window->GetJavaObject() : ScopedJavaLocalRef<jobject>();
-}
-
} // namespace content
diff --git a/chromium/content/browser/android/select_popup.h b/chromium/content/browser/android/select_popup.h
index bef949c1ae9..3ef5def0c0a 100644
--- a/chromium/content/browser/android/select_popup.h
+++ b/chromium/content/browser/android/select_popup.h
@@ -23,12 +23,7 @@ struct MenuItem;
class SelectPopup {
public:
- SelectPopup(JNIEnv* env,
- const base::android::JavaParamRef<jobject>& obj,
- WebContentsImpl* web_contents);
- base::android::ScopedJavaLocalRef<jobject> GetWindowAndroid(
- JNIEnv* env,
- const base::android::JavaParamRef<jobject>& obj);
+ explicit SelectPopup(WebContentsImpl* web_contents);
~SelectPopup();
// Creates a popup menu with |items|.
diff --git a/chromium/content/browser/android/synchronous_compositor_host.cc b/chromium/content/browser/android/synchronous_compositor_host.cc
index 953c10ab3a4..58d7822c4aa 100644
--- a/chromium/content/browser/android/synchronous_compositor_host.cc
+++ b/chromium/content/browser/android/synchronous_compositor_host.cc
@@ -504,6 +504,11 @@ void SynchronousCompositorHost::UpdateState(
renderer_param_version_ = params.version;
need_animate_scroll_ = params.need_animate_scroll;
root_scroll_offset_ = params.total_scroll_offset;
+ max_scroll_offset_ = params.max_scroll_offset;
+ scrollable_size_ = params.scrollable_size;
+ page_scale_factor_ = params.page_scale_factor;
+ min_page_scale_factor_ = params.min_page_scale_factor;
+ max_page_scale_factor_ = params.max_page_scale_factor;
invalidate_needs_draw_ |= params.invalidate_needs_draw;
if (need_invalidate_count_ != params.need_invalidate_count) {
@@ -521,15 +526,22 @@ void SynchronousCompositorHost::UpdateState(
client_->DidUpdateContent(this);
}
+ UpdateRootLayerStateOnClient();
+}
+
+void SynchronousCompositorHost::DidBecomeActive() {
+ UpdateRootLayerStateOnClient();
+}
+
+void SynchronousCompositorHost::UpdateRootLayerStateOnClient() {
// Ensure only valid values from compositor are sent to client.
// Compositor has page_scale_factor set to 0 before initialization, so check
// for that case here.
- if (params.page_scale_factor) {
+ if (page_scale_factor_) {
client_->UpdateRootLayerState(
- this, gfx::ScrollOffsetToVector2dF(params.total_scroll_offset),
- gfx::ScrollOffsetToVector2dF(params.max_scroll_offset),
- params.scrollable_size, params.page_scale_factor,
- params.min_page_scale_factor, params.max_page_scale_factor);
+ this, gfx::ScrollOffsetToVector2dF(root_scroll_offset_),
+ gfx::ScrollOffsetToVector2dF(max_scroll_offset_), scrollable_size_,
+ page_scale_factor_, min_page_scale_factor_, max_page_scale_factor_);
}
}
diff --git a/chromium/content/browser/android/synchronous_compositor_host.h b/chromium/content/browser/android/synchronous_compositor_host.h
index 6990380f9c5..3c17c46e4a6 100644
--- a/chromium/content/browser/android/synchronous_compositor_host.h
+++ b/chromium/content/browser/android/synchronous_compositor_host.h
@@ -54,6 +54,7 @@ class SynchronousCompositorHost : public SynchronousCompositor,
uint32_t layer_tree_frame_sink_id,
const std::vector<viz::ReturnedResource>& resources) override;
void SetMemoryPolicy(size_t bytes_limit) override;
+ void DidBecomeActive() override;
void DidChangeRootLayerScrollOffset(
const gfx::ScrollOffset& root_offset) override;
void SynchronouslyZoomBy(float zoom_delta, const gfx::Point& anchor) override;
@@ -102,6 +103,7 @@ class SynchronousCompositorHost : public SynchronousCompositor,
// Whether the synchronous compositor host is ready to
// handle blocking calls.
bool IsReadyForSynchronousCall();
+ void UpdateRootLayerStateOnClient();
RenderWidgetHostViewAndroid* const rwhva_;
SynchronousCompositorClient* const client_;
@@ -129,7 +131,8 @@ class SynchronousCompositorHost : public SynchronousCompositor,
// Indicates begin frames are paused from the browser.
bool begin_frame_paused_ = false;
- // Updated by both renderer and browser.
+ // Updated by both renderer and browser. This is in physical pixel when
+ // use-zoom-for-dsf is enabled, otherwise in dip.
gfx::ScrollOffset root_scroll_offset_;
// Indicates that whether OnComputeScroll is called or overridden. The
@@ -144,6 +147,12 @@ class SynchronousCompositorHost : public SynchronousCompositor,
bool invalidate_needs_draw_;
uint32_t did_activate_pending_tree_count_;
uint32_t frame_metadata_version_ = 0u;
+ // Physical pixel when use-zoom-for-dsf is enabled, otherwise in dip.
+ gfx::ScrollOffset max_scroll_offset_;
+ gfx::SizeF scrollable_size_;
+ float page_scale_factor_ = 0.f;
+ float min_page_scale_factor_ = 0.f;
+ float max_page_scale_factor_ = 0.f;
scoped_refptr<SynchronousCompositorSyncCallBridge> bridge_;
diff --git a/chromium/content/browser/android/tap_disambiguator.cc b/chromium/content/browser/android/tap_disambiguator.cc
deleted file mode 100644
index 875c128481d..00000000000
--- a/chromium/content/browser/android/tap_disambiguator.cc
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/android/tap_disambiguator.h"
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_string.h"
-#include "base/android/scoped_java_ref.h"
-#include "content/browser/renderer_host/render_widget_host_view_android.h"
-#include "content/public/browser/web_contents.h"
-#include "jni/TapDisambiguator_jni.h"
-#include "ui/gfx/android/java_bitmap.h"
-
-using base::android::AttachCurrentThread;
-using base::android::ConvertUTF8ToJavaString;
-using base::android::JavaParamRef;
-using base::android::ScopedJavaLocalRef;
-
-namespace content {
-
-namespace {
-
-ScopedJavaLocalRef<jobject> JNI_TapDisambiguator_CreateJavaRect(
- JNIEnv* env,
- const gfx::Rect& rect) {
- return ScopedJavaLocalRef<jobject>(Java_TapDisambiguator_createRect(
- env, rect.x(), rect.y(), rect.right(), rect.bottom()));
-}
-
-} // namespace
-
-jlong JNI_TapDisambiguator_Init(JNIEnv* env,
- const JavaParamRef<jobject>& obj,
- const JavaParamRef<jobject>& jweb_contents) {
- WebContents* web_contents = WebContents::FromJavaWebContents(jweb_contents);
- DCHECK(web_contents);
-
- // Owns itself and gets destroyed when |WebContentsDestroyed| is called.
- auto* tap_disambiguator = new TapDisambiguator(env, obj, web_contents);
- tap_disambiguator->Initialize();
- return reinterpret_cast<intptr_t>(tap_disambiguator);
-}
-
-TapDisambiguator::TapDisambiguator(JNIEnv* env,
- const JavaParamRef<jobject>& obj,
- WebContents* web_contents)
- : RenderWidgetHostConnector(web_contents), rwhva_(nullptr) {
- java_obj_ = JavaObjectWeakGlobalRef(env, obj);
-}
-
-TapDisambiguator::~TapDisambiguator() {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj = java_obj_.get(env);
- if (!obj.is_null())
- Java_TapDisambiguator_destroy(env, obj);
-}
-
-void TapDisambiguator::UpdateRenderProcessConnection(
- RenderWidgetHostViewAndroid* old_rwhva,
- RenderWidgetHostViewAndroid* new_rwhva) {
- if (old_rwhva)
- old_rwhva->set_tap_disambiguator(nullptr);
- if (new_rwhva)
- new_rwhva->set_tap_disambiguator(this);
- rwhva_ = new_rwhva;
-}
-
-void TapDisambiguator::ShowPopup(const gfx::Rect& rect_pixels,
- const SkBitmap& zoomed_bitmap) {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj = java_obj_.get(env);
- if (obj.is_null())
- return;
-
- ScopedJavaLocalRef<jobject> rect_object(
- JNI_TapDisambiguator_CreateJavaRect(env, rect_pixels));
-
- ScopedJavaLocalRef<jobject> java_bitmap =
- gfx::ConvertToJavaBitmap(&zoomed_bitmap);
- DCHECK(!java_bitmap.is_null());
-
- Java_TapDisambiguator_showPopup(env, obj, rect_object, java_bitmap);
-}
-
-void TapDisambiguator::HidePopup() {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj = java_obj_.get(env);
- if (obj.is_null())
- return;
- Java_TapDisambiguator_hidePopup(env, obj);
-}
-
-void TapDisambiguator::ResolveTapDisambiguation(
- JNIEnv* env,
- const JavaParamRef<jobject>& obj,
- jlong time_ms,
- jfloat x,
- jfloat y,
- jboolean is_long_press) {
- if (!rwhva_)
- return;
-
- float dip_scale = rwhva_->GetNativeView()->GetDipScale();
- rwhva_->ResolveTapDisambiguation(
- time_ms / 1000, gfx::Point(x / dip_scale, y / dip_scale), is_long_press);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/android/tap_disambiguator.h b/chromium/content/browser/android/tap_disambiguator.h
deleted file mode 100644
index 849c5b7803e..00000000000
--- a/chromium/content/browser/android/tap_disambiguator.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_ANDROID_TAP_DISAMBIGUATOR_H_
-#define CONTENT_BROWSER_ANDROID_TAP_DISAMBIGUATOR_H_
-
-#include <jni.h>
-
-#include "base/android/jni_weak_ref.h"
-#include "content/browser/android/render_widget_host_connector.h"
-#include "ui/gfx/geometry/rect_f.h"
-
-namespace content {
-
-class RenderWidgetHostViewAndroid;
-
-class TapDisambiguator : public RenderWidgetHostConnector {
- public:
- TapDisambiguator(JNIEnv* env,
- const base::android::JavaParamRef<jobject>& obj,
- WebContents* web_contents);
-
- // RendetWidgetHostConnector implementation.
- void UpdateRenderProcessConnection(
- RenderWidgetHostViewAndroid* old_rwhva,
- RenderWidgetHostViewAndroid* new_rhwva) override;
-
- // Shows the disambiguation popup
- // |rect_pixels| --> window coordinates which |zoomed_bitmap| represents
- // |zoomed_bitmap| --> magnified image of potential touch targets
- void ResolveTapDisambiguation(JNIEnv* env,
- const base::android::JavaParamRef<jobject>& obj,
- jlong time_ms,
- jfloat x,
- jfloat y,
- jboolean is_long_press);
-
- // Called from native -> java
-
- // Shows the disambiguator popup
- // |rect_pixels| --> window coordinates which |zoomed_bitmap| represents
- // |zoomed_bitmap| --> magnified image of potential touch targets
- void ShowPopup(const gfx::Rect& rect_pixels, const SkBitmap& zoomed_bitmap);
- void HidePopup();
-
- private:
- ~TapDisambiguator() override;
-
- // Current RenderWidgetHostView connected to this instance. Can be null.
- RenderWidgetHostViewAndroid* rwhva_;
- JavaObjectWeakGlobalRef java_obj_;
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_ANDROID_TAP_DISAMBIGUATOR_H_
diff --git a/chromium/content/browser/appcache/appcache.cc b/chromium/content/browser/appcache/appcache.cc
index 2e1a8046642..5390894d2ed 100644
--- a/chromium/content/browser/appcache/appcache.cc
+++ b/chromium/content/browser/appcache/appcache.cc
@@ -85,8 +85,9 @@ const AppCacheEntry* AppCache::GetEntryAndUrlWithResponseId(
return nullptr;
}
-GURL AppCache::GetNamespaceEntryUrl(const AppCacheNamespaceVector& namespaces,
- const GURL& namespace_url) const {
+GURL AppCache::GetNamespaceEntryUrl(
+ const std::vector<AppCacheNamespace>& namespaces,
+ const GURL& namespace_url) const {
size_t count = namespaces.size();
for (size_t i = 0; i < count; ++i) {
if (namespaces[i].namespace_url == namespace_url)
@@ -262,8 +263,8 @@ bool AppCache::FindResponseForRequest(const GURL& url,
return *found_network_namespace;
}
-
-void AppCache::ToResourceInfoVector(AppCacheResourceInfoVector* infos) const {
+void AppCache::ToResourceInfoVector(
+ std::vector<AppCacheResourceInfo>* infos) const {
DCHECK(infos && infos->empty());
for (const auto& pair : entries_) {
infos->push_back(AppCacheResourceInfo());
@@ -282,7 +283,7 @@ void AppCache::ToResourceInfoVector(AppCacheResourceInfoVector* infos) const {
// static
const AppCacheNamespace* AppCache::FindNamespace(
- const AppCacheNamespaceVector& namespaces,
+ const std::vector<AppCacheNamespace>& namespaces,
const GURL& url) {
size_t count = namespaces.size();
for (size_t i = 0; i < count; ++i) {
diff --git a/chromium/content/browser/appcache/appcache.h b/chromium/content/browser/appcache/appcache.h
index f468b5dea18..8e21cf3e71c 100644
--- a/chromium/content/browser/appcache/appcache.h
+++ b/chromium/content/browser/appcache/appcache.h
@@ -130,10 +130,10 @@ class CONTENT_EXPORT AppCache
bool* found_network_namespace);
// Populates the 'infos' vector with an element per entry in the appcache.
- void ToResourceInfoVector(AppCacheResourceInfoVector* infos) const;
+ void ToResourceInfoVector(std::vector<AppCacheResourceInfo>* infos) const;
static const AppCacheNamespace* FindNamespace(
- const AppCacheNamespaceVector& namespaces,
+ const std::vector<AppCacheNamespace>& namespaces,
const GURL& url);
private:
@@ -160,7 +160,7 @@ class CONTENT_EXPORT AppCache
return FindNamespace(online_whitelist_namespaces_, url) != nullptr;
}
- GURL GetNamespaceEntryUrl(const AppCacheNamespaceVector& namespaces,
+ GURL GetNamespaceEntryUrl(const std::vector<AppCacheNamespace>& namespaces,
const GURL& namespace_url) const;
// Use AppCacheHost::Associate*Cache() to manipulate host association.
@@ -175,9 +175,9 @@ class CONTENT_EXPORT AppCache
EntryMap entries_; // contains entries of all types
- AppCacheNamespaceVector intercept_namespaces_;
- AppCacheNamespaceVector fallback_namespaces_;
- AppCacheNamespaceVector online_whitelist_namespaces_;
+ std::vector<AppCacheNamespace> intercept_namespaces_;
+ std::vector<AppCacheNamespace> fallback_namespaces_;
+ std::vector<AppCacheNamespace> online_whitelist_namespaces_;
bool online_whitelist_all_;
bool is_complete_;
diff --git a/chromium/content/browser/appcache/appcache_database.cc b/chromium/content/browser/appcache/appcache_database.cc
index 0f747557abb..e3d373be53a 100644
--- a/chromium/content/browser/appcache/appcache_database.cc
+++ b/chromium/content/browser/appcache/appcache_database.cc
@@ -13,7 +13,7 @@
#include "base/strings/utf_string_conversions.h"
#include "content/browser/appcache/appcache_entry.h"
#include "content/browser/appcache/appcache_histograms.h"
-#include "sql/connection.h"
+#include "sql/database.h"
#include "sql/error_delegate_util.h"
#include "sql/meta_table.h"
#include "sql/statement.h"
@@ -156,14 +156,14 @@ const IndexInfo kIndexes[] = {
const int kTableCount = arraysize(kTables);
const int kIndexCount = arraysize(kIndexes);
-bool CreateTable(sql::Connection* db, const TableInfo& info) {
+bool CreateTable(sql::Database* db, const TableInfo& info) {
std::string sql("CREATE TABLE ");
sql += info.table_name;
sql += info.columns;
return db->Execute(sql.c_str());
}
-bool CreateIndex(sql::Connection* db, const IndexInfo& info) {
+bool CreateIndex(sql::Database* db, const IndexInfo& info) {
std::string sql;
if (info.unique)
sql += "CREATE UNIQUE INDEX ";
@@ -1042,7 +1042,7 @@ bool AppCacheDatabase::LazyOpen(bool create_if_needed) {
return false;
}
- db_.reset(new sql::Connection);
+ db_.reset(new sql::Database);
meta_table_.reset(new sql::MetaTable);
db_->set_histogram_tag("AppCache");
diff --git a/chromium/content/browser/appcache/appcache_database.h b/chromium/content/browser/appcache/appcache_database.h
index 164f6b58772..fe3e144e8ca 100644
--- a/chromium/content/browser/appcache/appcache_database.h
+++ b/chromium/content/browser/appcache/appcache_database.h
@@ -23,7 +23,7 @@
#include "url/origin.h"
namespace sql {
-class Connection;
+class Database;
class MetaTable;
class Statement;
}
@@ -190,7 +190,7 @@ class CONTENT_EXPORT AppCacheDatabase {
bool DeleteDeletableResponseIds(const std::vector<int64_t>& response_ids);
// So our callers can wrap operations in transactions.
- sql::Connection* db_connection() {
+ sql::Database* db_connection() {
LazyOpen(true);
return db_.get();
}
@@ -234,7 +234,7 @@ class CONTENT_EXPORT AppCacheDatabase {
void OnDatabaseError(int err, sql::Statement* stmt);
base::FilePath db_file_path_;
- std::unique_ptr<sql::Connection> db_;
+ std::unique_ptr<sql::Database> db_;
std::unique_ptr<sql::MetaTable> meta_table_;
std::map<int64_t, base::Time> lazy_last_access_times_;
bool is_disabled_;
diff --git a/chromium/content/browser/appcache/appcache_database_unittest.cc b/chromium/content/browser/appcache/appcache_database_unittest.cc
index 7f72b4fe59c..53b5e2e317f 100644
--- a/chromium/content/browser/appcache/appcache_database_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_database_unittest.cc
@@ -13,7 +13,7 @@
#include "base/strings/stringprintf.h"
#include "content/browser/appcache/appcache_database.h"
#include "content/browser/appcache/appcache_entry.h"
-#include "sql/connection.h"
+#include "sql/database.h"
#include "sql/meta_table.h"
#include "sql/statement.h"
#include "sql/test/scoped_error_expecter.h"
@@ -80,7 +80,7 @@ TEST(AppCacheDatabaseTest, ReCreate) {
}
#ifdef NDEBUG
-// Only run in release builds because sql::Connection and familiy
+// Only run in release builds because sql::Database and familiy
// crank up DLOG(FATAL)'ness and this test presents it with
// intentionally bad data which causes debug builds to exit instead
// of run to completion. In release builds, errors the are delivered
@@ -961,7 +961,7 @@ TEST(AppCacheDatabaseTest, UpgradeSchema4to7) {
const int kTableCount4 = arraysize(kTables4);
const int kIndexCount4 = arraysize(kIndexes4);
- sql::Connection connection;
+ sql::Database connection;
EXPECT_TRUE(connection.Open(kDbFile));
sql::Transaction transaction(&connection);
@@ -1212,7 +1212,7 @@ TEST(AppCacheDatabaseTest, UpgradeSchema5or6to7) {
const int kTableCount5 = arraysize(kTables5);
const int kIndexCount5 = arraysize(kIndexes5);
- sql::Connection connection;
+ sql::Database connection;
EXPECT_TRUE(connection.Open(kDbFile));
sql::Transaction transaction(&connection);
diff --git a/chromium/content/browser/appcache/appcache_disk_cache.cc b/chromium/content/browser/appcache/appcache_disk_cache.cc
index 8c28d1862d7..c7018934cb2 100644
--- a/chromium/content/browser/appcache/appcache_disk_cache.cc
+++ b/chromium/content/browser/appcache/appcache_disk_cache.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
@@ -16,6 +17,7 @@
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "net/base/cache_type.h"
+#include "net/base/completion_repeating_callback.h"
#include "net/base/net_errors.h"
namespace content {
@@ -65,27 +67,28 @@ class AppCacheDiskCache::EntryImpl : public Entry {
int64_t offset,
net::IOBuffer* buf,
int buf_len,
- const net::CompletionCallback& callback) override {
+ net::CompletionOnceCallback callback) override {
if (offset < 0 || offset > std::numeric_limits<int32_t>::max())
return net::ERR_INVALID_ARGUMENT;
if (!disk_cache_entry_)
return net::ERR_ABORTED;
- return disk_cache_entry_->ReadData(
- index, static_cast<int>(offset), buf, buf_len, callback);
+ return disk_cache_entry_->ReadData(index, static_cast<int>(offset), buf,
+ buf_len, std::move(callback));
}
int Write(int index,
int64_t offset,
net::IOBuffer* buf,
int buf_len,
- const net::CompletionCallback& callback) override {
+ net::CompletionOnceCallback callback) override {
if (offset < 0 || offset > std::numeric_limits<int32_t>::max())
return net::ERR_INVALID_ARGUMENT;
if (!disk_cache_entry_)
return net::ERR_ABORTED;
const bool kTruncate = true;
- return disk_cache_entry_->WriteData(
- index, static_cast<int>(offset), buf, buf_len, callback, kTruncate);
+ return disk_cache_entry_->WriteData(index, static_cast<int>(offset), buf,
+ buf_len, std::move(callback),
+ kTruncate);
}
int64_t GetSize(int index) override {
@@ -122,35 +125,35 @@ class AppCacheDiskCache::ActiveCall
static int CreateEntry(const base::WeakPtr<AppCacheDiskCache>& owner,
int64_t key,
Entry** entry,
- const net::CompletionCallback& callback) {
+ net::CompletionOnceCallback callback) {
scoped_refptr<ActiveCall> active_call(
- new ActiveCall(owner, entry, callback));
+ new ActiveCall(owner, entry, std::move(callback)));
int rv = owner->disk_cache()->CreateEntry(
base::Int64ToString(key), net::HIGHEST, &active_call->entry_ptr_,
- base::Bind(&ActiveCall::OnAsyncCompletion, active_call));
+ base::BindOnce(&ActiveCall::OnAsyncCompletion, active_call));
return active_call->HandleImmediateReturnValue(rv);
}
static int OpenEntry(const base::WeakPtr<AppCacheDiskCache>& owner,
int64_t key,
Entry** entry,
- const net::CompletionCallback& callback) {
+ net::CompletionOnceCallback callback) {
scoped_refptr<ActiveCall> active_call(
- new ActiveCall(owner, entry, callback));
+ new ActiveCall(owner, entry, std::move(callback)));
int rv = owner->disk_cache()->OpenEntry(
base::Int64ToString(key), net::HIGHEST, &active_call->entry_ptr_,
- base::Bind(&ActiveCall::OnAsyncCompletion, active_call));
+ base::BindOnce(&ActiveCall::OnAsyncCompletion, active_call));
return active_call->HandleImmediateReturnValue(rv);
}
static int DoomEntry(const base::WeakPtr<AppCacheDiskCache>& owner,
int64_t key,
- const net::CompletionCallback& callback) {
+ net::CompletionOnceCallback callback) {
scoped_refptr<ActiveCall> active_call(
- new ActiveCall(owner, nullptr, callback));
+ new ActiveCall(owner, nullptr, std::move(callback)));
int rv = owner->disk_cache()->DoomEntry(
base::Int64ToString(key), net::HIGHEST,
- base::Bind(&ActiveCall::OnAsyncCompletion, active_call));
+ base::BindOnce(&ActiveCall::OnAsyncCompletion, active_call));
return active_call->HandleImmediateReturnValue(rv);
}
@@ -159,10 +162,10 @@ class AppCacheDiskCache::ActiveCall
ActiveCall(const base::WeakPtr<AppCacheDiskCache>& owner,
Entry** entry,
- const net::CompletionCallback& callback)
+ net::CompletionOnceCallback callback)
: owner_(owner),
entry_(entry),
- callback_(callback),
+ callback_(std::move(callback)),
entry_ptr_(nullptr) {
DCHECK(owner_);
}
@@ -192,12 +195,12 @@ class AppCacheDiskCache::ActiveCall
rv = net::ERR_ABORTED;
}
}
- callback_.Run(rv);
+ std::move(callback_).Run(rv);
}
base::WeakPtr<AppCacheDiskCache> owner_;
Entry** entry_;
- net::CompletionCallback callback_;
+ net::CompletionOnceCallback callback_;
disk_cache::Entry* entry_ptr_;
};
@@ -219,15 +222,16 @@ int AppCacheDiskCache::InitWithDiskBackend(
int disk_cache_size,
bool force,
base::OnceClosure post_cleanup_callback,
- const net::CompletionCallback& callback) {
+ net::CompletionOnceCallback callback) {
return Init(net::APP_CACHE, disk_cache_directory, disk_cache_size, force,
- std::move(post_cleanup_callback), callback);
+ std::move(post_cleanup_callback), std::move(callback));
}
int AppCacheDiskCache::InitWithMemBackend(
- int mem_cache_size, const net::CompletionCallback& callback) {
+ int mem_cache_size,
+ net::CompletionOnceCallback callback) {
return Init(net::MEMORY_CACHE, base::FilePath(), mem_cache_size, false,
- base::OnceClosure(), callback);
+ base::OnceClosure(), std::move(callback));
}
void AppCacheDiskCache::Disable() {
@@ -254,59 +258,63 @@ void AppCacheDiskCache::Disable() {
int AppCacheDiskCache::CreateEntry(int64_t key,
Entry** entry,
- const net::CompletionCallback& callback) {
+ net::CompletionOnceCallback callback) {
DCHECK(entry);
DCHECK(!callback.is_null());
if (is_disabled_)
return net::ERR_ABORTED;
if (is_initializing_or_waiting_to_initialize()) {
- pending_calls_.push_back(PendingCall(CREATE, key, entry, callback));
+ pending_calls_.push_back(
+ PendingCall(CREATE, key, entry, std::move(callback)));
return net::ERR_IO_PENDING;
}
if (!disk_cache_)
return net::ERR_FAILED;
- return ActiveCall::CreateEntry(
- weak_factory_.GetWeakPtr(), key, entry, callback);
+ return ActiveCall::CreateEntry(weak_factory_.GetWeakPtr(), key, entry,
+ std::move(callback));
}
int AppCacheDiskCache::OpenEntry(int64_t key,
Entry** entry,
- const net::CompletionCallback& callback) {
+ net::CompletionOnceCallback callback) {
DCHECK(entry);
DCHECK(!callback.is_null());
if (is_disabled_)
return net::ERR_ABORTED;
if (is_initializing_or_waiting_to_initialize()) {
- pending_calls_.push_back(PendingCall(OPEN, key, entry, callback));
+ pending_calls_.push_back(
+ PendingCall(OPEN, key, entry, std::move(callback)));
return net::ERR_IO_PENDING;
}
if (!disk_cache_)
return net::ERR_FAILED;
- return ActiveCall::OpenEntry(
- weak_factory_.GetWeakPtr(), key, entry, callback);
+ return ActiveCall::OpenEntry(weak_factory_.GetWeakPtr(), key, entry,
+ std::move(callback));
}
int AppCacheDiskCache::DoomEntry(int64_t key,
- const net::CompletionCallback& callback) {
+ net::CompletionOnceCallback callback) {
DCHECK(!callback.is_null());
if (is_disabled_)
return net::ERR_ABORTED;
if (is_initializing_or_waiting_to_initialize()) {
- pending_calls_.push_back(PendingCall(DOOM, key, nullptr, callback));
+ pending_calls_.push_back(
+ PendingCall(DOOM, key, nullptr, std::move(callback)));
return net::ERR_IO_PENDING;
}
if (!disk_cache_)
return net::ERR_FAILED;
- return ActiveCall::DoomEntry(weak_factory_.GetWeakPtr(), key, callback);
+ return ActiveCall::DoomEntry(weak_factory_.GetWeakPtr(), key,
+ std::move(callback));
}
AppCacheDiskCache::AppCacheDiskCache(bool use_simple_cache)
@@ -323,10 +331,13 @@ AppCacheDiskCache::PendingCall::PendingCall(
PendingCallType call_type,
int64_t key,
Entry** entry,
- const net::CompletionCallback& callback)
- : call_type(call_type), key(key), entry(entry), callback(callback) {}
+ net::CompletionOnceCallback callback)
+ : call_type(call_type),
+ key(key),
+ entry(entry),
+ callback(std::move(callback)) {}
-AppCacheDiskCache::PendingCall::PendingCall(const PendingCall& other) = default;
+AppCacheDiskCache::PendingCall::PendingCall(PendingCall&& other) = default;
AppCacheDiskCache::PendingCall::~PendingCall() {}
@@ -335,7 +346,7 @@ int AppCacheDiskCache::Init(net::CacheType cache_type,
int cache_size,
bool force,
base::OnceClosure post_cleanup_callback,
- const net::CompletionCallback& callback) {
+ net::CompletionOnceCallback callback) {
DCHECK(!is_initializing_or_waiting_to_initialize() && !disk_cache_.get());
is_disabled_ = false;
create_backend_callback_ = new CreateBackendCallbackShim(this);
@@ -347,10 +358,10 @@ int AppCacheDiskCache::Init(net::CacheType cache_type,
cache_directory, cache_size, force, nullptr,
&(create_backend_callback_->backend_ptr_),
std::move(post_cleanup_callback),
- base::Bind(&CreateBackendCallbackShim::Callback,
- create_backend_callback_));
+ base::BindOnce(&CreateBackendCallbackShim::Callback,
+ create_backend_callback_));
if (rv == net::ERR_IO_PENDING)
- init_callback_ = callback;
+ init_callback_ = std::move(callback);
else
OnCreateBackendComplete(rv);
return rv;
@@ -364,29 +375,31 @@ void AppCacheDiskCache::OnCreateBackendComplete(int rv) {
// Invoke our clients callback function.
if (!init_callback_.is_null()) {
- init_callback_.Run(rv);
- init_callback_.Reset();
+ std::move(init_callback_).Run(rv);
}
// Service pending calls that were queued up while we were initializing.
- for (const auto& call : pending_calls_) {
+ for (auto& call : pending_calls_) {
+ // This is safe, because the callback will only be called once.
+ net::CompletionRepeatingCallback copyable_callback =
+ base::AdaptCallbackForRepeating(std::move(call.callback));
rv = net::ERR_FAILED;
switch (call.call_type) {
case CREATE:
- rv = CreateEntry(call.key, call.entry, call.callback);
+ rv = CreateEntry(call.key, call.entry, copyable_callback);
break;
case OPEN:
- rv = OpenEntry(call.key, call.entry, call.callback);
+ rv = OpenEntry(call.key, call.entry, copyable_callback);
break;
case DOOM:
- rv = DoomEntry(call.key, call.callback);
+ rv = DoomEntry(call.key, copyable_callback);
break;
default:
NOTREACHED();
break;
}
if (rv != net::ERR_IO_PENDING)
- call.callback.Run(rv);
+ copyable_callback.Run(rv);
}
pending_calls_.clear();
}
diff --git a/chromium/content/browser/appcache/appcache_disk_cache.h b/chromium/content/browser/appcache/appcache_disk_cache.h
index 5eba6053397..73bccf9d2f9 100644
--- a/chromium/content/browser/appcache/appcache_disk_cache.h
+++ b/chromium/content/browser/appcache/appcache_disk_cache.h
@@ -15,6 +15,7 @@
#include "base/memory/ref_counted.h"
#include "content/browser/appcache/appcache_response.h"
#include "content/common/content_export.h"
+#include "net/base/completion_once_callback.h"
#include "net/disk_cache/disk_cache.h"
namespace content {
@@ -32,23 +33,23 @@ class CONTENT_EXPORT AppCacheDiskCache
int disk_cache_size,
bool force,
base::OnceClosure post_cleanup_callback,
- const net::CompletionCallback& callback);
+ net::CompletionOnceCallback callback);
// Initializes the object to use memory only storage.
// This is used for Chrome's incognito browsing.
int InitWithMemBackend(int disk_cache_size,
- const net::CompletionCallback& callback);
+ net::CompletionOnceCallback callback);
void Disable();
bool is_disabled() const { return is_disabled_; }
int CreateEntry(int64_t key,
Entry** entry,
- const net::CompletionCallback& callback) override;
+ net::CompletionOnceCallback callback) override;
int OpenEntry(int64_t key,
Entry** entry,
- const net::CompletionCallback& callback) override;
- int DoomEntry(int64_t key, const net::CompletionCallback& callback) override;
+ net::CompletionOnceCallback callback) override;
+ int DoomEntry(int64_t key, net::CompletionOnceCallback callback) override;
void set_is_waiting_to_initialize(bool is_waiting_to_initialize) {
is_waiting_to_initialize_ = is_waiting_to_initialize;
@@ -73,21 +74,19 @@ class CONTENT_EXPORT AppCacheDiskCache
DOOM
};
struct PendingCall {
- PendingCallType call_type;
- int64_t key;
- Entry** entry;
- net::CompletionCallback callback;
-
PendingCall();
-
PendingCall(PendingCallType call_type,
int64_t key,
Entry** entry,
- const net::CompletionCallback& callback);
-
- PendingCall(const PendingCall& other);
+ net::CompletionOnceCallback callback);
+ PendingCall(PendingCall&& other);
~PendingCall();
+
+ PendingCallType call_type;
+ int64_t key;
+ Entry** entry;
+ net::CompletionOnceCallback callback;
};
using PendingCalls = std::vector<PendingCall>;
@@ -104,7 +103,7 @@ class CONTENT_EXPORT AppCacheDiskCache
int cache_size,
bool force,
base::OnceClosure post_cleanup_callback,
- const net::CompletionCallback& callback);
+ net::CompletionOnceCallback callback);
void OnCreateBackendComplete(int rv);
void AddOpenEntry(EntryImpl* entry) { open_entries_.insert(entry); }
void RemoveOpenEntry(EntryImpl* entry) { open_entries_.erase(entry); }
@@ -112,7 +111,7 @@ class CONTENT_EXPORT AppCacheDiskCache
bool use_simple_cache_;
bool is_disabled_;
bool is_waiting_to_initialize_;
- net::CompletionCallback init_callback_;
+ net::CompletionOnceCallback init_callback_;
scoped_refptr<CreateBackendCallbackShim> create_backend_callback_;
PendingCalls pending_calls_;
OpenEntries open_entries_;
diff --git a/chromium/content/browser/appcache/appcache_disk_cache_unittest.cc b/chromium/content/browser/appcache/appcache_disk_cache_unittest.cc
index 321ad52d4f1..f6e4cf492d9 100644
--- a/chromium/content/browser/appcache/appcache_disk_cache_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_disk_cache_unittest.cc
@@ -10,6 +10,7 @@
#include "base/single_thread_task_runner.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "net/base/completion_repeating_callback.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
@@ -24,9 +25,8 @@ class AppCacheDiskCacheTest : public testing::Test {
void SetUp() override {
ASSERT_TRUE(directory_.CreateUniqueTempDir());
- completion_callback_ = base::Bind(
- &AppCacheDiskCacheTest::OnComplete,
- base::Unretained(this));
+ completion_callback_ = base::BindRepeating(
+ &AppCacheDiskCacheTest::OnComplete, base::Unretained(this));
}
void TearDown() override { scoped_task_environment_.RunUntilIdle(); }
@@ -42,7 +42,7 @@ class AppCacheDiskCacheTest : public testing::Test {
base::test::ScopedTaskEnvironment scoped_task_environment_;
base::ScopedTempDir directory_;
- net::CompletionCallback completion_callback_;
+ net::CompletionRepeatingCallback completion_callback_;
std::vector<int> completion_results_;
static const int k10MBytes = 10 * 1024 * 1024;
diff --git a/chromium/content/browser/appcache/appcache_dispatcher_host.cc b/chromium/content/browser/appcache/appcache_dispatcher_host.cc
index 966ab0e1271..479fddbd61b 100644
--- a/chromium/content/browser/appcache/appcache_dispatcher_host.cc
+++ b/chromium/content/browser/appcache/appcache_dispatcher_host.cc
@@ -89,7 +89,7 @@ void AppCacheDispatcherHost::SelectCache(int32_t host_id,
mojo::ReportBadMessage("ACDH_SELECT_CACHE");
}
} else {
- frontend_proxy_.OnCacheSelected(host_id, std::move(AppCacheInfo()));
+ frontend_proxy_.OnCacheSelected(host_id, AppCacheInfo());
}
}
@@ -99,7 +99,7 @@ void AppCacheDispatcherHost::SelectCacheForSharedWorker(int32_t host_id,
if (!backend_impl_.SelectCacheForSharedWorker(host_id, appcache_id))
mojo::ReportBadMessage("ACDH_SELECT_CACHE_FOR_SHARED_WORKER");
} else {
- frontend_proxy_.OnCacheSelected(host_id, std::move(AppCacheInfo()));
+ frontend_proxy_.OnCacheSelected(host_id, AppCacheInfo());
}
}
diff --git a/chromium/content/browser/appcache/appcache_group.cc b/chromium/content/browser/appcache/appcache_group.cc
index 85e6be0e7e7..6a83480f298 100644
--- a/chromium/content/browser/appcache/appcache_group.cc
+++ b/chromium/content/browser/appcache/appcache_group.cc
@@ -114,9 +114,9 @@ void AppCacheGroup::AddCache(AppCache* complete_cache) {
void AppCacheGroup::RemoveCache(AppCache* cache) {
DCHECK(cache->associated_hosts().empty());
if (cache == newest_complete_cache_) {
- CancelUpdate();
AppCache* tmp_cache = newest_complete_cache_;
newest_complete_cache_ = nullptr;
+ CancelUpdate();
tmp_cache->set_owning_group(nullptr); // may cause this group to be deleted
} else {
scoped_refptr<AppCacheGroup> protect(this);
@@ -227,7 +227,7 @@ void AppCacheGroup::RunQueuedUpdates() {
// static
bool AppCacheGroup::FindObserver(
const UpdateObserver* find_me,
- const base::ObserverList<UpdateObserver>& observer_list) {
+ const base::ObserverList<UpdateObserver>::Unchecked& observer_list) {
return observer_list.HasObserver(find_me);
}
diff --git a/chromium/content/browser/appcache/appcache_group.h b/chromium/content/browser/appcache/appcache_group.h
index c119f59274d..9d20a731566 100644
--- a/chromium/content/browser/appcache/appcache_group.h
+++ b/chromium/content/browser/appcache/appcache_group.h
@@ -145,7 +145,7 @@ class CONTENT_EXPORT AppCacheGroup
void RunQueuedUpdates();
static bool FindObserver(
const UpdateObserver* find_me,
- const base::ObserverList<UpdateObserver>& observer_list);
+ const base::ObserverList<UpdateObserver>::Unchecked& observer_list);
void ScheduleUpdateRestart(int delay_ms);
void HostDestructionImminent(AppCacheHost* host);
@@ -179,11 +179,11 @@ class CONTENT_EXPORT AppCacheGroup
AppCacheStorage* storage_;
// List of objects observing this group.
- base::ObserverList<UpdateObserver> observers_;
+ base::ObserverList<UpdateObserver>::Unchecked observers_;
// Updates that have been queued for the next run.
QueuedUpdates queued_updates_;
- base::ObserverList<UpdateObserver> queued_observers_;
+ base::ObserverList<UpdateObserver>::Unchecked queued_observers_;
base::CancelableClosure restart_update_task_;
std::unique_ptr<HostObserver> host_observer_;
diff --git a/chromium/content/browser/appcache/appcache_histograms.cc b/chromium/content/browser/appcache/appcache_histograms.cc
index 6027c8c650a..110ffdf5261 100644
--- a/chromium/content/browser/appcache/appcache_histograms.cc
+++ b/chromium/content/browser/appcache/appcache_histograms.cc
@@ -132,21 +132,6 @@ void AppCacheHistograms::AddCompletionRunTimeSample(
UMA_HISTOGRAM_TIMES("appcache.CompletionRunTime", duration);
}
-void AppCacheHistograms::AddNetworkJobStartDelaySample(
- const base::TimeDelta& duration) {
- UMA_HISTOGRAM_TIMES("appcache.JobStartDelay.Network", duration);
-}
-
-void AppCacheHistograms::AddErrorJobStartDelaySample(
- const base::TimeDelta& duration) {
- UMA_HISTOGRAM_TIMES("appcache.JobStartDelay.Error", duration);
-}
-
-void AppCacheHistograms::AddAppCacheJobStartDelaySample(
- const base::TimeDelta& duration) {
- UMA_HISTOGRAM_TIMES("appcache.JobStartDelay.AppCache", duration);
-}
-
void AppCacheHistograms::AddMissingManifestEntrySample() {
UMA_HISTOGRAM_BOOLEAN("appcache.MissingManifestEntry", true);
}
diff --git a/chromium/content/browser/appcache/appcache_histograms.h b/chromium/content/browser/appcache/appcache_histograms.h
index 043d6d9a4fc..6414d9f3edc 100644
--- a/chromium/content/browser/appcache/appcache_histograms.h
+++ b/chromium/content/browser/appcache/appcache_histograms.h
@@ -46,9 +46,6 @@ class AppCacheHistograms {
static void AddTaskRunTimeSample(const base::TimeDelta& duration);
static void AddCompletionQueueTimeSample(const base::TimeDelta& duration);
static void AddCompletionRunTimeSample(const base::TimeDelta& duration);
- static void AddNetworkJobStartDelaySample(const base::TimeDelta& duration);
- static void AddErrorJobStartDelaySample(const base::TimeDelta& duration);
- static void AddAppCacheJobStartDelaySample(const base::TimeDelta& duration);
static void AddMissingManifestEntrySample();
enum MissingManifestCallsiteType {
diff --git a/chromium/content/browser/appcache/appcache_host.cc b/chromium/content/browser/appcache/appcache_host.cc
index 2b27d83d316..f82d1f76585 100644
--- a/chromium/content/browser/appcache/appcache_host.cc
+++ b/chromium/content/browser/appcache/appcache_host.cc
@@ -4,6 +4,8 @@
#include "content/browser/appcache/appcache_host.h"
+#include <vector>
+
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string_util.h"
@@ -24,29 +26,31 @@ namespace content {
namespace {
-void FillCacheInfo(const AppCache* cache,
- const GURL& manifest_url,
- AppCacheStatus status, AppCacheInfo* info) {
- info->manifest_url = manifest_url;
- info->status = status;
+AppCacheInfo CreateCacheInfo(const AppCache* cache,
+ const GURL& manifest_url,
+ AppCacheStatus status) {
+ AppCacheInfo info;
+ info.manifest_url = manifest_url;
+ info.status = status;
if (!cache)
- return;
+ return info;
- info->cache_id = cache->cache_id();
+ info.cache_id = cache->cache_id();
if (!cache->is_complete())
- return;
+ return info;
DCHECK(cache->owning_group());
- info->is_complete = true;
- info->group_id = cache->owning_group()->group_id();
- info->last_update_time = cache->update_time();
- info->creation_time = cache->owning_group()->creation_time();
- info->size = cache->cache_size();
+ info.is_complete = true;
+ info.group_id = cache->owning_group()->group_id();
+ info.last_update_time = cache->update_time();
+ info.creation_time = cache->owning_group()->creation_time();
+ info.size = cache->cache_size();
+ return info;
}
-} // Anonymous namespace
+} // namespace
AppCacheHost::AppCacheHost(int host_id,
AppCacheFrontend* frontend,
@@ -317,7 +321,7 @@ std::unique_ptr<AppCacheRequestHandler> AppCacheHost::CreateRequestHandler(
}
void AppCacheHost::GetResourceList(
- AppCacheResourceInfoVector* resource_infos) {
+ std::vector<AppCacheResourceInfo>* resource_infos) {
if (associated_cache_.get() && associated_cache_->is_complete())
associated_cache_->ToResourceInfoVector(resource_infos);
}
@@ -463,9 +467,8 @@ void AppCacheHost::OnUpdateComplete(AppCacheGroup* group) {
if (associated_cache_info_pending_ && associated_cache_.get() &&
associated_cache_->is_complete()) {
- AppCacheInfo info;
- FillCacheInfo(
- associated_cache_.get(), preferred_manifest_url_, GetStatus(), &info);
+ AppCacheInfo info = CreateCacheInfo(associated_cache_.get(),
+ preferred_manifest_url_, GetStatus());
associated_cache_info_pending_ = false;
// In the network service world, we need to pass the URLLoaderFactory
// instance to the renderer which it can use to request subresources.
@@ -562,11 +565,10 @@ void AppCacheHost::AssociateCacheHelper(AppCache* cache,
associated_cache_ = cache;
SetSwappableCache(cache ? cache->owning_group() : nullptr);
associated_cache_info_pending_ = cache && !cache->is_complete();
- AppCacheInfo info;
if (cache)
cache->AssociateHost(this);
- FillCacheInfo(cache, manifest_url, GetStatus(), &info);
+ AppCacheInfo info = CreateCacheInfo(cache, manifest_url, GetStatus());
// In the network service world, we need to pass the URLLoaderFactory
// instance to the renderer which it can use to request subresources.
// This ensures that they can be served out of the AppCache.
diff --git a/chromium/content/browser/appcache/appcache_host.h b/chromium/content/browser/appcache/appcache_host.h
index e5d29763fda..ee149def125 100644
--- a/chromium/content/browser/appcache/appcache_host.h
+++ b/chromium/content/browser/appcache/appcache_host.h
@@ -340,7 +340,7 @@ class CONTENT_EXPORT AppCacheHost
bool associated_cache_info_pending_;
// List of objects observing us.
- base::ObserverList<Observer> observers_;
+ base::ObserverList<Observer>::Unchecked observers_;
// Used to inform the QuotaManager of what origins are currently in use.
url::Origin origin_in_use_;
diff --git a/chromium/content/browser/appcache/appcache_host_unittest.cc b/chromium/content/browser/appcache/appcache_host_unittest.cc
index 85c35283e29..64f9bcfec8d 100644
--- a/chromium/content/browser/appcache/appcache_host_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_host_unittest.cc
@@ -180,8 +180,8 @@ TEST_F(AppCacheHostTest, Basic) {
}
TEST_F(AppCacheHostTest, SelectNoCache) {
- scoped_refptr<MockQuotaManagerProxy> mock_quota_proxy(
- new MockQuotaManagerProxy);
+ scoped_refptr<MockQuotaManagerProxy> mock_quota_proxy =
+ base::MakeRefCounted<MockQuotaManagerProxy>();
service_.set_quota_manager_proxy(mock_quota_proxy.get());
// Reset our mock frontend
@@ -255,7 +255,8 @@ TEST_F(AppCacheHostTest, ForeignFallbackEntry) {
// Precondition, a cache with a fallback entry that is not marked as foreign.
const int kCacheId = 22;
const GURL kFallbackURL("http://origin/fallback_resource");
- scoped_refptr<AppCache> cache = new AppCache(service_.storage(), kCacheId);
+ scoped_refptr<AppCache> cache =
+ base::MakeRefCounted<AppCache>(service_.storage(), kCacheId);
cache->AddEntry(kFallbackURL, AppCacheEntry(AppCacheEntry::FALLBACK));
AppCacheHost host(1, &mock_frontend_, &service_);
@@ -341,20 +342,22 @@ TEST_F(AppCacheHostTest, SetSwappableCache) {
host.SetSwappableCache(nullptr);
EXPECT_FALSE(host.swappable_cache_.get());
- scoped_refptr<AppCacheGroup> group1(new AppCacheGroup(
- service_.storage(), GURL(), service_.storage()->NewGroupId()));
+ const GURL kGroup1ManifestUrl("http://bar.com");
+ scoped_refptr<AppCacheGroup> group1 = base::MakeRefCounted<AppCacheGroup>(
+ service_.storage(), kGroup1ManifestUrl, service_.storage()->NewGroupId());
host.SetSwappableCache(group1.get());
EXPECT_FALSE(host.swappable_cache_.get());
- AppCache* cache1 = new AppCache(service_.storage(), 111);
+ scoped_refptr<AppCache> cache1 =
+ base::MakeRefCounted<AppCache>(service_.storage(), 111);
cache1->set_complete(true);
- group1->AddCache(cache1);
+ group1->AddCache(cache1.get());
host.SetSwappableCache(group1.get());
EXPECT_EQ(cache1, host.swappable_cache_.get());
mock_frontend_.last_host_id_ = -222; // to verify we received OnCacheSelected
- host.AssociateCompleteCache(cache1);
+ host.AssociateCompleteCache(cache1.get());
EXPECT_FALSE(host.swappable_cache_.get()); // was same as associated cache
EXPECT_EQ(AppCacheStatus::APPCACHE_STATUS_IDLE, host.GetStatus());
// verify OnCacheSelected was called
@@ -362,41 +365,52 @@ TEST_F(AppCacheHostTest, SetSwappableCache) {
EXPECT_EQ(cache1->cache_id(), mock_frontend_.last_cache_id_);
EXPECT_EQ(AppCacheStatus::APPCACHE_STATUS_IDLE, mock_frontend_.last_status_);
- AppCache* cache2 = new AppCache(service_.storage(), 222);
+ scoped_refptr<AppCache> cache2 =
+ base::MakeRefCounted<AppCache>(service_.storage(), 222);
cache2->set_complete(true);
- group1->AddCache(cache2);
- EXPECT_EQ(cache2, host.swappable_cache_.get()); // updated to newest
-
- scoped_refptr<AppCacheGroup> group2(
- new AppCacheGroup(service_.storage(), GURL("http://foo.com"),
- service_.storage()->NewGroupId()));
- AppCache* cache3 = new AppCache(service_.storage(), 333);
+ group1->AddCache(cache2.get());
+ EXPECT_EQ(cache2.get(), host.swappable_cache_.get()); // updated to newest
+
+ const GURL kGroup2ManifestUrl("http://foo.com/");
+ scoped_refptr<AppCacheGroup> group2 = base::MakeRefCounted<AppCacheGroup>(
+ service_.storage(), kGroup2ManifestUrl, service_.storage()->NewGroupId());
+ scoped_refptr<AppCache> cache3 =
+ base::MakeRefCounted<AppCache>(service_.storage(), 333);
cache3->set_complete(true);
- group2->AddCache(cache3);
+ group2->AddCache(cache3.get());
- AppCache* cache4 = new AppCache(service_.storage(), 444);
+ scoped_refptr<AppCache> cache4 =
+ base::MakeRefCounted<AppCache>(service_.storage(), 444);
cache4->set_complete(true);
- group2->AddCache(cache4);
- EXPECT_EQ(cache2, host.swappable_cache_.get()); // unchanged
+ group2->AddCache(cache4.get());
+ EXPECT_EQ(cache2.get(), host.swappable_cache_.get()); // unchanged
- host.AssociateCompleteCache(cache3);
- EXPECT_EQ(cache4, host.swappable_cache_.get()); // newest cache in group2
+ cache1.reset();
+ cache2.reset();
+
+ host.AssociateCompleteCache(cache3.get());
+ EXPECT_EQ(cache4.get(),
+ host.swappable_cache_.get()); // newest cache in group2
EXPECT_FALSE(group1->HasCache()); // both caches in group1 have refcount 0
- host.AssociateNoCache(GURL());
+ cache3.reset();
+ cache4.reset();
+
+ host.AssociateNoCache(kGroup1ManifestUrl);
EXPECT_FALSE(host.swappable_cache_.get());
EXPECT_FALSE(group2->HasCache()); // both caches in group2 have refcount 0
// Host adds reference to newest cache when an update is complete.
- AppCache* cache5 = new AppCache(service_.storage(), 555);
+ scoped_refptr<AppCache> cache5 =
+ base::MakeRefCounted<AppCache>(service_.storage(), 555);
cache5->set_complete(true);
- group2->AddCache(cache5);
+ group2->AddCache(cache5.get());
host.group_being_updated_ = group2;
host.OnUpdateComplete(group2.get());
EXPECT_FALSE(host.group_being_updated_.get());
- EXPECT_EQ(cache5, host.swappable_cache_.get());
+ EXPECT_EQ(cache5.get(), host.swappable_cache_.get());
- group2->RemoveCache(cache5);
+ group2->RemoveCache(cache5.get());
EXPECT_FALSE(group2->HasCache());
host.group_being_updated_ = group2;
host.OnUpdateComplete(group2.get());
@@ -405,8 +419,8 @@ TEST_F(AppCacheHostTest, SetSwappableCache) {
}
TEST_F(AppCacheHostTest, SelectCacheAllowed) {
- scoped_refptr<MockQuotaManagerProxy> mock_quota_proxy(
- new MockQuotaManagerProxy);
+ scoped_refptr<MockQuotaManagerProxy> mock_quota_proxy =
+ base::MakeRefCounted<MockQuotaManagerProxy>();
MockAppCachePolicy mock_appcache_policy;
mock_appcache_policy.can_create_return_value_ = true;
service_.set_quota_manager_proxy(mock_quota_proxy.get());
@@ -446,8 +460,8 @@ TEST_F(AppCacheHostTest, SelectCacheAllowed) {
}
TEST_F(AppCacheHostTest, SelectCacheBlocked) {
- scoped_refptr<MockQuotaManagerProxy> mock_quota_proxy(
- new MockQuotaManagerProxy);
+ scoped_refptr<MockQuotaManagerProxy> mock_quota_proxy =
+ base::MakeRefCounted<MockQuotaManagerProxy>();
MockAppCachePolicy mock_appcache_policy;
mock_appcache_policy.can_create_return_value_ = false;
service_.set_quota_manager_proxy(mock_quota_proxy.get());
diff --git a/chromium/content/browser/appcache/appcache_internals_ui.cc b/chromium/content/browser/appcache/appcache_internals_ui.cc
index f33713440f4..d95dcaf3494 100644
--- a/chromium/content/browser/appcache/appcache_internals_ui.cc
+++ b/chromium/content/browser/appcache/appcache_internals_ui.cc
@@ -127,7 +127,7 @@ GetDictionaryValueForAppCacheResourceInfo(
}
std::unique_ptr<base::ListValue> GetListValueForAppCacheResourceInfoVector(
- AppCacheResourceInfoVector* resource_info_vector) {
+ std::vector<AppCacheResourceInfo>* resource_info_vector) {
std::unique_ptr<base::ListValue> list(new base::ListValue);
for (const AppCacheResourceInfo& res_info : *resource_info_vector)
list->Append(GetDictionaryValueForAppCacheResourceInfo(res_info));
@@ -238,9 +238,9 @@ void AppCacheInternalsUI::Proxy::RequestAppCacheDetails(
void AppCacheInternalsUI::Proxy::OnGroupLoaded(AppCacheGroup* appcache_group,
const GURL& manifest_gurl) {
- std::unique_ptr<AppCacheResourceInfoVector> resource_info_vector;
+ std::unique_ptr<std::vector<AppCacheResourceInfo>> resource_info_vector;
if (appcache_group && appcache_group->newest_complete_cache()) {
- resource_info_vector.reset(new AppCacheResourceInfoVector);
+ resource_info_vector.reset(new std::vector<AppCacheResourceInfo>);
appcache_group->newest_complete_cache()->ToResourceInfoVector(
resource_info_vector.get());
std::sort(resource_info_vector->begin(), resource_info_vector->end(),
@@ -445,7 +445,7 @@ void AppCacheInternalsUI::OnAppCacheInfoDeleted(
void AppCacheInternalsUI::OnAppCacheDetailsReady(
const base::FilePath& partition_path,
const std::string& manifest_url,
- std::unique_ptr<AppCacheResourceInfoVector> resource_info_vector) {
+ std::unique_ptr<std::vector<AppCacheResourceInfo>> resource_info_vector) {
if (resource_info_vector) {
web_ui()->CallJavascriptFunctionUnsafe(
kFunctionOnAppCacheDetailsReady, base::Value(manifest_url),
@@ -464,25 +464,22 @@ void AppCacheInternalsUI::OnFileDetailsReady(
scoped_refptr<net::IOBuffer> response_data,
int data_length) {
std::string headers;
- if (response_info->http_response_info()) {
- headers.append("<hr><pre>");
- headers.append(net::EscapeForHTML(
- response_info->http_response_info()->headers->GetStatusLine()));
+ headers.append("<hr><pre>");
+ headers.append(net::EscapeForHTML(
+ response_info->http_response_info().headers->GetStatusLine()));
+ headers.push_back('\n');
+
+ size_t iter = 0;
+ std::string name, value;
+ while (response_info->http_response_info().headers->EnumerateHeaderLines(
+ &iter, &name, &value)) {
+ headers.append(net::EscapeForHTML(name));
+ headers.append(": ");
+ headers.append(net::EscapeForHTML(value));
headers.push_back('\n');
-
- size_t iter = 0;
- std::string name, value;
- while (response_info->http_response_info()->headers->EnumerateHeaderLines(
- &iter, &name, &value)) {
- headers.append(net::EscapeForHTML(name));
- headers.append(": ");
- headers.append(net::EscapeForHTML(value));
- headers.push_back('\n');
- }
- headers.append("</pre>");
- } else {
- headers.append("Failed to read response headers. <br>");
}
+ headers.append("</pre>");
+
std::string hex_dump = base::StringPrintf(
"<hr><pre> Showing %d of %d bytes\n\n", static_cast<int>(data_length),
static_cast<int>(response_info->response_data_size()));
diff --git a/chromium/content/browser/appcache/appcache_internals_ui.h b/chromium/content/browser/appcache/appcache_internals_ui.h
index 5fdf4a308c4..930361f0957 100644
--- a/chromium/content/browser/appcache/appcache_internals_ui.h
+++ b/chromium/content/browser/appcache/appcache_internals_ui.h
@@ -9,6 +9,7 @@
#include <list>
#include <memory>
+#include <vector>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
@@ -108,7 +109,7 @@ class AppCacheInternalsUI : public WebUIController {
void OnAppCacheDetailsReady(
const base::FilePath& partition_path,
const std::string& manifest_url,
- std::unique_ptr<AppCacheResourceInfoVector> resource_info_vector);
+ std::unique_ptr<std::vector<AppCacheResourceInfo>> resource_info_vector);
void OnFileDetailsReady(const Proxy::ResponseEnquiry& response_enquiry,
scoped_refptr<AppCacheResponseInfo> response_info,
scoped_refptr<net::IOBuffer> response_data,
diff --git a/chromium/content/browser/appcache/appcache_job.cc b/chromium/content/browser/appcache/appcache_job.cc
index 24312c7de5b..20fcaed3a65 100644
--- a/chromium/content/browser/appcache/appcache_job.cc
+++ b/chromium/content/browser/appcache/appcache_job.cc
@@ -84,8 +84,8 @@ void AppCacheJob::SetupRangeResponse() {
// Make a copy of the full response headers and fix them up
// for the range we'll be returning.
- range_response_info_.reset(
- new net::HttpResponseInfo(*info_->http_response_info()));
+ range_response_info_ =
+ std::make_unique<net::HttpResponseInfo>(info_->http_response_info());
net::HttpResponseHeaders* headers = range_response_info_->headers.get();
headers->UpdateWithNewRange(range_requested_, resource_size,
true /* replace status line */);
diff --git a/chromium/content/browser/appcache/appcache_manifest_parser.h b/chromium/content/browser/appcache/appcache_manifest_parser.h
index 75f7fe8356c..016655b25e9 100644
--- a/chromium/content/browser/appcache/appcache_manifest_parser.h
+++ b/chromium/content/browser/appcache/appcache_manifest_parser.h
@@ -48,9 +48,9 @@ struct CONTENT_EXPORT AppCacheManifest {
~AppCacheManifest();
base::hash_set<std::string> explicit_urls;
- AppCacheNamespaceVector intercept_namespaces;
- AppCacheNamespaceVector fallback_namespaces;
- AppCacheNamespaceVector online_whitelist_namespaces;
+ std::vector<AppCacheNamespace> intercept_namespaces;
+ std::vector<AppCacheNamespace> fallback_namespaces;
+ std::vector<AppCacheNamespace> online_whitelist_namespaces;
bool online_whitelist_all = false;
bool did_ignore_intercept_namespaces = false;
bool did_ignore_fallback_namespaces = false;
diff --git a/chromium/content/browser/appcache/appcache_manifest_parser_unittest.cc b/chromium/content/browser/appcache/appcache_manifest_parser_unittest.cc
index caa0264b770..5ca2d3ac9e1 100644
--- a/chromium/content/browser/appcache/appcache_manifest_parser_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_manifest_parser_unittest.cc
@@ -5,6 +5,7 @@
#include <stddef.h>
#include <string>
+#include <vector>
#include "base/macros.h"
#include "content/browser/appcache/appcache_manifest_parser.h"
@@ -174,7 +175,8 @@ TEST(AppCacheManifestParserTest, WhitelistUrls) {
EXPECT_FALSE(manifest.did_ignore_intercept_namespaces);
EXPECT_FALSE(manifest.did_ignore_fallback_namespaces);
- const AppCacheNamespaceVector& online = manifest.online_whitelist_namespaces;
+ const std::vector<AppCacheNamespace>& online =
+ manifest.online_whitelist_namespaces;
const size_t kExpected = 6;
ASSERT_EQ(kExpected, online.size());
EXPECT_EQ(APPCACHE_NETWORK_NAMESPACE, online[0].type);
@@ -223,7 +225,8 @@ TEST(AppCacheManifestParserTest, FallbackUrls) {
EXPECT_FALSE(manifest.did_ignore_intercept_namespaces);
EXPECT_FALSE(manifest.did_ignore_fallback_namespaces);
- const AppCacheNamespaceVector& fallbacks = manifest.fallback_namespaces;
+ const std::vector<AppCacheNamespace>& fallbacks =
+ manifest.fallback_namespaces;
const size_t kExpected = 5;
ASSERT_EQ(kExpected, fallbacks.size());
EXPECT_EQ(APPCACHE_FALLBACK_NAMESPACE, fallbacks[0].type);
@@ -281,7 +284,8 @@ TEST(AppCacheManifestParserTest, FallbackUrlsWithPort) {
EXPECT_TRUE(manifest.online_whitelist_namespaces.empty());
EXPECT_FALSE(manifest.online_whitelist_all);
- const AppCacheNamespaceVector& fallbacks = manifest.fallback_namespaces;
+ const std::vector<AppCacheNamespace>& fallbacks =
+ manifest.fallback_namespaces;
const size_t kExpected = 3;
ASSERT_EQ(kExpected, fallbacks.size());
EXPECT_EQ(APPCACHE_FALLBACK_NAMESPACE, fallbacks[0].type);
@@ -334,7 +338,8 @@ TEST(AppCacheManifestParserTest, InterceptUrls) {
EXPECT_FALSE(manifest.did_ignore_intercept_namespaces);
EXPECT_FALSE(manifest.did_ignore_fallback_namespaces);
- const AppCacheNamespaceVector& intercepts = manifest.intercept_namespaces;
+ const std::vector<AppCacheNamespace>& intercepts =
+ manifest.intercept_namespaces;
const size_t kExpected = 3;
ASSERT_EQ(kExpected, intercepts.size());
EXPECT_EQ(APPCACHE_INTERCEPT_NAMESPACE, intercepts[0].type);
@@ -401,7 +406,8 @@ TEST(AppCacheManifestParserTest, ComboUrls) {
EXPECT_TRUE(urls.find("http://combo.com:99/explicit-2") != urls.end());
EXPECT_TRUE(urls.find("http://www.diff.com/explicit-3") != urls.end());
- const AppCacheNamespaceVector& online = manifest.online_whitelist_namespaces;
+ const std::vector<AppCacheNamespace>& online =
+ manifest.online_whitelist_namespaces;
expected = 4;
ASSERT_EQ(expected, online.size());
EXPECT_EQ(GURL("http://combo.com/whitelist-1"),
@@ -413,7 +419,8 @@ TEST(AppCacheManifestParserTest, ComboUrls) {
EXPECT_EQ(GURL("http://combo.com:99/whitelist-4"),
online[3].namespace_url);
- const AppCacheNamespaceVector& fallbacks = manifest.fallback_namespaces;
+ const std::vector<AppCacheNamespace>& fallbacks =
+ manifest.fallback_namespaces;
expected = 2;
ASSERT_EQ(expected, fallbacks.size());
EXPECT_EQ(APPCACHE_FALLBACK_NAMESPACE, fallbacks[0].type);
diff --git a/chromium/content/browser/appcache/appcache_quota_client.cc b/chromium/content/browser/appcache/appcache_quota_client.cc
index 378bb0efe92..c9266e4e7b9 100644
--- a/chromium/content/browser/appcache/appcache_quota_client.cc
+++ b/chromium/content/browser/appcache/appcache_quota_client.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include <map>
#include <set>
+#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
@@ -207,15 +208,16 @@ const AppCacheStorage::UsageMap* AppCacheQuotaClient::GetUsageMap() {
return service_->storage()->usage_map();
}
-net::CancelableCompletionCallback*
+net::CancelableCompletionRepeatingCallback*
AppCacheQuotaClient::GetServiceDeleteCallback() {
- // Lazily created due to CancelableCompletionCallback's threading
- // restrictions, there is no way to detach from the thread created on.
+ // Lazily created due to base::CancelableCallback's threading restrictions,
+ // there is no way to detach from the thread created on.
if (!service_delete_callback_) {
- service_delete_callback_.reset(
- new net::CancelableCompletionCallback(
- base::Bind(&AppCacheQuotaClient::DidDeleteAppCachesForOrigin,
- base::Unretained(this))));
+ service_delete_callback_ =
+ std::make_unique<net::CancelableCompletionRepeatingCallback>(
+ base::BindRepeating(
+ &AppCacheQuotaClient::DidDeleteAppCachesForOrigin,
+ base::Unretained(this)));
}
return service_delete_callback_.get();
}
diff --git a/chromium/content/browser/appcache/appcache_quota_client.h b/chromium/content/browser/appcache/appcache_quota_client.h
index d40424dcea3..a5dc1e63064 100644
--- a/chromium/content/browser/appcache/appcache_quota_client.h
+++ b/chromium/content/browser/appcache/appcache_quota_client.h
@@ -14,7 +14,7 @@
#include "base/memory/ref_counted.h"
#include "content/browser/appcache/appcache_storage.h"
#include "content/common/content_export.h"
-#include "net/base/completion_callback.h"
+#include "net/base/completion_repeating_callback.h"
#include "storage/browser/quota/quota_client.h"
#include "storage/browser/quota/quota_task.h"
#include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
@@ -67,7 +67,7 @@ class AppCacheQuotaClient : public storage::QuotaClient {
void ProcessPendingRequests();
void DeletePendingRequests();
const AppCacheStorage::UsageMap* GetUsageMap();
- net::CancelableCompletionCallback* GetServiceDeleteCallback();
+ net::CancelableCompletionRepeatingCallback* GetServiceDeleteCallback();
// For use by appcache internals during initialization and shutdown.
CONTENT_EXPORT void NotifyAppCacheReady();
@@ -81,7 +81,8 @@ class AppCacheQuotaClient : public storage::QuotaClient {
// And once it's ready, we can only handle one delete request at a time,
// so we queue up additional requests while one is in already in progress.
DeletionCallback current_delete_request_callback_;
- std::unique_ptr<net::CancelableCompletionCallback> service_delete_callback_;
+ std::unique_ptr<net::CancelableCompletionRepeatingCallback>
+ service_delete_callback_;
AppCacheServiceImpl* service_;
bool appcache_is_ready_;
diff --git a/chromium/content/browser/appcache/appcache_request_handler.cc b/chromium/content/browser/appcache/appcache_request_handler.cc
index 7f291f904b0..459c79ab482 100644
--- a/chromium/content/browser/appcache/appcache_request_handler.cc
+++ b/chromium/content/browser/appcache/appcache_request_handler.cc
@@ -222,17 +222,17 @@ void AppCacheRequestHandler::GetExtraResponseInfo(int64_t* cache_id,
// static
std::unique_ptr<AppCacheRequestHandler>
-AppCacheRequestHandler::InitializeForNavigationNetworkService(
+AppCacheRequestHandler::InitializeForMainResourceNetworkService(
const network::ResourceRequest& request,
- AppCacheNavigationHandleCore* appcache_handle_core,
+ base::WeakPtr<AppCacheHost> appcache_host,
scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory) {
std::unique_ptr<AppCacheRequestHandler> handler =
- appcache_handle_core->host()->CreateRequestHandler(
+ appcache_host->CreateRequestHandler(
AppCacheURLLoaderRequest::Create(request),
static_cast<ResourceType>(request.resource_type),
request.should_reset_appcache);
handler->network_loader_factory_ = std::move(network_loader_factory);
- handler->appcache_host_ = appcache_handle_core->host()->GetWeakPtr();
+ handler->appcache_host_ = std::move(appcache_host);
return handler;
}
@@ -403,8 +403,8 @@ void AppCacheRequestHandler::OnMainResponseFound(
}
if (should_reset_appcache_ && !manifest_url.is_empty()) {
- host_->service()->DeleteAppCacheGroup(
- manifest_url, net::CompletionCallback());
+ host_->service()->DeleteAppCacheGroup(manifest_url,
+ net::CompletionOnceCallback());
DeliverNetworkResponse();
return;
}
@@ -546,13 +546,21 @@ void AppCacheRequestHandler::OnCacheSelectionComplete(AppCacheHost* host) {
}
void AppCacheRequestHandler::MaybeCreateLoader(
- const network::ResourceRequest& resource_request,
+ const network::ResourceRequest& tentative_resource_request,
ResourceContext* resource_context,
- LoaderCallback callback) {
+ LoaderCallback callback,
+ FallbackCallback fallback_callback) {
loader_callback_ =
base::BindOnce(&AppCacheRequestHandler::RunLoaderCallbackForMainResource,
weak_factory_.GetWeakPtr(), std::move(callback));
- request_->AsURLLoaderRequest()->set_request(resource_request);
+
+ // TODO(crbug.com/876531): Figure out how AppCache interception should
+ // interact with URLLoaderThrottles. It might be incorrect to store
+ // |tentative_resource_request| here, since throttles can rewrite headers
+ // between now and when the request handler passed to |loader_callback_| is
+ // invoked.
+ request_->AsURLLoaderRequest()->set_request(tentative_resource_request);
+
MaybeLoadResource(nullptr);
// If a job is created, the job assumes ownership of the callback and
// the responsibility to call it. If no job is created, we call it with
@@ -572,16 +580,19 @@ bool AppCacheRequestHandler::MaybeCreateLoaderForResponse(
// a loader to start.
bool was_called = false;
loader_callback_ = base::BindOnce(
- [](network::mojom::URLLoaderPtr* loader,
+ [](const network::ResourceRequest& resource_request,
+ network::mojom::URLLoaderPtr* loader,
network::mojom::URLLoaderClientRequest* client_request,
bool* was_called,
SingleRequestURLLoaderFactory::RequestHandler handler) {
*was_called = true;
network::mojom::URLLoaderClientPtr client;
*client_request = mojo::MakeRequest(&client);
- std::move(handler).Run(mojo::MakeRequest(loader), std::move(client));
+ std::move(handler).Run(resource_request, mojo::MakeRequest(loader),
+ std::move(client));
},
- loader, client_request, &was_called);
+ *(request_->AsURLLoaderRequest()->GetResourceRequest()), loader,
+ client_request, &was_called);
request_->AsURLLoaderRequest()->set_response(response);
if (!MaybeLoadFallbackForResponse(nullptr)) {
DCHECK(!was_called);
@@ -612,9 +623,13 @@ void AppCacheRequestHandler::MaybeCreateSubresourceLoader(
LoaderCallback loader_callback) {
DCHECK(!job_);
DCHECK(!is_main_resource());
+ // AppCache doesn't use the fallback_callback.
+ FallbackCallback fallback_callback = base::DoNothing();
+
// Subresource loads start out just like a main resource loads, but they go
// down different branches along the way to completion.
- MaybeCreateLoader(resource_request, nullptr, std::move(loader_callback));
+ MaybeCreateLoader(resource_request, nullptr, std::move(loader_callback),
+ std::move(fallback_callback));
}
void AppCacheRequestHandler::MaybeFallbackForSubresourceResponse(
diff --git a/chromium/content/browser/appcache/appcache_request_handler.h b/chromium/content/browser/appcache/appcache_request_handler.h
index b8b82668b0e..57362f43c43 100644
--- a/chromium/content/browser/appcache/appcache_request_handler.h
+++ b/chromium/content/browser/appcache/appcache_request_handler.h
@@ -33,7 +33,6 @@ struct ResourceResponseHead;
namespace content {
class AppCacheJob;
-class AppCacheNavigationHandleCore;
class AppCacheSubresourceURLFactory;
class AppCacheRequest;
class AppCacheRequestHandlerTest;
@@ -75,9 +74,11 @@ class CONTENT_EXPORT AppCacheRequestHandler
// MaybeLoadResource and MaybeLoadFallbackForResponse.
// Eventually one of the Deliver*Response() methods is called and the
// LoaderCallback is invoked.
- void MaybeCreateLoader(const network::ResourceRequest& resource_request,
- ResourceContext* resource_context,
- LoaderCallback callback) override;
+ void MaybeCreateLoader(
+ const network::ResourceRequest& tentative_resource_request,
+ ResourceContext* resource_context,
+ LoaderCallback callback,
+ FallbackCallback fallback_callback) override;
// MaybeCreateLoaderForResponse always returns synchronously.
bool MaybeCreateLoaderForResponse(
const network::ResourceResponseHead& response,
@@ -106,9 +107,9 @@ class CONTENT_EXPORT AppCacheRequestHandler
LoaderCallback callback);
static std::unique_ptr<AppCacheRequestHandler>
- InitializeForNavigationNetworkService(
+ InitializeForMainResourceNetworkService(
const network::ResourceRequest& request,
- AppCacheNavigationHandleCore* appcache_handle_core,
+ base::WeakPtr<AppCacheHost> appcache_host,
scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory);
static bool IsMainResourceType(ResourceType type) {
diff --git a/chromium/content/browser/appcache/appcache_response.cc b/chromium/content/browser/appcache/appcache_response.cc
index dd47432bcb6..15bb71504fb 100644
--- a/chromium/content/browser/appcache/appcache_response.cc
+++ b/chromium/content/browser/appcache/appcache_response.cc
@@ -6,6 +6,8 @@
#include <stddef.h>
+#include <utility>
+
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/compiler_specific.h"
@@ -17,7 +19,7 @@
#include "base/strings/string_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/browser/appcache/appcache_storage.h"
-#include "net/base/completion_callback.h"
+#include "net/base/completion_once_callback.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "storage/common/storage_histograms.h"
@@ -29,20 +31,19 @@ namespace {
// Disk cache entry data indices.
enum { kResponseInfoIndex, kResponseContentIndex, kResponseMetadataIndex };
-// An IOBuffer that wraps a pickle's data. Ownership of the
-// pickle is transfered to the WrappedPickleIOBuffer object.
+// An IOBuffer that wraps a pickle's data.
class WrappedPickleIOBuffer : public net::WrappedIOBuffer {
public:
- explicit WrappedPickleIOBuffer(const base::Pickle* pickle)
+ explicit WrappedPickleIOBuffer(std::unique_ptr<const base::Pickle> pickle)
: net::WrappedIOBuffer(reinterpret_cast<const char*>(pickle->data())),
- pickle_(pickle) {
- DCHECK(pickle->data());
+ pickle_(std::move(pickle)) {
+ DCHECK(pickle_->data());
}
private:
- ~WrappedPickleIOBuffer() override {}
+ ~WrappedPickleIOBuffer() override = default;
- std::unique_ptr<const base::Pickle> pickle_;
+ const std::unique_ptr<const base::Pickle> pickle_;
};
} // anon namespace
@@ -50,17 +51,18 @@ class WrappedPickleIOBuffer : public net::WrappedIOBuffer {
// AppCacheResponseInfo ----------------------------------------------
-AppCacheResponseInfo::AppCacheResponseInfo(AppCacheStorage* storage,
- const GURL& manifest_url,
- int64_t response_id,
- net::HttpResponseInfo* http_info,
- int64_t response_data_size)
+AppCacheResponseInfo::AppCacheResponseInfo(
+ AppCacheStorage* storage,
+ const GURL& manifest_url,
+ int64_t response_id,
+ std::unique_ptr<net::HttpResponseInfo> http_info,
+ int64_t response_data_size)
: manifest_url_(manifest_url),
response_id_(response_id),
- http_response_info_(http_info),
+ http_response_info_(std::move(http_info)),
response_data_size_(response_data_size),
storage_(storage) {
- DCHECK(http_info);
+ DCHECK(http_response_info_);
DCHECK(response_id != kAppCacheNoResponseId);
storage_->working_set()->AddResponseInfo(this);
}
@@ -74,10 +76,11 @@ AppCacheResponseInfo::~AppCacheResponseInfo() {
HttpResponseInfoIOBuffer::HttpResponseInfoIOBuffer()
: response_data_size(kUnkownResponseDataSize) {}
-HttpResponseInfoIOBuffer::HttpResponseInfoIOBuffer(net::HttpResponseInfo* info)
- : http_info(info), response_data_size(kUnkownResponseDataSize) {}
+HttpResponseInfoIOBuffer::HttpResponseInfoIOBuffer(
+ std::unique_ptr<net::HttpResponseInfo> info)
+ : http_info(std::move(info)), response_data_size(kUnkownResponseDataSize) {}
-HttpResponseInfoIOBuffer::~HttpResponseInfoIOBuffer() {}
+HttpResponseInfoIOBuffer::~HttpResponseInfoIOBuffer() = default;
// AppCacheDiskCacheInterface ----------------------------------------
@@ -95,12 +98,11 @@ AppCacheDiskCacheInterface::~AppCacheDiskCacheInterface() {}
AppCacheResponseIO::AppCacheResponseIO(
int64_t response_id,
- const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache)
+ base::WeakPtr<AppCacheDiskCacheInterface> disk_cache)
: response_id_(response_id),
- disk_cache_(disk_cache),
+ disk_cache_(std::move(disk_cache)),
entry_(nullptr),
- buffer_len_(0),
- weak_factory_(this) {}
+ buffer_len_(0) {}
AppCacheResponseIO::~AppCacheResponseIO() {
if (entry_)
@@ -109,8 +111,8 @@ AppCacheResponseIO::~AppCacheResponseIO() {
void AppCacheResponseIO::ScheduleIOCompletionCallback(int result) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&AppCacheResponseIO::OnIOComplete,
- weak_factory_.GetWeakPtr(), result));
+ FROM_HERE,
+ base::BindOnce(&AppCacheResponseIO::OnIOComplete, GetWeakPtr(), result));
}
void AppCacheResponseIO::InvokeUserCompletionCallback(int result) {
@@ -128,8 +130,7 @@ void AppCacheResponseIO::ReadRaw(int index, int offset,
DCHECK(entry_);
int rv = entry_->Read(
index, offset, buf, buf_len,
- base::Bind(&AppCacheResponseIO::OnRawIOComplete,
- weak_factory_.GetWeakPtr()));
+ base::BindOnce(&AppCacheResponseIO::OnRawIOComplete, GetWeakPtr()));
if (rv != net::ERR_IO_PENDING)
ScheduleIOCompletionCallback(rv);
}
@@ -139,8 +140,7 @@ void AppCacheResponseIO::WriteRaw(int index, int offset,
DCHECK(entry_);
int rv = entry_->Write(
index, offset, buf, buf_len,
- base::Bind(&AppCacheResponseIO::OnRawIOComplete,
- weak_factory_.GetWeakPtr()));
+ base::BindOnce(&AppCacheResponseIO::OnRawIOComplete, GetWeakPtr()));
if (rv != net::ERR_IO_PENDING)
ScheduleIOCompletionCallback(rv);
}
@@ -159,28 +159,34 @@ void AppCacheResponseIO::OpenEntryIfNeeded() {
rv = net::ERR_FAILED;
} else {
entry_ptr = new AppCacheDiskCacheInterface::Entry*;
- open_callback_ =
- base::Bind(&AppCacheResponseIO::OpenEntryCallback,
- weak_factory_.GetWeakPtr(), base::Owned(entry_ptr));
- rv = disk_cache_->OpenEntry(response_id_, entry_ptr, open_callback_);
+ rv = disk_cache_->OpenEntry(
+ response_id_, entry_ptr,
+ base::BindOnce(&AppCacheResponseIO::OpenEntryCallback, GetWeakPtr(),
+ entry_ptr));
}
if (rv != net::ERR_IO_PENDING)
- OpenEntryCallback(entry_ptr, rv);
+ OpenEntryCallback(GetWeakPtr(), entry_ptr, rv);
}
+// static
void AppCacheResponseIO::OpenEntryCallback(
- AppCacheDiskCacheInterface::Entry** entry, int rv) {
- DCHECK(info_buffer_.get() || buffer_.get());
+ base::WeakPtr<AppCacheResponseIO> response,
+ AppCacheDiskCacheInterface::Entry** entry,
+ int rv) {
+ if (!response) {
+ delete entry;
+ return;
+ }
- if (!open_callback_.is_null()) {
- if (rv == net::OK) {
- DCHECK(entry);
- entry_ = *entry;
- }
- open_callback_.Reset();
+ DCHECK(response->info_buffer_.get() || response->buffer_.get());
+
+ if (!response->entry_ && rv == net::OK) {
+ DCHECK(entry);
+ response->entry_ = *entry;
}
- OnOpenEntryComplete();
+ delete entry;
+ response->OnOpenEntryComplete();
}
@@ -188,16 +194,15 @@ void AppCacheResponseIO::OpenEntryCallback(
AppCacheResponseReader::AppCacheResponseReader(
int64_t response_id,
- const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache)
- : AppCacheResponseIO(response_id, disk_cache),
+ base::WeakPtr<AppCacheDiskCacheInterface> disk_cache)
+ : AppCacheResponseIO(response_id, std::move(disk_cache)),
range_offset_(0),
range_length_(std::numeric_limits<int32_t>::max()),
read_position_(0),
reading_metadata_size_(0),
weak_factory_(this) {}
-AppCacheResponseReader::~AppCacheResponseReader() {
-}
+AppCacheResponseReader::~AppCacheResponseReader() = default;
void AppCacheResponseReader::ReadInfo(HttpResponseInfoIOBuffer* info_buf,
OnceCompletionCallback callback) {
@@ -312,20 +317,23 @@ void AppCacheResponseReader::OnOpenEntryComplete() {
ContinueReadData();
}
+base::WeakPtr<AppCacheResponseIO> AppCacheResponseReader::GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+}
+
// AppCacheResponseWriter ----------------------------------------------
AppCacheResponseWriter::AppCacheResponseWriter(
int64_t response_id,
- const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache)
- : AppCacheResponseIO(response_id, disk_cache),
+ base::WeakPtr<AppCacheDiskCacheInterface> disk_cache)
+ : AppCacheResponseIO(response_id, std::move(disk_cache)),
info_size_(0),
write_position_(0),
write_amount_(0),
creation_phase_(INITIAL_ATTEMPT),
weak_factory_(this) {}
-AppCacheResponseWriter::~AppCacheResponseWriter() {
-}
+AppCacheResponseWriter::~AppCacheResponseWriter() = default;
void AppCacheResponseWriter::WriteInfo(HttpResponseInfoIOBuffer* info_buf,
OnceCompletionCallback callback) {
@@ -350,10 +358,11 @@ void AppCacheResponseWriter::ContinueWriteInfo() {
const bool kSkipTransientHeaders = true;
const bool kTruncated = false;
- base::Pickle* pickle = new base::Pickle;
- info_buffer_->http_info->Persist(pickle, kSkipTransientHeaders, kTruncated);
+ std::unique_ptr<base::Pickle> pickle = std::make_unique<base::Pickle>();
+ info_buffer_->http_info->Persist(pickle.get(), kSkipTransientHeaders,
+ kTruncated);
write_amount_ = static_cast<int>(pickle->size());
- buffer_ = new WrappedPickleIOBuffer(pickle); // takes ownership of pickle
+ buffer_ = base::MakeRefCounted<WrappedPickleIOBuffer>(std::move(pickle));
WriteRaw(kResponseInfoIndex, 0, buffer_.get(), write_amount_);
}
@@ -408,73 +417,94 @@ void AppCacheResponseWriter::CreateEntryIfNeededAndContinue() {
} else {
creation_phase_ = INITIAL_ATTEMPT;
entry_ptr = new AppCacheDiskCacheInterface::Entry*;
- create_callback_ =
- base::Bind(&AppCacheResponseWriter::OnCreateEntryComplete,
- weak_factory_.GetWeakPtr(), base::Owned(entry_ptr));
- rv = disk_cache_->CreateEntry(response_id_, entry_ptr, create_callback_);
+ rv = disk_cache_->CreateEntry(
+ response_id_, entry_ptr,
+ base::BindOnce(&AppCacheResponseWriter::OnCreateEntryComplete,
+ weak_factory_.GetWeakPtr(), entry_ptr));
}
if (rv != net::ERR_IO_PENDING)
- OnCreateEntryComplete(entry_ptr, rv);
+ OnCreateEntryComplete(weak_factory_.GetWeakPtr(), entry_ptr, rv);
}
+// static
void AppCacheResponseWriter::OnCreateEntryComplete(
- AppCacheDiskCacheInterface::Entry** entry, int rv) {
- DCHECK(info_buffer_.get() || buffer_.get());
+ base::WeakPtr<AppCacheResponseWriter> writer,
+ AppCacheDiskCacheInterface::Entry** entry,
+ int rv) {
+ if (!writer) {
+ if (entry) {
+ delete entry;
+ }
+ return;
+ }
- if (!disk_cache_) {
- ScheduleIOCompletionCallback(net::ERR_FAILED);
+ DCHECK(writer->info_buffer_.get() || writer->buffer_.get());
+
+ if (!writer->disk_cache_) {
+ if (entry) {
+ delete entry;
+ }
+ writer->ScheduleIOCompletionCallback(net::ERR_FAILED);
return;
- } else if (creation_phase_ == INITIAL_ATTEMPT) {
+ } else if (writer->creation_phase_ == INITIAL_ATTEMPT) {
if (rv != net::OK) {
// We may try to overwrite existing entries.
- creation_phase_ = DOOM_EXISTING;
- rv = disk_cache_->DoomEntry(response_id_, create_callback_);
+ delete entry;
+ writer->creation_phase_ = DOOM_EXISTING;
+ rv = writer->disk_cache_->DoomEntry(
+ writer->response_id_,
+ base::BindOnce(&AppCacheResponseWriter::OnCreateEntryComplete, writer,
+ nullptr));
if (rv != net::ERR_IO_PENDING)
- OnCreateEntryComplete(nullptr, rv);
+ OnCreateEntryComplete(writer, nullptr, rv);
return;
}
- } else if (creation_phase_ == DOOM_EXISTING) {
- creation_phase_ = SECOND_ATTEMPT;
+ } else if (writer->creation_phase_ == DOOM_EXISTING) {
+ DCHECK_EQ(nullptr, entry);
+ writer->creation_phase_ = SECOND_ATTEMPT;
AppCacheDiskCacheInterface::Entry** entry_ptr =
new AppCacheDiskCacheInterface::Entry*;
- create_callback_ =
- base::Bind(&AppCacheResponseWriter::OnCreateEntryComplete,
- weak_factory_.GetWeakPtr(), base::Owned(entry_ptr));
- rv = disk_cache_->CreateEntry(response_id_, entry_ptr, create_callback_);
+ rv = writer->disk_cache_->CreateEntry(
+ writer->response_id_, entry_ptr,
+ base::BindOnce(&AppCacheResponseWriter::OnCreateEntryComplete, writer,
+ entry_ptr));
if (rv != net::ERR_IO_PENDING)
- OnCreateEntryComplete(entry_ptr, rv);
+ OnCreateEntryComplete(writer, entry_ptr, rv);
return;
}
- if (!create_callback_.is_null()) {
- if (rv == net::OK)
- entry_ = *entry;
-
- create_callback_.Reset();
+ if (!writer->entry_ && rv == net::OK) {
+ DCHECK(entry);
+ writer->entry_ = *entry;
}
- if (info_buffer_.get())
- ContinueWriteInfo();
+ delete entry;
+
+ if (writer->info_buffer_.get())
+ writer->ContinueWriteInfo();
else
- ContinueWriteData();
+ writer->ContinueWriteData();
+}
+
+base::WeakPtr<AppCacheResponseIO> AppCacheResponseWriter::GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
}
// AppCacheResponseMetadataWriter ----------------------------------------------
AppCacheResponseMetadataWriter::AppCacheResponseMetadataWriter(
int64_t response_id,
- const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache)
- : AppCacheResponseIO(response_id, disk_cache),
+ base::WeakPtr<AppCacheDiskCacheInterface> disk_cache)
+ : AppCacheResponseIO(response_id, std::move(disk_cache)),
write_amount_(0),
weak_factory_(this) {}
-AppCacheResponseMetadataWriter::~AppCacheResponseMetadataWriter() {
-}
+AppCacheResponseMetadataWriter::~AppCacheResponseMetadataWriter() = default;
void AppCacheResponseMetadataWriter::WriteMetadata(
net::IOBuffer* buf,
int buf_len,
- const net::CompletionCallback& callback) {
+ net::CompletionOnceCallback callback) {
DCHECK(!callback.is_null());
DCHECK(!IsIOPending());
DCHECK(buf);
@@ -483,7 +513,7 @@ void AppCacheResponseMetadataWriter::WriteMetadata(
buffer_ = buf;
write_amount_ = buf_len;
- callback_ = callback; // cleared on completion
+ callback_ = std::move(callback); // cleared on completion
OpenEntryIfNeeded();
}
@@ -503,4 +533,8 @@ void AppCacheResponseMetadataWriter::OnIOComplete(int result) {
// Note: |this| may have been deleted by the completion callback.
}
+base::WeakPtr<AppCacheResponseIO> AppCacheResponseMetadataWriter::GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+}
+
} // namespace content
diff --git a/chromium/content/browser/appcache/appcache_response.h b/chromium/content/browser/appcache/appcache_response.h
index fb85715d141..de0663e162e 100644
--- a/chromium/content/browser/appcache/appcache_response.h
+++ b/chromium/content/browser/appcache/appcache_response.h
@@ -14,7 +14,7 @@
#include "base/memory/weak_ptr.h"
#include "content/common/appcache_interfaces.h"
#include "content/common/content_export.h"
-#include "net/base/completion_callback.h"
+#include "net/base/completion_once_callback.h"
#include "net/http/http_response_info.h"
#include "url/gurl.h"
@@ -35,29 +35,28 @@ using OnceCompletionCallback = base::OnceCallback<void(int)>;
class CONTENT_EXPORT AppCacheResponseInfo
: public base::RefCounted<AppCacheResponseInfo> {
public:
- // AppCacheResponseInfo takes ownership of the http_info.
AppCacheResponseInfo(AppCacheStorage* storage,
const GURL& manifest_url,
int64_t response_id,
- net::HttpResponseInfo* http_info,
+ std::unique_ptr<net::HttpResponseInfo> http_info,
int64_t response_data_size);
const GURL& manifest_url() const { return manifest_url_; }
int64_t response_id() const { return response_id_; }
- const net::HttpResponseInfo* http_response_info() const {
- return http_response_info_.get();
+ const net::HttpResponseInfo& http_response_info() const {
+ return *http_response_info_;
}
int64_t response_data_size() const { return response_data_size_; }
private:
friend class base::RefCounted<AppCacheResponseInfo>;
- virtual ~AppCacheResponseInfo();
+ ~AppCacheResponseInfo();
const GURL manifest_url_;
const int64_t response_id_;
const std::unique_ptr<net::HttpResponseInfo> http_response_info_;
const int64_t response_data_size_;
- AppCacheStorage* storage_;
+ AppCacheStorage* const storage_;
};
// A refcounted wrapper for HttpResponseInfo so we can apply the
@@ -68,11 +67,12 @@ struct CONTENT_EXPORT HttpResponseInfoIOBuffer
int response_data_size;
HttpResponseInfoIOBuffer();
- explicit HttpResponseInfoIOBuffer(net::HttpResponseInfo* info);
+ explicit HttpResponseInfoIOBuffer(
+ std::unique_ptr<net::HttpResponseInfo> info);
- protected:
+ private:
friend class base::RefCountedThreadSafe<HttpResponseInfoIOBuffer>;
- virtual ~HttpResponseInfoIOBuffer();
+ ~HttpResponseInfoIOBuffer();
};
// Low level storage API used by the response reader and writer.
@@ -84,16 +84,16 @@ class CONTENT_EXPORT AppCacheDiskCacheInterface {
int64_t offset,
net::IOBuffer* buf,
int buf_len,
- const net::CompletionCallback& callback) = 0;
+ net::CompletionOnceCallback callback) = 0;
virtual int Write(int index,
int64_t offset,
net::IOBuffer* buf,
int buf_len,
- const net::CompletionCallback& callback) = 0;
+ net::CompletionOnceCallback callback) = 0;
virtual int64_t GetSize(int index) = 0;
virtual void Close() = 0;
protected:
- virtual ~Entry() {}
+ virtual ~Entry() = default;
};
// The uma_name pointer must remain valid for the life of the object.
@@ -101,12 +101,11 @@ class CONTENT_EXPORT AppCacheDiskCacheInterface {
virtual int CreateEntry(int64_t key,
Entry** entry,
- const net::CompletionCallback& callback) = 0;
+ net::CompletionOnceCallback callback) = 0;
virtual int OpenEntry(int64_t key,
Entry** entry,
- const net::CompletionCallback& callback) = 0;
- virtual int DoomEntry(int64_t key,
- const net::CompletionCallback& callback) = 0;
+ net::CompletionOnceCallback callback) = 0;
+ virtual int DoomEntry(int64_t key, net::CompletionOnceCallback callback) = 0;
const char* uma_name() const { return uma_name_; }
base::WeakPtr<AppCacheDiskCacheInterface> GetWeakPtr();
@@ -125,20 +124,23 @@ class CONTENT_EXPORT AppCacheResponseIO {
int64_t response_id() const { return response_id_; }
protected:
- AppCacheResponseIO(
- int64_t response_id,
- const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache);
+ AppCacheResponseIO(int64_t response_id,
+ base::WeakPtr<AppCacheDiskCacheInterface> disk_cache);
virtual void OnIOComplete(int result) = 0;
virtual void OnOpenEntryComplete() {}
- bool IsIOPending() { return !callback_.is_null(); }
+ bool IsIOPending() const { return !callback_.is_null(); }
void ScheduleIOCompletionCallback(int result);
void InvokeUserCompletionCallback(int result);
void ReadRaw(int index, int offset, net::IOBuffer* buf, int buf_len);
void WriteRaw(int index, int offset, net::IOBuffer* buf, int buf_len);
void OpenEntryIfNeeded();
+ // Methods in this class use weak pointers. The weak pointer factories must be
+ // defined in the subclasses, to avoid use-after-free situations.
+ virtual base::WeakPtr<AppCacheResponseIO> GetWeakPtr() = 0;
+
const int64_t response_id_;
base::WeakPtr<AppCacheDiskCacheInterface> disk_cache_;
AppCacheDiskCacheInterface::Entry* entry_;
@@ -146,20 +148,20 @@ class CONTENT_EXPORT AppCacheResponseIO {
scoped_refptr<net::IOBuffer> buffer_;
int buffer_len_;
OnceCompletionCallback callback_;
- net::CompletionCallback open_callback_;
- base::WeakPtrFactory<AppCacheResponseIO> weak_factory_;
+ net::CompletionOnceCallback open_callback_;
private:
void OnRawIOComplete(int result);
- void OpenEntryCallback(AppCacheDiskCacheInterface::Entry** entry, int rv);
+ static void OpenEntryCallback(base::WeakPtr<AppCacheResponseIO> response,
+ AppCacheDiskCacheInterface::Entry** entry,
+ int rv);
};
// Reads existing response data from storage. If the object is deleted
// and there is a read in progress, the implementation will return
// immediately but will take care of any side effect of cancelling the
// operation. In other words, instances are safe to delete at will.
-class CONTENT_EXPORT AppCacheResponseReader
- : public AppCacheResponseIO {
+class CONTENT_EXPORT AppCacheResponseReader : public AppCacheResponseIO {
public:
~AppCacheResponseReader() override;
@@ -201,12 +203,13 @@ class CONTENT_EXPORT AppCacheResponseReader
friend class content::MockAppCacheStorage;
// Should only be constructed by the storage class and derivatives.
- AppCacheResponseReader(
- int64_t response_id,
- const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache);
+ AppCacheResponseReader(int64_t response_id,
+ base::WeakPtr<AppCacheDiskCacheInterface> disk_cache);
void OnIOComplete(int result) override;
void OnOpenEntryComplete() override;
+ base::WeakPtr<AppCacheResponseIO> GetWeakPtr() override;
+
void ContinueReadInfo();
void ContinueReadData();
@@ -214,6 +217,7 @@ class CONTENT_EXPORT AppCacheResponseReader
int range_length_;
int read_position_;
int reading_metadata_size_;
+
base::WeakPtrFactory<AppCacheResponseReader> weak_factory_;
};
@@ -221,8 +225,7 @@ class CONTENT_EXPORT AppCacheResponseReader
// and there is a write in progress, the implementation will return
// immediately but will take care of any side effect of cancelling the
// operation. In other words, instances are safe to delete at will.
-class CONTENT_EXPORT AppCacheResponseWriter
- : public AppCacheResponseIO {
+class CONTENT_EXPORT AppCacheResponseWriter : public AppCacheResponseIO {
public:
~AppCacheResponseWriter() override;
@@ -258,9 +261,8 @@ class CONTENT_EXPORT AppCacheResponseWriter
protected:
// Should only be constructed by the storage class and derivatives.
- AppCacheResponseWriter(
- int64_t response_id,
- const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache);
+ AppCacheResponseWriter(int64_t response_id,
+ base::WeakPtr<AppCacheDiskCacheInterface> disk_cache);
private:
friend class AppCacheStorageImpl;
@@ -274,16 +276,20 @@ class CONTENT_EXPORT AppCacheResponseWriter
};
void OnIOComplete(int result) override;
+ base::WeakPtr<AppCacheResponseIO> GetWeakPtr() override;
+
void ContinueWriteInfo();
void ContinueWriteData();
void CreateEntryIfNeededAndContinue();
- void OnCreateEntryComplete(AppCacheDiskCacheInterface::Entry** entry, int rv);
+ static void OnCreateEntryComplete(
+ base::WeakPtr<AppCacheResponseWriter> writer,
+ AppCacheDiskCacheInterface::Entry** entry,
+ int rv);
int info_size_;
int write_position_;
int write_amount_;
CreationPhase creation_phase_;
- net::CompletionCallback create_callback_;
base::WeakPtrFactory<AppCacheResponseWriter> weak_factory_;
};
@@ -307,7 +313,7 @@ class CONTENT_EXPORT AppCacheResponseMetadataWriter
// progress.
void WriteMetadata(net::IOBuffer* buf,
int buf_len,
- const net::CompletionCallback& callback);
+ net::CompletionOnceCallback callback);
// Returns true if there is a write pending.
bool IsWritePending() { return IsIOPending(); }
@@ -319,11 +325,12 @@ class CONTENT_EXPORT AppCacheResponseMetadataWriter
// Should only be constructed by the storage class and derivatives.
AppCacheResponseMetadataWriter(
int64_t response_id,
- const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache);
+ base::WeakPtr<AppCacheDiskCacheInterface> disk_cache);
private:
void OnIOComplete(int result) override;
void OnOpenEntryComplete() override;
+ base::WeakPtr<AppCacheResponseIO> GetWeakPtr() override;
int write_amount_;
base::WeakPtrFactory<AppCacheResponseMetadataWriter> weak_factory_;
diff --git a/chromium/content/browser/appcache/appcache_response_unittest.cc b/chromium/content/browser/appcache/appcache_response_unittest.cc
index d0c91629877..799c9133b52 100644
--- a/chromium/content/browser/appcache/appcache_response_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_response_unittest.cc
@@ -177,19 +177,21 @@ class AppCacheResponseTest : public testing::Test {
int basic_response_size() { return 5; } // should match kHttpBody above
- void WriteResponse(net::HttpResponseInfo* head,
- IOBuffer* body, int body_len) {
+ void WriteResponse(std::unique_ptr<net::HttpResponseInfo> head,
+ IOBuffer* body,
+ int body_len) {
DCHECK(body);
scoped_refptr<IOBuffer> body_ref(body);
PushNextTask(base::BindOnce(&AppCacheResponseTest::WriteResponseBody,
base::Unretained(this), body_ref, body_len));
- WriteResponseHead(head);
+ WriteResponseHead(std::move(head));
}
- void WriteResponseHead(net::HttpResponseInfo* head) {
+ void WriteResponseHead(std::unique_ptr<net::HttpResponseInfo> head) {
EXPECT_FALSE(writer_->IsWritePending());
- expected_write_result_ = GetHttpResponseInfoSize(head);
- write_info_buffer_ = new HttpResponseInfoIOBuffer(head);
+ expected_write_result_ = GetHttpResponseInfoSize(*head);
+ write_info_buffer_ =
+ base::MakeRefCounted<HttpResponseInfoIOBuffer>(std::move(head));
writer_->WriteInfo(
write_info_buffer_.get(),
base::BindOnce(&AppCacheResponseTest::OnWriteInfoComplete,
@@ -198,7 +200,7 @@ class AppCacheResponseTest : public testing::Test {
void WriteResponseBody(scoped_refptr<IOBuffer> io_buffer, int buf_len) {
EXPECT_FALSE(writer_->IsWritePending());
- write_buffer_ = io_buffer;
+ write_buffer_ = std::move(io_buffer);
expected_write_result_ = buf_len;
writer_->WriteData(write_buffer_.get(), buf_len,
base::BindOnce(&AppCacheResponseTest::OnWriteComplete,
@@ -268,36 +270,36 @@ class AppCacheResponseTest : public testing::Test {
// Helpers to work with HttpResponseInfo objects
- net::HttpResponseInfo* MakeHttpResponseInfo(const std::string& raw_headers) {
- net::HttpResponseInfo* info = new net::HttpResponseInfo;
+ std::unique_ptr<net::HttpResponseInfo> MakeHttpResponseInfo(
+ const std::string& raw_headers) {
+ std::unique_ptr<net::HttpResponseInfo> info =
+ std::make_unique<net::HttpResponseInfo>();
info->request_time = base::Time::Now();
info->response_time = base::Time::Now();
info->was_cached = false;
- info->headers = new net::HttpResponseHeaders(raw_headers);
+ info->headers = base::MakeRefCounted<net::HttpResponseHeaders>(raw_headers);
return info;
}
- int GetHttpResponseInfoSize(const net::HttpResponseInfo* info) {
- base::Pickle pickle;
- return PickleHttpResonseInfo(&pickle, info);
+ int GetHttpResponseInfoSize(const net::HttpResponseInfo& info) {
+ base::Pickle pickle = PickleHttpResonseInfo(info);
+ return pickle.size();
}
- bool CompareHttpResponseInfos(const net::HttpResponseInfo* info1,
- const net::HttpResponseInfo* info2) {
- base::Pickle pickle1;
- base::Pickle pickle2;
- PickleHttpResonseInfo(&pickle1, info1);
- PickleHttpResonseInfo(&pickle2, info2);
+ bool CompareHttpResponseInfos(const net::HttpResponseInfo& info1,
+ const net::HttpResponseInfo& info2) {
+ base::Pickle pickle1 = PickleHttpResonseInfo(info1);
+ base::Pickle pickle2 = PickleHttpResonseInfo(info2);
return (pickle1.size() == pickle2.size()) &&
(0 == memcmp(pickle1.data(), pickle2.data(), pickle1.size()));
}
- int PickleHttpResonseInfo(base::Pickle* pickle,
- const net::HttpResponseInfo* info) {
+ base::Pickle PickleHttpResonseInfo(const net::HttpResponseInfo& info) {
const bool kSkipTransientHeaders = true;
const bool kTruncated = false;
- info->Persist(pickle, kSkipTransientHeaders, kTruncated);
- return pickle->size();
+ base::Pickle pickle;
+ info.Persist(&pickle, kSkipTransientHeaders, kTruncated);
+ return pickle;
}
// Helpers to fill and verify blocks of memory with a value
@@ -398,7 +400,7 @@ class AppCacheResponseTest : public testing::Test {
EXPECT_EQ(written_response_id_, storage_delegate_->loaded_info_id_);
EXPECT_TRUE(storage_delegate_->loaded_info_.get());
EXPECT_TRUE(CompareHttpResponseInfos(
- write_info_buffer_->http_info.get(),
+ *write_info_buffer_->http_info,
storage_delegate_->loaded_info_->http_response_info()));
EXPECT_EQ(basic_response_size(),
storage_delegate_->loaded_info_->response_data_size());
@@ -469,20 +471,18 @@ class AppCacheResponseTest : public testing::Test {
void Metadata_VerifyMetadata(const char* metadata) {
EXPECT_EQ(written_response_id_, storage_delegate_->loaded_info_id_);
EXPECT_TRUE(storage_delegate_->loaded_info_.get());
- const net::HttpResponseInfo* read_head =
+ const net::HttpResponseInfo& read_head =
storage_delegate_->loaded_info_->http_response_info();
- EXPECT_TRUE(read_head);
const int metadata_size = strlen(metadata);
if (metadata_size) {
- EXPECT_TRUE(read_head->metadata.get());
- EXPECT_EQ(metadata_size, read_head->metadata->size());
- EXPECT_EQ(0,
- memcmp(metadata, read_head->metadata->data(), metadata_size));
+ EXPECT_TRUE(read_head.metadata.get());
+ EXPECT_EQ(metadata_size, read_head.metadata->size());
+ EXPECT_EQ(0, memcmp(metadata, read_head.metadata->data(), metadata_size));
} else {
- EXPECT_FALSE(read_head->metadata.get());
+ EXPECT_FALSE(read_head.metadata.get());
}
EXPECT_TRUE(CompareHttpResponseInfos(
- write_info_buffer_->http_info.get(),
+ *write_info_buffer_->http_info,
storage_delegate_->loaded_info_->http_response_info()));
EXPECT_EQ(basic_response_size(),
storage_delegate_->loaded_info_->response_data_size());
@@ -494,9 +494,10 @@ class AppCacheResponseTest : public testing::Test {
void AmountWritten() {
static const char kHttpHeaders[] = "HTTP/1.0 200 OK\0\0";
std::string raw_headers(kHttpHeaders, arraysize(kHttpHeaders));
- net::HttpResponseInfo* head = MakeHttpResponseInfo(raw_headers);
+ std::unique_ptr<net::HttpResponseInfo> head =
+ MakeHttpResponseInfo(raw_headers);
int expected_amount_written =
- GetHttpResponseInfoSize(head) + kNumBlocks * kBlockSize;
+ GetHttpResponseInfoSize(*head) + kNumBlocks * kBlockSize;
// Push tasks in reverse order.
PushNextTask(base::BindOnce(&AppCacheResponseTest::Verify_AmountWritten,
@@ -507,7 +508,7 @@ class AppCacheResponseTest : public testing::Test {
base::Unretained(this), kNumBlocks - i));
}
PushNextTask(base::BindOnce(&AppCacheResponseTest::WriteResponseHead,
- base::Unretained(this), head));
+ base::Unretained(this), std::move(head)));
writer_.reset(service_->storage()->CreateResponseWriter(GURL()));
written_response_id_ = writer_->response_id();
diff --git a/chromium/content/browser/appcache/appcache_service_impl.cc b/chromium/content/browser/appcache/appcache_service_impl.cc
index 763140468ee..513eef22af8 100644
--- a/chromium/content/browser/appcache/appcache_service_impl.cc
+++ b/chromium/content/browser/appcache/appcache_service_impl.cc
@@ -14,7 +14,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "content/browser/appcache/appcache.h"
#include "content/browser/appcache/appcache_backend_impl.h"
@@ -25,28 +25,18 @@
#include "content/browser/appcache/appcache_response.h"
#include "content/browser/appcache/appcache_service_impl.h"
#include "content/browser/appcache/appcache_storage_impl.h"
-#include "net/base/completion_callback.h"
#include "net/base/io_buffer.h"
#include "storage/browser/quota/special_storage_policy.h"
namespace content {
-namespace {
+AppCacheInfoCollection::AppCacheInfoCollection() = default;
-void DeferredCallback(OnceCompletionCallback callback, int rv) {
- std::move(callback).Run(rv);
-}
-
-} // namespace
-
-AppCacheInfoCollection::AppCacheInfoCollection() {}
-
-AppCacheInfoCollection::~AppCacheInfoCollection() {}
+AppCacheInfoCollection::~AppCacheInfoCollection() = default;
// AsyncHelper -------
-class AppCacheServiceImpl::AsyncHelper
- : public AppCacheStorage::Delegate {
+class AppCacheServiceImpl::AsyncHelper : public AppCacheStorage::Delegate {
public:
AsyncHelper(AppCacheServiceImpl* service, OnceCompletionCallback callback)
: service_(service), callback_(std::move(callback)) {
@@ -65,13 +55,12 @@ class AppCacheServiceImpl::AsyncHelper
protected:
void CallCallback(int rv) {
- if (!callback_.is_null()) {
+ if (callback_) {
// Defer to guarantee async completion.
base::SequencedTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(&DeferredCallback, std::move(callback_), rv));
+ FROM_HERE, base::BindOnce(std::move(callback_), rv));
}
- callback_.Reset();
+ DCHECK(!callback_);
}
AppCacheServiceImpl* service_;
@@ -90,11 +79,11 @@ void AppCacheServiceImpl::AsyncHelper::Cancel() {
class AppCacheServiceImpl::DeleteHelper : public AsyncHelper {
public:
- DeleteHelper(
- AppCacheServiceImpl* service, const GURL& manifest_url,
- const net::CompletionCallback& callback)
- : AsyncHelper(service, callback), manifest_url_(manifest_url) {
- }
+ DeleteHelper(AppCacheServiceImpl* service,
+ const GURL& manifest_url,
+ net::CompletionOnceCallback callback)
+ : AsyncHelper(service, std::move(callback)),
+ manifest_url_(manifest_url) {}
void Start() override {
service_->storage()->LoadOrCreateGroup(manifest_url_, this);
@@ -137,8 +126,8 @@ class AppCacheServiceImpl::DeleteOriginHelper : public AsyncHelper {
public:
DeleteOriginHelper(AppCacheServiceImpl* service,
const url::Origin& origin,
- const net::CompletionCallback& callback)
- : AsyncHelper(service, callback),
+ net::CompletionOnceCallback callback)
+ : AsyncHelper(service, std::move(callback)),
origin_(origin),
num_caches_to_delete_(0),
successes_(0),
@@ -261,7 +250,7 @@ class AppCacheServiceImpl::CheckResponseHelper : AsyncHelper {
const GURL& manifest_url,
int64_t cache_id,
int64_t response_id)
- : AsyncHelper(service, net::CompletionCallback()),
+ : AsyncHelper(service, net::CompletionOnceCallback()),
manifest_url_(manifest_url),
cache_id_(cache_id),
response_id_(response_id),
@@ -320,7 +309,8 @@ void AppCacheServiceImpl::CheckResponseHelper::OnGroupLoaded(
if (cache_->cache_id() == cache_id_) {
AppCacheHistograms::CountCheckResponseResult(
AppCacheHistograms::ENTRY_NOT_FOUND);
- service_->DeleteAppCacheGroup(manifest_url_, net::CompletionCallback());
+ service_->DeleteAppCacheGroup(manifest_url_,
+ net::CompletionOnceCallback());
} else {
AppCacheHistograms::CountCheckResponseResult(
AppCacheHistograms::RESPONSE_OUT_OF_DATE);
@@ -344,7 +334,7 @@ void AppCacheServiceImpl::CheckResponseHelper::OnReadInfoComplete(int result) {
if (result < 0) {
AppCacheHistograms::CountCheckResponseResult(
AppCacheHistograms::READ_HEADERS_ERROR);
- service_->DeleteAppCacheGroup(manifest_url_, net::CompletionCallback());
+ service_->DeleteAppCacheGroup(manifest_url_, net::CompletionOnceCallback());
delete this;
return;
}
@@ -380,7 +370,7 @@ void AppCacheServiceImpl::CheckResponseHelper::OnReadDataComplete(int result) {
AppCacheHistograms::CountCheckResponseResult(check_result);
if (check_result != AppCacheHistograms::RESPONSE_OK)
- service_->DeleteAppCacheGroup(manifest_url_, net::CompletionCallback());
+ service_->DeleteAppCacheGroup(manifest_url_, net::CompletionOnceCallback());
delete this;
}
@@ -442,9 +432,9 @@ void AppCacheServiceImpl::ScheduleReinitialize() {
// leave the appcache disabled for an indefinite period of time. Some
// users never shutdown the browser.
- const base::TimeDelta kZeroDelta;
- const base::TimeDelta kOneHour(base::TimeDelta::FromHours(1));
- const base::TimeDelta k30Seconds(base::TimeDelta::FromSeconds(30));
+ constexpr base::TimeDelta kZeroDelta;
+ constexpr base::TimeDelta kOneHour = base::TimeDelta::FromHours(1);
+ constexpr base::TimeDelta kThirtySeconds = base::TimeDelta::FromSeconds(30);
// If the system managed to stay up for long enough, reset the
// delay so a new failure won't incur a long wait to get going again.
@@ -456,7 +446,7 @@ void AppCacheServiceImpl::ScheduleReinitialize() {
this, &AppCacheServiceImpl::Reinitialize);
// Adjust the delay for next time.
- base::TimeDelta increment = std::max(k30Seconds, next_reinit_delay_);
+ base::TimeDelta increment = std::max(kThirtySeconds, next_reinit_delay_);
next_reinit_delay_ = std::min(next_reinit_delay_ + increment, kOneHour);
}
@@ -484,15 +474,17 @@ void AppCacheServiceImpl::GetAllAppCacheInfo(AppCacheInfoCollection* collection,
void AppCacheServiceImpl::DeleteAppCacheGroup(
const GURL& manifest_url,
- const net::CompletionCallback& callback) {
- DeleteHelper* helper = new DeleteHelper(this, manifest_url, callback);
+ net::CompletionOnceCallback callback) {
+ DeleteHelper* helper =
+ new DeleteHelper(this, manifest_url, std::move(callback));
helper->Start();
}
void AppCacheServiceImpl::DeleteAppCachesForOrigin(
const url::Origin& origin,
- const net::CompletionCallback& callback) {
- DeleteOriginHelper* helper = new DeleteOriginHelper(this, origin, callback);
+ net::CompletionOnceCallback callback) {
+ DeleteOriginHelper* helper =
+ new DeleteOriginHelper(this, origin, std::move(callback));
helper->Start();
}
@@ -512,8 +504,7 @@ void AppCacheServiceImpl::set_special_storage_policy(
void AppCacheServiceImpl::RegisterBackend(
AppCacheBackendImpl* backend_impl) {
DCHECK(backends_.find(backend_impl->process_id()) == backends_.end());
- backends_.insert(
- BackendMap::value_type(backend_impl->process_id(), backend_impl));
+ backends_.insert({backend_impl->process_id(), backend_impl});
}
void AppCacheServiceImpl::UnregisterBackend(
diff --git a/chromium/content/browser/appcache/appcache_service_impl.h b/chromium/content/browser/appcache/appcache_service_impl.h
index bf6fabe30ff..d83fc409e17 100644
--- a/chromium/content/browser/appcache/appcache_service_impl.h
+++ b/chromium/content/browser/appcache/appcache_service_impl.h
@@ -21,7 +21,7 @@
#include "content/common/appcache_interfaces.h"
#include "content/common/content_export.h"
#include "content/public/browser/appcache_service.h"
-#include "net/base/completion_callback.h"
+#include "net/base/completion_once_callback.h"
#include "net/base/net_errors.h"
#include "storage/browser/quota/quota_manager_proxy.h"
@@ -65,8 +65,7 @@ class CONTENT_EXPORT AppCacheStorageReference
// Class that manages the application cache service. Sends notifications
// to many frontends. One instance per user-profile. Each instance has
// exclusive access to its cache_directory on disk.
-class CONTENT_EXPORT AppCacheServiceImpl
- : public AppCacheService {
+class CONTENT_EXPORT AppCacheServiceImpl : public AppCacheService {
public:
class CONTENT_EXPORT Observer {
@@ -105,14 +104,13 @@ class CONTENT_EXPORT AppCacheServiceImpl
void GetAllAppCacheInfo(AppCacheInfoCollection* collection,
OnceCompletionCallback callback) override;
void DeleteAppCacheGroup(const GURL& manifest_url,
- const net::CompletionCallback& callback) override;
+ net::CompletionOnceCallback callback) override;
// Deletes all appcaches for the origin, 'callback' is invoked upon
// completion. This method always completes asynchronously.
// (virtual for unit testing)
- virtual void DeleteAppCachesForOrigin(
- const url::Origin& origin,
- const net::CompletionCallback& callback);
+ virtual void DeleteAppCachesForOrigin(const url::Origin& origin,
+ net::CompletionOnceCallback callback);
// Checks the integrity of 'response_id' by reading the headers and data.
// If it cannot be read, the cache group for 'manifest_url' is deleted.
@@ -155,8 +153,8 @@ class CONTENT_EXPORT AppCacheServiceImpl
void RegisterBackend(AppCacheBackendImpl* backend_impl);
virtual void UnregisterBackend(AppCacheBackendImpl* backend_impl);
AppCacheBackendImpl* GetBackend(int id) const {
- BackendMap::const_iterator it = backends_.find(id);
- return (it != backends_.end()) ? it->second : NULL;
+ auto it = backends_.find(id);
+ return (it != backends_.end()) ? it->second : nullptr;
}
AppCacheStorage* storage() const { return storage_.get(); }
@@ -193,10 +191,6 @@ class CONTENT_EXPORT AppCacheServiceImpl
class GetInfoHelper;
class CheckResponseHelper;
- using PendingAsyncHelpers =
- std::map<AsyncHelper*, std::unique_ptr<AsyncHelper>>;
- using BackendMap = std::map<int, AppCacheBackendImpl*>;
-
void Reinitialize();
base::FilePath cache_directory_;
@@ -206,8 +200,9 @@ class CONTENT_EXPORT AppCacheServiceImpl
std::unique_ptr<AppCacheStorage> storage_;
scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_;
scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
- PendingAsyncHelpers pending_helpers_;
- BackendMap backends_; // One 'backend' per child process.
+ std::map<AsyncHelper*, std::unique_ptr<AsyncHelper>> pending_helpers_;
+ // One 'backend' per child process.
+ std::map<int, AppCacheBackendImpl*> backends_;
// Context for use during cache updates.
net::URLRequestContext* request_context_;
// If true, nothing (not even session-only data) should be deleted on exit.
@@ -215,7 +210,7 @@ class CONTENT_EXPORT AppCacheServiceImpl
base::Time last_reinit_time_;
base::TimeDelta next_reinit_delay_;
base::OneShotTimer reinit_timer_;
- base::ObserverList<Observer> observers_;
+ base::ObserverList<Observer>::Unchecked observers_;
// In the network service world contains the pointer to the
// URLLoaderFactoryGetter instance which is used to get to the network
diff --git a/chromium/content/browser/appcache/appcache_service_unittest.cc b/chromium/content/browser/appcache/appcache_service_unittest.cc
index 6d0d46cbc5c..50a7421ae9c 100644
--- a/chromium/content/browser/appcache/appcache_service_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_service_unittest.cc
@@ -18,7 +18,7 @@
#include "content/browser/appcache/appcache_response.h"
#include "content/browser/appcache/appcache_service_impl.h"
#include "content/browser/appcache/mock_appcache_storage.h"
-#include "net/base/completion_callback.h"
+#include "net/base/completion_once_callback.h"
#include "net/base/io_buffer.h"
#include "net/http/http_response_headers.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -101,10 +101,7 @@ class AppCacheServiceImplTest : public testing::Test {
kManifestUrl(kOriginURL.Resolve("manifest")),
service_(new AppCacheServiceImpl(nullptr)),
delete_result_(net::OK),
- delete_completion_count_(0),
- deletion_callback_(
- base::Bind(&AppCacheServiceImplTest::OnDeleteAppCachesComplete,
- base::Unretained(this))) {
+ delete_completion_count_(0) {
// Setup to use mock storage.
service_->storage_.reset(new MockAppCacheStorage(service_.get()));
}
@@ -183,6 +180,11 @@ class AppCacheServiceImplTest : public testing::Test {
return pickle->size();
}
+ net::CompletionOnceCallback deletion_callback() {
+ return base::BindOnce(&AppCacheServiceImplTest::OnDeleteAppCachesComplete,
+ base::Unretained(this));
+ }
+
const GURL kOriginURL;
const url::Origin kOrigin;
const GURL kManifestUrl;
@@ -191,12 +193,11 @@ class AppCacheServiceImplTest : public testing::Test {
std::unique_ptr<AppCacheServiceImpl> service_;
int delete_result_;
int delete_completion_count_;
- net::CompletionCallback deletion_callback_;
};
TEST_F(AppCacheServiceImplTest, DeleteAppCachesForOrigin) {
// Without giving mock storage simiulated info, should fail.
- service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
+ service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback());
EXPECT_EQ(0, delete_completion_count_);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, delete_completion_count_);
@@ -205,7 +206,7 @@ TEST_F(AppCacheServiceImplTest, DeleteAppCachesForOrigin) {
// Should succeed given an empty info collection.
mock_storage()->SimulateGetAllInfo(new content::AppCacheInfoCollection);
- service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
+ service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback());
EXPECT_EQ(0, delete_completion_count_);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, delete_completion_count_);
@@ -227,7 +228,7 @@ TEST_F(AppCacheServiceImplTest, DeleteAppCachesForOrigin) {
info_vector.push_back(mock_manifest_3);
info->infos_by_origin[kOrigin] = info_vector;
mock_storage()->SimulateGetAllInfo(info.get());
- service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
+ service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback());
EXPECT_EQ(0, delete_completion_count_);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, delete_completion_count_);
@@ -238,7 +239,7 @@ TEST_F(AppCacheServiceImplTest, DeleteAppCachesForOrigin) {
info->infos_by_origin[kOrigin] = info_vector;
mock_storage()->SimulateGetAllInfo(info.get());
mock_storage()->SimulateMakeGroupObsoleteFailure();
- service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
+ service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback());
EXPECT_EQ(0, delete_completion_count_);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, delete_completion_count_);
@@ -247,7 +248,7 @@ TEST_F(AppCacheServiceImplTest, DeleteAppCachesForOrigin) {
// Should complete with abort error if the service is deleted
// prior to a delete completion.
- service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
+ service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback());
EXPECT_EQ(0, delete_completion_count_);
service_.reset(); // kill it
EXPECT_EQ(1, delete_completion_count_);
diff --git a/chromium/content/browser/appcache/appcache_storage.cc b/chromium/content/browser/appcache/appcache_storage.cc
index e4394e252df..3be839ed241 100644
--- a/chromium/content/browser/appcache/appcache_storage.cc
+++ b/chromium/content/browser/appcache/appcache_storage.cc
@@ -4,6 +4,8 @@
#include "content/browser/appcache/appcache_storage.h"
+#include <utility>
+
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/memory/ptr_util.h"
@@ -71,9 +73,8 @@ void AppCacheStorage::ResponseInfoLoadTask::OnReadComplete(int result) {
scoped_refptr<AppCacheResponseInfo> info;
if (result >= 0) {
- info = new AppCacheResponseInfo(storage_, manifest_url_,
- response_id_,
- info_buffer_->http_info.release(),
+ info = new AppCacheResponseInfo(storage_, manifest_url_, response_id_,
+ std::move(info_buffer_->http_info),
info_buffer_->response_data_size);
}
FOR_EACH_DELEGATE(delegates_, OnResponseInfoLoaded(info.get(), response_id_));
diff --git a/chromium/content/browser/appcache/appcache_storage.h b/chromium/content/browser/appcache/appcache_storage.h
index 2bf62b2c41f..5e49a2760a2 100644
--- a/chromium/content/browser/appcache/appcache_storage.h
+++ b/chromium/content/browser/appcache/appcache_storage.h
@@ -18,7 +18,6 @@
#include "base/memory/weak_ptr.h"
#include "content/browser/appcache/appcache_working_set.h"
#include "content/common/content_export.h"
-#include "net/base/completion_callback.h"
#include "url/origin.h"
class GURL;
diff --git a/chromium/content/browser/appcache/appcache_storage_impl.cc b/chromium/content/browser/appcache/appcache_storage_impl.cc
index b7003845da0..7ca367b82d4 100644
--- a/chromium/content/browser/appcache/appcache_storage_impl.cc
+++ b/chromium/content/browser/appcache/appcache_storage_impl.cc
@@ -35,7 +35,7 @@
#include "content/public/common/content_switches.h"
#include "net/base/cache_type.h"
#include "net/base/net_errors.h"
-#include "sql/connection.h"
+#include "sql/database.h"
#include "sql/transaction.h"
#include "storage/browser/quota/quota_client.h"
#include "storage/browser/quota/quota_manager.h"
@@ -44,17 +44,20 @@
namespace content {
-const int kMB = 1024 * 1024;
+namespace {
+
+constexpr const int kMB = 1024 * 1024;
// Hard coded default when not using quota management.
-static const int kDefaultQuota = 5 * kMB;
+constexpr const int kDefaultQuota = 5 * kMB;
-static const int kMaxAppCacheDiskCacheSize = 250 * kMB;
-static const int kMaxAppCacheMemDiskCacheSize = 10 * kMB;
-static const base::FilePath::CharType kDiskCacheDirectoryName[] =
- FILE_PATH_LITERAL("Cache");
+constexpr const int kMaxAppCacheDiskCacheSize = 250 * kMB;
+constexpr const int kMaxAppCacheMemDiskCacheSize = 10 * kMB;
-namespace {
+constexpr base::FilePath::CharType kDiskCacheDirectoryName[] =
+ FILE_PATH_LITERAL("Cache");
+constexpr base::FilePath::CharType kAppCacheDatabaseName[] =
+ FILE_PATH_LITERAL("Index");
// Helpers for clearing data from the AppCacheDatabase.
bool DeleteGroupAndRelatedRecords(
@@ -107,7 +110,7 @@ void AppCacheStorageImpl::ClearSessionOnlyOrigins(
if (origins.empty())
return; // nothing to delete
- sql::Connection* connection = database->db_connection();
+ sql::Database* connection = database->db_connection();
if (!connection) {
NOTREACHED() << "Missing database connection.";
return;
@@ -701,7 +704,7 @@ void AppCacheStorageImpl::StoreGroupAndCacheTask::OnQuotaCallback(
void AppCacheStorageImpl::StoreGroupAndCacheTask::Run() {
DCHECK(!success_);
- sql::Connection* connection = database_->db_connection();
+ sql::Database* connection = database_->db_connection();
if (!connection)
return;
@@ -872,7 +875,7 @@ class NetworkNamespaceHelper {
bool IsInNetworkNamespace(const GURL& url, int64_t cache_id) {
std::pair<WhiteListMap::iterator, bool> result = namespaces_map_.insert(
- WhiteListMap::value_type(cache_id, AppCacheNamespaceVector()));
+ WhiteListMap::value_type(cache_id, std::vector<AppCacheNamespace>()));
if (result.second)
GetOnlineWhiteListForCache(cache_id, &result.first->second);
return AppCache::FindNamespace(result.first->second, url) != nullptr;
@@ -880,7 +883,7 @@ class NetworkNamespaceHelper {
private:
void GetOnlineWhiteListForCache(int64_t cache_id,
- AppCacheNamespaceVector* namespaces) {
+ std::vector<AppCacheNamespace>* namespaces) {
DCHECK(namespaces && namespaces->empty());
using WhiteListVector =
std::vector<AppCacheDatabase::OnlineWhiteListRecord>;
@@ -896,7 +899,7 @@ class NetworkNamespaceHelper {
}
// Key is cache id
- using WhiteListMap = std::map<int64_t, AppCacheNamespaceVector>;
+ using WhiteListMap = std::map<int64_t, std::vector<AppCacheNamespace>>;
WhiteListMap namespaces_map_;
AppCacheDatabase* database_;
};
@@ -1185,7 +1188,7 @@ AppCacheStorageImpl::MakeGroupObsoleteTask::MakeGroupObsoleteTask(
void AppCacheStorageImpl::MakeGroupObsoleteTask::Run() {
DCHECK(!success_);
- sql::Connection* connection = database_->db_connection();
+ sql::Database* connection = database_->db_connection();
if (!connection)
return;
@@ -1975,8 +1978,8 @@ void AppCacheStorageImpl::LazilyCommitLastAccessTimes() {
const base::TimeDelta kDelay = base::TimeDelta::FromMinutes(5);
lazy_commit_timer_.Start(
FROM_HERE, kDelay,
- base::Bind(&AppCacheStorageImpl::OnLazyCommitTimer,
- weak_factory_.GetWeakPtr()));
+ base::BindOnce(&AppCacheStorageImpl::OnLazyCommitTimer,
+ weak_factory_.GetWeakPtr()));
}
void AppCacheStorageImpl::OnLazyCommitTimer() {
diff --git a/chromium/content/browser/appcache/appcache_storage_unittest.cc b/chromium/content/browser/appcache/appcache_storage_unittest.cc
index 961299a6eaa..b3ebc6a12e5 100644
--- a/chromium/content/browser/appcache/appcache_storage_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_storage_unittest.cc
@@ -29,7 +29,8 @@ class AppCacheStorageTest : public testing::Test {
TEST_F(AppCacheStorageTest, AddRemoveCache) {
MockAppCacheService service;
- scoped_refptr<AppCache> cache(new AppCache(service.storage(), 111));
+ scoped_refptr<AppCache> cache =
+ base::MakeRefCounted<AppCache>(service.storage(), 111);
EXPECT_EQ(cache.get(),
service.storage()->working_set()->GetCache(111));
@@ -45,14 +46,16 @@ TEST_F(AppCacheStorageTest, AddRemoveCache) {
TEST_F(AppCacheStorageTest, AddRemoveGroup) {
MockAppCacheService service;
- scoped_refptr<AppCacheGroup> group(
- new AppCacheGroup(service.storage(), GURL(), 111));
+ const GURL kManifestUrl("http://origin/");
+ scoped_refptr<AppCacheGroup> group =
+ base::MakeRefCounted<AppCacheGroup>(service.storage(), kManifestUrl, 111);
- EXPECT_EQ(group.get(), service.storage()->working_set()->GetGroup(GURL()));
+ EXPECT_EQ(group.get(),
+ service.storage()->working_set()->GetGroup(kManifestUrl));
service.storage()->working_set()->RemoveGroup(group.get());
- EXPECT_TRUE(!service.storage()->working_set()->GetGroup(GURL()));
+ EXPECT_TRUE(!service.storage()->working_set()->GetGroup(kManifestUrl));
// Removing non-existing group from service should not fail.
MockAppCacheService dummy;
@@ -61,10 +64,11 @@ TEST_F(AppCacheStorageTest, AddRemoveGroup) {
TEST_F(AppCacheStorageTest, AddRemoveResponseInfo) {
MockAppCacheService service;
- scoped_refptr<AppCacheResponseInfo> info(
- new AppCacheResponseInfo(service.storage(), GURL(),
- 111, new net::HttpResponseInfo,
- kUnkownResponseDataSize));
+ const GURL kManifestUrl("http://origin/");
+ scoped_refptr<AppCacheResponseInfo> info =
+ base::MakeRefCounted<AppCacheResponseInfo>(
+ service.storage(), kManifestUrl, 111,
+ std::make_unique<net::HttpResponseInfo>(), kUnkownResponseDataSize);
EXPECT_EQ(info.get(),
service.storage()->working_set()->GetResponseInfo(111));
@@ -121,8 +125,8 @@ TEST_F(AppCacheStorageTest, UsageMap) {
const url::Origin kOrigin2(url::Origin::Create(GURL("http://origin2/")));
MockAppCacheService service;
- scoped_refptr<MockQuotaManagerProxy> mock_proxy(
- new MockQuotaManagerProxy(nullptr, nullptr));
+ scoped_refptr<MockQuotaManagerProxy> mock_proxy =
+ base::MakeRefCounted<MockQuotaManagerProxy>(nullptr, nullptr);
service.set_quota_manager_proxy(mock_proxy.get());
service.storage()->UpdateUsageMapAndNotify(kOrigin, 0);
diff --git a/chromium/content/browser/appcache/appcache_subresource_url_factory.cc b/chromium/content/browser/appcache/appcache_subresource_url_factory.cc
index 08336328e4e..c3f75f9d9a1 100644
--- a/chromium/content/browser/appcache/appcache_subresource_url_factory.cc
+++ b/chromium/content/browser/appcache/appcache_subresource_url_factory.cc
@@ -108,7 +108,7 @@ class SubresourceLoader : public network::mojom::URLLoader,
network::mojom::URLLoaderClientPtr client_ptr;
local_client_binding_.Bind(mojo::MakeRequest(&client_ptr));
- std::move(handler).Run(mojo::MakeRequest(&appcache_loader_),
+ std::move(handler).Run(request_, mojo::MakeRequest(&appcache_loader_),
std::move(client_ptr));
}
diff --git a/chromium/content/browser/appcache/appcache_unittest.cc b/chromium/content/browser/appcache/appcache_unittest.cc
index 5fb6ea92bea..67c8b01e9a8 100644
--- a/chromium/content/browser/appcache/appcache_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_unittest.cc
@@ -5,6 +5,8 @@
#include <stddef.h>
#include <stdint.h>
+#include <vector>
+
#include "base/test/scoped_task_environment.h"
#include "content/browser/appcache/appcache.h"
#include "content/browser/appcache/appcache_host.h"
@@ -136,7 +138,7 @@ TEST_F(AppCacheTest, InitializeWithManifest) {
EXPECT_EQ(GURL("http://fb1.com"), fallbacks[0].namespace_url);
EXPECT_EQ(GURL("http://fbone.com"), fallbacks[0].target_url);
EXPECT_TRUE(fallbacks[0].is_pattern);
- const AppCacheNamespaceVector& whitelist =
+ const std::vector<AppCacheNamespace>& whitelist =
cache->online_whitelist_namespaces_;
expected = 2;
EXPECT_EQ(expected, whitelist.size());
diff --git a/chromium/content/browser/appcache/appcache_update_job.cc b/chromium/content/browser/appcache/appcache_update_job.cc
index a6d641667cb..32be530befe 100644
--- a/chromium/content/browser/appcache/appcache_update_job.cc
+++ b/chromium/content/browser/appcache/appcache_update_job.cc
@@ -688,8 +688,9 @@ void AppCacheUpdateJob::HandleManifestRefetchCompleted(URLFetcher* fetcher,
StoreGroupAndCache();
} else {
manifest_response_writer_.reset(CreateResponseWriter());
- scoped_refptr<HttpResponseInfoIOBuffer> io_buffer(
- new HttpResponseInfoIOBuffer(manifest_response_info_.release()));
+ scoped_refptr<HttpResponseInfoIOBuffer> io_buffer =
+ base::MakeRefCounted<HttpResponseInfoIOBuffer>(
+ std::move(manifest_response_info_));
manifest_response_writer_->WriteInfo(
io_buffer.get(),
base::BindOnce(&AppCacheUpdateJob::OnManifestInfoWriteComplete,
@@ -893,7 +894,8 @@ void AppCacheUpdateJob::CheckIfManifestChanged() {
GURL(), 0, false /*is_cross_origin*/),
DB_ERROR, GURL());
AppCacheHistograms::AddMissingManifestEntrySample();
- service->DeleteAppCacheGroup(manifest_url_, net::CompletionCallback());
+ service->DeleteAppCacheGroup(manifest_url_,
+ net::CompletionOnceCallback());
}
return;
}
@@ -989,8 +991,8 @@ void AppCacheUpdateJob::FetchUrls() {
DCHECK(existing_entry->response_id() ==
url_to_fetch.existing_response_info->response_id());
fetcher->set_existing_response_headers(
- url_to_fetch.existing_response_info->http_response_info()->headers
- .get());
+ url_to_fetch.existing_response_info->http_response_info()
+ .headers.get());
fetcher->set_existing_entry(*existing_entry);
}
fetcher->Start();
@@ -1167,7 +1169,7 @@ void AppCacheUpdateJob::OnResponseInfoLoaded(
AppCacheResponseInfo* response_info,
int64_t response_id) {
const net::HttpResponseInfo* http_info =
- response_info ? response_info->http_response_info() : nullptr;
+ response_info ? &response_info->http_response_info() : nullptr;
// Needed response info for a manifest fetch request.
if (internal_state_ == FETCH_MANIFEST) {
diff --git a/chromium/content/browser/appcache/appcache_update_job.h b/chromium/content/browser/appcache/appcache_update_job.h
index 262da887387..79eabef47b1 100644
--- a/chromium/content/browser/appcache/appcache_update_job.h
+++ b/chromium/content/browser/appcache/appcache_update_job.h
@@ -26,7 +26,6 @@
#include "content/browser/appcache/appcache_storage.h"
#include "content/common/appcache_interfaces.h"
#include "content/common/content_export.h"
-#include "net/base/completion_callback.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request.h"
#include "url/gurl.h"
diff --git a/chromium/content/browser/appcache/appcache_update_job_unittest.cc b/chromium/content/browser/appcache/appcache_update_job_unittest.cc
index d801ffce9a4..6cb4ce06c35 100644
--- a/chromium/content/browser/appcache/appcache_update_job_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_update_job_unittest.cc
@@ -7,6 +7,7 @@
#include <stddef.h>
#include <stdint.h>
+#include <memory>
#include <utility>
#include "base/bind.h"
@@ -1388,14 +1389,17 @@ class AppCacheUpdateJobTest : public testing::TestWithParam<RequestHandlerType>,
"HTTP/1.1 200 OK\0"
"Cache-Control: max-age=8675309\0"
"\0";
- net::HttpResponseHeaders* headers =
- new net::HttpResponseHeaders(std::string(data, arraysize(data)));
- net::HttpResponseInfo* response_info = new net::HttpResponseInfo();
+ scoped_refptr<net::HttpResponseHeaders> headers =
+ base::MakeRefCounted<net::HttpResponseHeaders>(
+ std::string(data, base::size(data)));
+ std::unique_ptr<net::HttpResponseInfo> response_info =
+ std::make_unique<net::HttpResponseInfo>();
response_info->request_time = base::Time::Now();
response_info->response_time = base::Time::Now();
- response_info->headers = headers; // adds ref to headers
- scoped_refptr<HttpResponseInfoIOBuffer> io_buffer(
- new HttpResponseInfoIOBuffer(response_info)); // adds ref to info
+ response_info->headers = std::move(headers);
+ scoped_refptr<HttpResponseInfoIOBuffer> io_buffer =
+ base::MakeRefCounted<HttpResponseInfoIOBuffer>(
+ std::move(response_info));
response_writer_->WriteInfo(
io_buffer.get(),
base::BindOnce(
@@ -1451,14 +1455,17 @@ class AppCacheUpdateJobTest : public testing::TestWithParam<RequestHandlerType>,
"HTTP/1.1 200 OK\0"
"Expires: Thu, 01 Dec 1994 16:00:00 GMT\0"
"\0";
- net::HttpResponseHeaders* headers =
- new net::HttpResponseHeaders(std::string(data, arraysize(data)));
- net::HttpResponseInfo* response_info = new net::HttpResponseInfo();
+ scoped_refptr<net::HttpResponseHeaders> headers =
+ base::MakeRefCounted<net::HttpResponseHeaders>(
+ std::string(data, base::size(data)));
+ std::unique_ptr<net::HttpResponseInfo> response_info =
+ std::make_unique<net::HttpResponseInfo>();
response_info->request_time = base::Time::Now();
response_info->response_time = base::Time::Now();
- response_info->headers = headers; // adds ref to headers
- scoped_refptr<HttpResponseInfoIOBuffer> io_buffer(
- new HttpResponseInfoIOBuffer(response_info)); // adds ref to info
+ response_info->headers = std::move(headers);
+ scoped_refptr<HttpResponseInfoIOBuffer> io_buffer =
+ base::MakeRefCounted<HttpResponseInfoIOBuffer>(
+ std::move(response_info));
response_writer_->WriteInfo(
io_buffer.get(),
base::BindOnce(
@@ -1514,14 +1521,17 @@ class AppCacheUpdateJobTest : public testing::TestWithParam<RequestHandlerType>,
"Cache-Control: max-age=8675309\0"
"Vary: blah\0"
"\0";
- net::HttpResponseHeaders* headers =
- new net::HttpResponseHeaders(std::string(data, arraysize(data)));
- net::HttpResponseInfo* response_info = new net::HttpResponseInfo();
+ scoped_refptr<net::HttpResponseHeaders> headers =
+ base::MakeRefCounted<net::HttpResponseHeaders>(
+ std::string(data, base::size(data)));
+ std::unique_ptr<net::HttpResponseInfo> response_info =
+ std::make_unique<net::HttpResponseInfo>();
response_info->request_time = base::Time::Now();
response_info->response_time = base::Time::Now();
- response_info->headers = headers; // adds ref to headers
- scoped_refptr<HttpResponseInfoIOBuffer> io_buffer(
- new HttpResponseInfoIOBuffer(response_info)); // adds ref to info
+ response_info->headers = std::move(headers);
+ scoped_refptr<HttpResponseInfoIOBuffer> io_buffer =
+ base::MakeRefCounted<HttpResponseInfoIOBuffer>(
+ std::move(response_info));
response_writer_->WriteInfo(
io_buffer.get(),
base::BindOnce(
@@ -1581,14 +1591,17 @@ class AppCacheUpdateJobTest : public testing::TestWithParam<RequestHandlerType>,
"Cache-Control: max-age=8675309\0"
"Vary: origin, accept-encoding\0"
"\0";
- net::HttpResponseHeaders* headers =
- new net::HttpResponseHeaders(std::string(data, arraysize(data)));
- net::HttpResponseInfo* response_info = new net::HttpResponseInfo();
+ scoped_refptr<net::HttpResponseHeaders> headers =
+ base::MakeRefCounted<net::HttpResponseHeaders>(
+ std::string(data, base::size(data)));
+ std::unique_ptr<net::HttpResponseInfo> response_info =
+ std::make_unique<net::HttpResponseInfo>();
response_info->request_time = base::Time::Now();
response_info->response_time = base::Time::Now();
- response_info->headers = headers; // adds ref to headers
- scoped_refptr<HttpResponseInfoIOBuffer> io_buffer(
- new HttpResponseInfoIOBuffer(response_info)); // adds ref to info
+ response_info->headers = std::move(headers);
+ scoped_refptr<HttpResponseInfoIOBuffer> io_buffer =
+ base::MakeRefCounted<HttpResponseInfoIOBuffer>(
+ std::move(response_info));
response_writer_->WriteInfo(
io_buffer.get(),
base::BindOnce(
@@ -3204,12 +3217,15 @@ class AppCacheUpdateJobTest : public testing::TestWithParam<RequestHandlerType>,
"HTTP/1.1 200 OK\0"
"Last-Modified: Sat, 29 Oct 1994 19:43:31 GMT\0"
"\0";
- net::HttpResponseHeaders* headers =
- new net::HttpResponseHeaders(std::string(data, arraysize(data)));
- net::HttpResponseInfo* response_info = new net::HttpResponseInfo();
- response_info->headers = headers; // adds ref to headers
- scoped_refptr<HttpResponseInfoIOBuffer> io_buffer(
- new HttpResponseInfoIOBuffer(response_info)); // adds ref to info
+ scoped_refptr<net::HttpResponseHeaders> headers =
+ base::MakeRefCounted<net::HttpResponseHeaders>(
+ std::string(data, base::size(data)));
+ std::unique_ptr<net::HttpResponseInfo> response_info =
+ std::make_unique<net::HttpResponseInfo>();
+ response_info->headers = std::move(headers);
+ scoped_refptr<HttpResponseInfoIOBuffer> io_buffer =
+ base::MakeRefCounted<HttpResponseInfoIOBuffer>(
+ std::move(response_info));
response_writer_->WriteInfo(
io_buffer.get(),
base::BindOnce(
@@ -3274,12 +3290,15 @@ class AppCacheUpdateJobTest : public testing::TestWithParam<RequestHandlerType>,
"HTTP/1.1 200 OK\0"
"ETag: \"LadeDade\"\0"
"\0";
- net::HttpResponseHeaders* headers =
- new net::HttpResponseHeaders(std::string(data, arraysize(data)));
- net::HttpResponseInfo* response_info = new net::HttpResponseInfo();
- response_info->headers = headers; // adds ref to headers
- scoped_refptr<HttpResponseInfoIOBuffer> io_buffer(
- new HttpResponseInfoIOBuffer(response_info)); // adds ref to info
+ scoped_refptr<net::HttpResponseHeaders> headers =
+ base::MakeRefCounted<net::HttpResponseHeaders>(
+ std::string(data, base::size(data)));
+ std::unique_ptr<net::HttpResponseInfo> response_info =
+ std::make_unique<net::HttpResponseInfo>();
+ response_info->headers = std::move(headers);
+ scoped_refptr<HttpResponseInfoIOBuffer> io_buffer =
+ base::MakeRefCounted<HttpResponseInfoIOBuffer>(
+ std::move(response_info));
response_writer_->WriteInfo(
io_buffer.get(),
base::BindOnce(
@@ -3532,11 +3551,12 @@ class AppCacheUpdateJobTest : public testing::TestWithParam<RequestHandlerType>,
const GURL& manifest_url,
int64_t response_id,
const std::string& raw_headers) {
- net::HttpResponseInfo* http_info = new net::HttpResponseInfo();
+ std::unique_ptr<net::HttpResponseInfo> http_info =
+ std::make_unique<net::HttpResponseInfo>();
http_info->headers = new net::HttpResponseHeaders(raw_headers);
scoped_refptr<AppCacheResponseInfo> info(
- new AppCacheResponseInfo(service_->storage(), manifest_url,
- response_id, http_info, 0));
+ new AppCacheResponseInfo(service_->storage(), manifest_url, response_id,
+ std::move(http_info), 0));
response_infos_.push_back(info);
return info.get();
}
diff --git a/chromium/content/browser/appcache/appcache_update_url_fetcher.cc b/chromium/content/browser/appcache/appcache_update_url_fetcher.cc
index f364e70cf9a..e9652f899a3 100644
--- a/chromium/content/browser/appcache/appcache_update_url_fetcher.cc
+++ b/chromium/content/browser/appcache/appcache_update_url_fetcher.cc
@@ -107,9 +107,10 @@ void AppCacheUpdateJob::URLFetcher::OnResponseStarted(int net_error) {
// completion before reading any response data.
if (fetch_type_ == URL_FETCH || fetch_type_ == MASTER_ENTRY_FETCH) {
response_writer_.reset(job_->CreateResponseWriter());
- scoped_refptr<HttpResponseInfoIOBuffer> io_buffer(
- new HttpResponseInfoIOBuffer(
- new net::HttpResponseInfo(request_->GetResponseInfo())));
+ scoped_refptr<HttpResponseInfoIOBuffer> io_buffer =
+ base::MakeRefCounted<HttpResponseInfoIOBuffer>(
+ std::make_unique<net::HttpResponseInfo>(
+ request_->GetResponseInfo()));
response_writer_->WriteInfo(
io_buffer.get(),
base::BindOnce(&URLFetcher::OnWriteComplete, base::Unretained(this)));
diff --git a/chromium/content/browser/appcache/appcache_url_loader_job.cc b/chromium/content/browser/appcache/appcache_url_loader_job.cc
index 1455c9f3f23..e4245c4861f 100644
--- a/chromium/content/browser/appcache/appcache_url_loader_job.cc
+++ b/chromium/content/browser/appcache/appcache_url_loader_job.cc
@@ -44,9 +44,6 @@ void AppCacheURLLoaderJob::DeliverAppCachedResponse(const GURL& manifest_url,
load_timing_info_.request_start_time = base::Time::Now();
load_timing_info_.request_start = base::TimeTicks::Now();
- AppCacheHistograms::AddAppCacheJobStartDelaySample(base::TimeTicks::Now() -
- start_time_tick_);
-
manifest_url_ = manifest_url;
cache_id_ = cache_id;
entry_ = entry;
@@ -66,16 +63,11 @@ void AppCacheURLLoaderJob::DeliverNetworkResponse() {
if (AppCacheRequestHandler::IsRunningInTests())
return;
- AppCacheHistograms::AddNetworkJobStartDelaySample(base::TimeTicks::Now() -
- start_time_tick_);
-
// We signal our caller with an empy callback that it needs to perform
// the network load.
DCHECK(loader_callback_ && !binding_.is_bound());
std::move(loader_callback_).Run({});
- weak_factory_.InvalidateWeakPtrs();
- is_deleting_soon_ = true;
- base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
+ DeleteSoon();
}
void AppCacheURLLoaderJob::DeliverErrorResponse() {
@@ -87,10 +79,18 @@ void AppCacheURLLoaderJob::DeliverErrorResponse() {
if (loader_callback_)
CallLoaderCallback();
- NotifyCompleted(net::ERR_FAILED);
- AppCacheHistograms::AddErrorJobStartDelaySample(base::TimeTicks::Now() -
- start_time_tick_);
+ if (!client_) {
+ // Although all callsites that lead to construction of AppCacheURLLoaderJob
+ // provide a NavigationLoaderInterceptor::LoaderCallback, some use weak
+ // pointers to bind it. So it's possible that in between the time that
+ // AppCacheURLLoaderJob grabs the response info from storage that the
+ // callback is now empty, which leads to client_ not being initialized.
+ DeleteSoon();
+ return;
+ }
+
+ NotifyCompleted(net::ERR_FAILED);
}
AppCacheURLLoaderJob* AppCacheURLLoaderJob::AsURLLoaderJob() {
@@ -129,13 +129,18 @@ void AppCacheURLLoaderJob::DeleteIfNeeded() {
delete this;
}
-void AppCacheURLLoaderJob::Start(network::mojom::URLLoaderRequest request,
- network::mojom::URLLoaderClientPtr client) {
+void AppCacheURLLoaderJob::Start(
+ const network::ResourceRequest& /* resource_request */,
+ network::mojom::URLLoaderRequest request,
+ network::mojom::URLLoaderClientPtr client) {
+ // TODO(crbug.com/876531): Figure out how AppCache interception should
+ // interact with URLLoaderThrottles. It might be incorrect to ignore
+ // |resource_request| here, since it's the current request after throttles.
DCHECK(!binding_.is_bound());
binding_.Bind(std::move(request));
client_ = std::move(client);
- binding_.set_connection_error_handler(base::BindOnce(
- &AppCacheURLLoaderJob::OnConnectionError, GetDerivedWeakPtr()));
+ binding_.set_connection_error_handler(
+ base::BindOnce(&AppCacheURLLoaderJob::DeleteSoon, GetDerivedWeakPtr()));
}
AppCacheURLLoaderJob::AppCacheURLLoaderJob(
@@ -178,6 +183,12 @@ void AppCacheURLLoaderJob::OnResponseInfoLoaded(
if (loader_callback_)
CallLoaderCallback();
+ if (!client_) {
+ // See comment in DeliverErrorResponse.
+ DeleteSoon();
+ return;
+ }
+
info_ = response_info;
reader_.reset(
storage_->CreateResponseReader(manifest_url_, entry_.response_id()));
@@ -248,7 +259,7 @@ void AppCacheURLLoaderJob::OnResponseBodyStreamReady(MojoResult result) {
ReadMore();
}
-void AppCacheURLLoaderJob::OnConnectionError() {
+void AppCacheURLLoaderJob::DeleteSoon() {
if (storage_.get())
storage_->CancelDelegateCallbacks(this);
weak_factory_.InvalidateWeakPtrs();
@@ -257,36 +268,34 @@ void AppCacheURLLoaderJob::OnConnectionError() {
}
void AppCacheURLLoaderJob::SendResponseInfo() {
- DCHECK(client_);
// If this is null it means the response information was sent to the client.
if (!data_pipe_.consumer_handle.is_valid())
return;
- const net::HttpResponseInfo* http_info = is_range_request()
- ? range_response_info_.get()
- : info_->http_response_info();
+ const net::HttpResponseInfo& http_info =
+ is_range_request() ? *range_response_info_ : info_->http_response_info();
network::ResourceResponseHead response_head;
- response_head.headers = http_info->headers;
+ response_head.headers = http_info.headers;
response_head.appcache_id = cache_id_;
response_head.appcache_manifest_url = manifest_url_;
- http_info->headers->GetMimeType(&response_head.mime_type);
- http_info->headers->GetCharset(&response_head.charset);
+ http_info.headers->GetMimeType(&response_head.mime_type);
+ http_info.headers->GetCharset(&response_head.charset);
// TODO(ananta)
// Verify if the times sent here are correct.
- response_head.request_time = http_info->request_time;
- response_head.response_time = http_info->response_time;
+ response_head.request_time = http_info.request_time;
+ response_head.response_time = http_info.response_time;
response_head.content_length =
is_range_request() ? range_response_info_->headers->GetContentLength()
: info_->response_data_size();
- response_head.connection_info = http_info->connection_info;
- response_head.socket_address = http_info->socket_address;
- response_head.was_fetched_via_spdy = http_info->was_fetched_via_spdy;
- response_head.was_alpn_negotiated = http_info->was_alpn_negotiated;
- response_head.alpn_negotiated_protocol = http_info->alpn_negotiated_protocol;
- if (http_info->ssl_info.cert)
- response_head.ssl_info = http_info->ssl_info;
+ response_head.connection_info = http_info.connection_info;
+ response_head.socket_address = http_info.socket_address;
+ response_head.was_fetched_via_spdy = http_info.was_fetched_via_spdy;
+ response_head.was_alpn_negotiated = http_info.was_alpn_negotiated;
+ response_head.alpn_negotiated_protocol = http_info.alpn_negotiated_protocol;
+ if (http_info.ssl_info.cert)
+ response_head.ssl_info = http_info.ssl_info;
response_head.load_timing = load_timing_info_;
client_->OnReceiveResponse(response_head);
@@ -334,7 +343,7 @@ void AppCacheURLLoaderJob::NotifyCompleted(int error_code) {
if (!error_code) {
const net::HttpResponseInfo* http_info =
is_range_request() ? range_response_info_.get()
- : (info_ ? info_->http_response_info() : nullptr);
+ : (info_ ? &info_->http_response_info() : nullptr);
status.exists_in_cache = http_info->was_cached;
status.completion_time = base::TimeTicks::Now();
status.encoded_body_length =
diff --git a/chromium/content/browser/appcache/appcache_url_loader_job.h b/chromium/content/browser/appcache/appcache_url_loader_job.h
index 1cc9ae22816..93767a7ca5f 100644
--- a/chromium/content/browser/appcache/appcache_url_loader_job.h
+++ b/chromium/content/browser/appcache/appcache_url_loader_job.h
@@ -39,7 +39,8 @@ class CONTENT_EXPORT AppCacheURLLoaderJob : public AppCacheJob,
~AppCacheURLLoaderJob() override;
// Sets up the bindings.
- void Start(network::mojom::URLLoaderRequest request,
+ void Start(const network::ResourceRequest& resource_request,
+ network::mojom::URLLoaderRequest request,
network::mojom::URLLoaderClientPtr client);
// AppCacheJob overrides.
@@ -89,8 +90,9 @@ class CONTENT_EXPORT AppCacheURLLoaderJob : public AppCacheJob,
// Callback invoked when the data pipe can be written to.
void OnResponseBodyStreamReady(MojoResult result);
- // Mojo binding error handler.
- void OnConnectionError();
+ // Schedules a task to delete self with some clean-ups. This is also used as
+ // a mojo binding error handler.
+ void DeleteSoon();
void SendResponseInfo();
void ReadMore();
diff --git a/chromium/content/browser/appcache/appcache_url_loader_request.cc b/chromium/content/browser/appcache/appcache_url_loader_request.cc
index 03e37c05688..75bd7798eec 100644
--- a/chromium/content/browser/appcache/appcache_url_loader_request.cc
+++ b/chromium/content/browser/appcache/appcache_url_loader_request.cc
@@ -84,6 +84,7 @@ void AppCacheURLLoaderRequest::UpdateWithRedirectInfo(
request_.url = redirect_info.new_url;
request_.method = redirect_info.new_method;
request_.referrer = GURL(redirect_info.new_referrer);
+ request_.referrer_policy = redirect_info.new_referrer_policy;
request_.site_for_cookies = redirect_info.new_site_for_cookies;
}
diff --git a/chromium/content/browser/appcache/appcache_url_request_job.cc b/chromium/content/browser/appcache/appcache_url_request_job.cc
index 70fd5664338..d0c16f3b250 100644
--- a/chromium/content/browser/appcache/appcache_url_request_job.cc
+++ b/chromium/content/browser/appcache/appcache_url_request_job.cc
@@ -138,8 +138,6 @@ void AppCacheURLRequestJob::BeginDelivery() {
switch (delivery_type_) {
case NETWORK_DELIVERY:
- AppCacheHistograms::AddNetworkJobStartDelaySample(
- base::TimeTicks::Now() - start_time_tick_);
// To fallthru to the network, we restart the request which will
// cause a new job to be created to retrieve the resource from the
// network. Our caller is responsible for arranging to not re-intercept
@@ -148,8 +146,6 @@ void AppCacheURLRequestJob::BeginDelivery() {
break;
case ERROR_DELIVERY:
- AppCacheHistograms::AddErrorJobStartDelaySample(
- base::TimeTicks::Now() - start_time_tick_);
request()->net_log().AddEvent(
net::NetLogEventType::APPCACHE_DELIVERING_ERROR_RESPONSE);
NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
@@ -157,8 +153,6 @@ void AppCacheURLRequestJob::BeginDelivery() {
break;
case APPCACHED_DELIVERY:
- AppCacheHistograms::AddAppCacheJobStartDelaySample(
- base::TimeTicks::Now() - start_time_tick_);
request()->net_log().AddEvent(
is_fallback_
? net::NetLogEventType::APPCACHE_DELIVERING_FALLBACK_RESPONSE
@@ -222,7 +216,7 @@ const net::HttpResponseInfo* AppCacheURLRequestJob::http_info() const {
return nullptr;
if (range_response_info_)
return range_response_info_.get();
- return info_->http_response_info();
+ return &info_->http_response_info();
}
void AppCacheURLRequestJob::OnReadComplete(int result) {
diff --git a/chromium/content/browser/appcache/appcache_url_request_job_unittest.cc b/chromium/content/browser/appcache/appcache_url_request_job_unittest.cc
index f8413977f0e..266c8173551 100644
--- a/chromium/content/browser/appcache/appcache_url_request_job_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_url_request_job_unittest.cc
@@ -337,25 +337,28 @@ class AppCacheURLRequestJobTest : public testing::Test {
// Wrappers to call AppCacheResponseReader/Writer Read and Write methods
void WriteBasicResponse() {
- scoped_refptr<IOBuffer> body(new WrappedIOBuffer(kHttpBasicBody));
+ scoped_refptr<IOBuffer> body =
+ base::MakeRefCounted<WrappedIOBuffer>(kHttpBasicBody);
std::string raw_headers(kHttpBasicHeaders, arraysize(kHttpBasicHeaders));
WriteResponse(
MakeHttpResponseInfo(raw_headers), body.get(), strlen(kHttpBasicBody));
}
- void WriteResponse(net::HttpResponseInfo* head,
- IOBuffer* body, int body_len) {
+ void WriteResponse(std::unique_ptr<net::HttpResponseInfo> head,
+ IOBuffer* body,
+ int body_len) {
DCHECK(body);
scoped_refptr<IOBuffer> body_ref(body);
PushNextTask(base::BindOnce(&AppCacheURLRequestJobTest::WriteResponseBody,
base::Unretained(this), body_ref, body_len));
- WriteResponseHead(head);
+ WriteResponseHead(std::move(head));
}
- void WriteResponseHead(net::HttpResponseInfo* head) {
+ void WriteResponseHead(std::unique_ptr<net::HttpResponseInfo> head) {
EXPECT_FALSE(writer_->IsWritePending());
- expected_write_result_ = GetHttpResponseInfoSize(head);
- write_info_buffer_ = new HttpResponseInfoIOBuffer(head);
+ expected_write_result_ = GetHttpResponseInfoSize(*head);
+ write_info_buffer_ =
+ base::MakeRefCounted<HttpResponseInfoIOBuffer>(std::move(head));
writer_->WriteInfo(
write_info_buffer_.get(),
base::BindOnce(&AppCacheURLRequestJobTest::OnWriteInfoComplete,
@@ -409,36 +412,36 @@ class AppCacheURLRequestJobTest : public testing::Test {
// Helpers to work with HttpResponseInfo objects
- net::HttpResponseInfo* MakeHttpResponseInfo(const std::string& raw_headers) {
- net::HttpResponseInfo* info = new net::HttpResponseInfo;
+ std::unique_ptr<net::HttpResponseInfo> MakeHttpResponseInfo(
+ const std::string& raw_headers) {
+ std::unique_ptr<net::HttpResponseInfo> info =
+ std::make_unique<net::HttpResponseInfo>();
info->request_time = base::Time::Now();
info->response_time = base::Time::Now();
info->was_cached = false;
- info->headers = new net::HttpResponseHeaders(raw_headers);
+ info->headers = base::MakeRefCounted<net::HttpResponseHeaders>(raw_headers);
return info;
}
- int GetHttpResponseInfoSize(const net::HttpResponseInfo* info) {
- base::Pickle pickle;
- return PickleHttpResonseInfo(&pickle, info);
+ int GetHttpResponseInfoSize(const net::HttpResponseInfo& info) {
+ base::Pickle pickle = PickleHttpResonseInfo(info);
+ return pickle.size();
}
- bool CompareHttpResponseInfos(const net::HttpResponseInfo* info1,
- const net::HttpResponseInfo* info2) {
- base::Pickle pickle1;
- base::Pickle pickle2;
- PickleHttpResonseInfo(&pickle1, info1);
- PickleHttpResonseInfo(&pickle2, info2);
+ bool CompareHttpResponseInfos(const net::HttpResponseInfo& info1,
+ const net::HttpResponseInfo& info2) {
+ base::Pickle pickle1 = PickleHttpResonseInfo(info1);
+ base::Pickle pickle2 = PickleHttpResonseInfo(info2);
return (pickle1.size() == pickle2.size()) &&
(0 == memcmp(pickle1.data(), pickle2.data(), pickle1.size()));
}
- int PickleHttpResonseInfo(base::Pickle* pickle,
- const net::HttpResponseInfo* info) {
+ base::Pickle PickleHttpResonseInfo(const net::HttpResponseInfo& info) {
const bool kSkipTransientHeaders = true;
const bool kTruncated = false;
- info->Persist(pickle, kSkipTransientHeaders, kTruncated);
- return pickle->size();
+ base::Pickle pickle;
+ info.Persist(&pickle, kSkipTransientHeaders, kTruncated);
+ return pickle;
}
// Helpers to fill and verify blocks of memory with a value
@@ -665,8 +668,7 @@ class AppCacheURLRequestJobTest : public testing::Test {
void VerifyDeliverSmallAppCachedResponse() {
EXPECT_EQ(net::OK, url_request_delegate_->request_status());
EXPECT_TRUE(CompareHttpResponseInfos(
- write_info_buffer_->http_info.get(),
- &url_request_delegate_->received_info_));
+ *write_info_buffer_->http_info, url_request_delegate_->received_info_));
EXPECT_EQ(5, url_request_delegate_->amount_received_);
EXPECT_EQ(0, memcmp(kHttpBasicBody,
url_request_delegate_->received_data_->data(),
@@ -712,8 +714,7 @@ class AppCacheURLRequestJobTest : public testing::Test {
void VerifyDeliverLargeAppCachedResponse() {
EXPECT_EQ(net::OK, url_request_delegate_->request_status());
EXPECT_TRUE(CompareHttpResponseInfos(
- write_info_buffer_->http_info.get(),
- &url_request_delegate_->received_info_));
+ *write_info_buffer_->http_info, url_request_delegate_->received_info_));
EXPECT_EQ(3072, url_request_delegate_->amount_received_);
char* p = url_request_delegate_->received_data_->data();
for (int i = 0; i < 3; ++i, p += kBlockSize)
diff --git a/chromium/content/browser/appcache/mock_appcache_service.cc b/chromium/content/browser/appcache/mock_appcache_service.cc
index da773f185db..6505950fb3b 100644
--- a/chromium/content/browser/appcache/mock_appcache_service.cc
+++ b/chromium/content/browser/appcache/mock_appcache_service.cc
@@ -4,6 +4,8 @@
#include "content/browser/appcache/mock_appcache_service.h"
+#include <utility>
+
#include "base/bind.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
@@ -11,17 +13,16 @@
namespace content {
-static void DeferredCallCallback(
- const net::CompletionCallback& callback, int rv) {
- callback.Run(rv);
+static void DeferredCallCallback(net::CompletionOnceCallback callback, int rv) {
+ std::move(callback).Run(rv);
}
void MockAppCacheService::DeleteAppCachesForOrigin(
const url::Origin& origin,
- const net::CompletionCallback& callback) {
+ net::CompletionOnceCallback callback) {
++delete_called_count_;
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&DeferredCallCallback, callback,
+ FROM_HERE, base::BindOnce(&DeferredCallCallback, std::move(callback),
mock_delete_appcaches_for_origin_result_));
}
diff --git a/chromium/content/browser/appcache/mock_appcache_service.h b/chromium/content/browser/appcache/mock_appcache_service.h
index 51ac9c76591..322d12fd52c 100644
--- a/chromium/content/browser/appcache/mock_appcache_service.h
+++ b/chromium/content/browser/appcache/mock_appcache_service.h
@@ -24,9 +24,8 @@ class MockAppCacheService : public AppCacheServiceImpl {
// Just returns a canned completion code without actually
// removing groups and caches in our mock storage instance.
- void DeleteAppCachesForOrigin(
- const url::Origin& origin,
- const net::CompletionCallback& callback) override;
+ void DeleteAppCachesForOrigin(const url::Origin& origin,
+ net::CompletionOnceCallback callback) override;
void set_quota_manager_proxy(storage::QuotaManagerProxy* proxy) {
quota_manager_proxy_ = proxy;
diff --git a/chromium/content/browser/appcache/mock_appcache_storage.h b/chromium/content/browser/appcache/mock_appcache_storage.h
index 09a1fbd0722..4823ff0523f 100644
--- a/chromium/content/browser/appcache/mock_appcache_storage.h
+++ b/chromium/content/browser/appcache/mock_appcache_storage.h
@@ -144,7 +144,8 @@ class MockAppCacheStorage : public AppCacheStorage {
if (!disk_cache_) {
const int kMaxCacheSize = 10 * 1024 * 1024;
disk_cache_.reset(new AppCacheDiskCache);
- disk_cache_->InitWithMemBackend(kMaxCacheSize, net::CompletionCallback());
+ disk_cache_->InitWithMemBackend(kMaxCacheSize,
+ net::CompletionOnceCallback());
}
return disk_cache_.get();
}
diff --git a/chromium/content/browser/background_fetch/OWNERS b/chromium/content/browser/background_fetch/OWNERS
index a7cd217e75b..3a617dc86ba 100644
--- a/chromium/content/browser/background_fetch/OWNERS
+++ b/chromium/content/browser/background_fetch/OWNERS
@@ -3,9 +3,10 @@
# //chrome/browser/background_fetch/
# //content/common/background_fetch/
-awdf@chromium.org
peter@chromium.org
delphick@chromium.org
+nator@chromium.org
+rayankans@chromium.org
# TEAM: platform-capabilities@chromium.org
# COMPONENT: Blink>BackgroundFetch
diff --git a/chromium/content/browser/background_fetch/background_fetch.proto b/chromium/content/browser/background_fetch/background_fetch.proto
index c8708770309..d1cef4f3bfd 100644
--- a/chromium/content/browser/background_fetch/background_fetch.proto
+++ b/chromium/content/browser/background_fetch/background_fetch.proto
@@ -11,8 +11,26 @@ package content.proto;
// Stores per-registration (as opposed to per-request) data.
// https://wicg.github.io/background-fetch/#background-fetch-registration
//
-// Next Tag: 7
+// Next Tag: 9
message BackgroundFetchRegistration {
+ enum BackgroundFetchState {
+ PENDING = 0; // Default value.
+ FAILURE = 1;
+ SUCCESS = 2;
+ }
+
+ // This should be kept in sync with blink.mojom.BackgroundFetchFailureReason.
+ enum BackgroundFetchFailureReason {
+ NONE = 0; // Default value.
+ CANCELLED_FROM_UI = 1;
+ CANCELLED_BY_DEVELOPER = 2;
+ BAD_STATUS = 3;
+ FETCH_ERROR = 4;
+ SERVICE_WORKER_UNAVAILABLE = 5;
+ QUOTA_EXCEEDED = 6;
+ TOTAL_DOWNLOAD_SIZE_EXCEEDED = 7;
+ }
+
// See definition of |unique_id| in BackgroundFetchRegistrationId.
optional string unique_id = 1;
@@ -23,6 +41,8 @@ message BackgroundFetchRegistration {
optional uint64 uploaded = 4;
optional uint64 download_total = 5;
optional uint64 downloaded = 6;
+ optional BackgroundFetchState state = 7;
+ optional BackgroundFetchFailureReason failure_reason = 8;
}
// Developer provided options.
@@ -30,6 +50,8 @@ message BackgroundFetchRegistration {
//
// Next Tag: 3
message BackgroundFetchOptions {
+ // The initial title provided by the developer. This can be updated,
+ // and the most recent value is stored in BackgroundFetchUIOptions.
optional string title = 1;
// https://w3c.github.io/manifest/#dom-imageresource
@@ -66,7 +88,7 @@ message BackgroundFetchOptions {
// in memory. This information should be everything needed to reconstruct
// the state of an interrupted background fetch.
//
-// Next Tag: 7
+// Next Tag: 6
message BackgroundFetchMetadata {
optional int64 creation_microseconds_since_unix_epoch = 1;
optional string origin = 2;
@@ -76,10 +98,17 @@ message BackgroundFetchMetadata {
// Number of fetches initiated by the developer.
optional int32 num_fetches = 5;
+}
+
+// All the updateable options that show up in the UI (e.g. notification).
+//
+// Next Tag: 3
+message BackgroundFetchUIOptions {
+ optional string title = 1;
// Raw bytes needed to deserialize into a PNG icon. Only used if the icon
// has a max resolution of 256x256. This means this is at most ~256KB.
- optional bytes icon = 6;
+ optional bytes icon = 2;
}
// A background fetch request that is still in a pending state.
diff --git a/chromium/content/browser/background_fetch/background_fetch_context.cc b/chromium/content/browser/background_fetch/background_fetch_context.cc
index 38bdb10727d..13f6f472b29 100644
--- a/chromium/content/browser/background_fetch/background_fetch_context.cc
+++ b/chromium/content/browser/background_fetch/background_fetch_context.cc
@@ -12,12 +12,16 @@
#include "content/browser/background_fetch/background_fetch_metrics.h"
#include "content/browser/background_fetch/background_fetch_registration_id.h"
#include "content/browser/background_fetch/background_fetch_registration_notifier.h"
+#include "content/browser/background_fetch/background_fetch_request_match_params.h"
#include "content/browser/background_fetch/background_fetch_scheduler.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/public/browser/background_fetch_delegate.h"
#include "content/public/browser/browser_context.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
#include "net/url_request/url_request_context_getter.h"
#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
namespace content {
@@ -25,7 +29,8 @@ BackgroundFetchContext::BackgroundFetchContext(
BrowserContext* browser_context,
const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context,
const scoped_refptr<content::CacheStorageContextImpl>&
- cache_storage_context)
+ cache_storage_context,
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy)
: browser_context_(browser_context),
service_worker_context_(service_worker_context),
event_dispatcher_(service_worker_context),
@@ -38,7 +43,8 @@ BackgroundFetchContext::BackgroundFetchContext(
DCHECK(service_worker_context_);
data_manager_ = std::make_unique<BackgroundFetchDataManager>(
- browser_context_, service_worker_context, cache_storage_context);
+ browser_context_, service_worker_context, cache_storage_context,
+ std::move(quota_manager_proxy));
scheduler_ = std::make_unique<BackgroundFetchScheduler>(data_manager_.get());
delegate_proxy_.SetClickEventDispatcher(base::BindRepeating(
&BackgroundFetchContext::DispatchClickEvent, weak_factory_.GetWeakPtr()));
@@ -72,11 +78,9 @@ void BackgroundFetchContext::DidGetInitializationData(
}
for (auto& data : initialization_data) {
- CreateController(data.registration_id, data.options, data.icon,
- data.ui_title, data.num_completed_requests,
- data.num_requests, data.active_fetch_guids,
- std::make_unique<BackgroundFetchRegistration>(
- std::move(data.registration)));
+ CreateController(data.registration_id, data.registration, data.options,
+ data.icon, data.ui_title, data.num_completed_requests,
+ data.num_requests, std::move(data.active_fetch_requests));
}
}
@@ -104,7 +108,7 @@ void BackgroundFetchContext::GetDeveloperIdsForServiceWorker(
void BackgroundFetchContext::DidGetRegistration(
blink::mojom::BackgroundFetchService::GetRegistrationCallback callback,
blink::mojom::BackgroundFetchError error,
- std::unique_ptr<BackgroundFetchRegistration> registration) {
+ const BackgroundFetchRegistration& registration) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (error != blink::mojom::BackgroundFetchError::NONE) {
@@ -113,13 +117,15 @@ void BackgroundFetchContext::DidGetRegistration(
return;
}
- DCHECK(registration);
+ BackgroundFetchRegistration updated_registration(registration);
+
// The data manager only has the number of bytes from completed downloads, so
// augment this with the number of downloaded bytes from in-progress jobs.
- DCHECK(job_controllers_.count(registration->unique_id));
- registration->downloaded +=
- job_controllers_[registration->unique_id]->GetInProgressDownloadedBytes();
- std::move(callback).Run(error, *registration.get());
+ DCHECK(job_controllers_.count(registration.unique_id));
+ updated_registration.downloaded +=
+ job_controllers_[registration.unique_id]->GetInProgressDownloadedBytes();
+
+ std::move(callback).Run(error, updated_registration);
}
void BackgroundFetchContext::StartFetch(
@@ -127,6 +133,7 @@ void BackgroundFetchContext::StartFetch(
const std::vector<ServiceWorkerFetchRequest>& requests,
const BackgroundFetchOptions& options,
const SkBitmap& icon,
+ RenderFrameHost* render_frame_host,
blink::mojom::BackgroundFetchService::FetchCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -137,11 +144,58 @@ void BackgroundFetchContext::StartFetch(
DCHECK_EQ(0u, fetch_callbacks_.count(registration_id));
fetch_callbacks_[registration_id] = std::move(callback);
- data_manager_->CreateRegistration(
- registration_id, requests, options, icon,
+ // |data_manager| is guaranteed to outlive |this|. |create_registration| is
+ // passed to `DidGetPermission`, which is tied to |weak_factory_|. That means
+ // that if |create_registration| runs, |this| is still alive, as is
+ // |data_manager| (a pointer owned by |this|).
+ auto create_registration = base::BindOnce(
+ &BackgroundFetchDataManager::CreateRegistration,
+ base::Unretained(data_manager_.get()), registration_id, requests, options,
+ icon,
base::BindOnce(&BackgroundFetchContext::DidCreateRegistration,
- weak_factory_.GetWeakPtr(), registration_id, options, icon,
- requests.size()));
+ weak_factory_.GetWeakPtr(), registration_id));
+
+ GetPermissionForOrigin(
+ registration_id.origin(), render_frame_host,
+ base::BindOnce(&BackgroundFetchContext::DidGetPermission,
+ weak_factory_.GetWeakPtr(), std::move(create_registration),
+ registration_id));
+}
+
+void BackgroundFetchContext::GetPermissionForOrigin(
+ const url::Origin& origin,
+ RenderFrameHost* render_frame_host,
+ GetPermissionCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ ResourceRequestInfo::WebContentsGetter wc_getter = base::NullCallback();
+
+ // Permissions need to go through the DownloadRequestLimiter if the fetch
+ // is started from a top-level frame.
+ if (render_frame_host && !render_frame_host->GetParent()) {
+ wc_getter = base::BindRepeating(&WebContents::FromFrameTreeNodeId,
+ render_frame_host->GetFrameTreeNodeId());
+ }
+
+ delegate_proxy_.GetPermissionForOrigin(origin, std::move(wc_getter),
+ std::move(callback));
+}
+
+void BackgroundFetchContext::DidGetPermission(
+ base::OnceClosure permission_closure,
+ const BackgroundFetchRegistrationId& registration_id,
+ bool has_permission) {
+ if (has_permission) {
+ std::move(permission_closure).Run();
+ return;
+ }
+
+ // No permission, the fetch should be rejected.
+ background_fetch::RecordRegistrationCreatedError(
+ blink::mojom::BackgroundFetchError::PERMISSION_DENIED);
+ std::move(fetch_callbacks_[registration_id])
+ .Run(blink::mojom::BackgroundFetchError::PERMISSION_DENIED,
+ base::nullopt);
}
void BackgroundFetchContext::GetIconDisplaySize(
@@ -153,35 +207,25 @@ void BackgroundFetchContext::GetIconDisplaySize(
void BackgroundFetchContext::DidCreateRegistration(
const BackgroundFetchRegistrationId& registration_id,
- const BackgroundFetchOptions& options,
- const SkBitmap& icon,
- size_t num_requests,
blink::mojom::BackgroundFetchError error,
- std::unique_ptr<BackgroundFetchRegistration> registration) {
+ const BackgroundFetchRegistration& registration) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
background_fetch::RecordRegistrationCreatedError(error);
- if (error != blink::mojom::BackgroundFetchError::NONE) {
- DCHECK(fetch_callbacks_.count(registration_id));
- std::move(fetch_callbacks_[registration_id])
- .Run(error, base::nullopt /* BackgroundFetchRegistration */);
- fetch_callbacks_.erase(registration_id);
- return;
- }
- if (hang_registration_creation_for_testing_) {
- // Hang here, to allow time for testing races. For instance, this helps us
- // test the behavior when a service worker gets unregistered before the
- // controller can be created.
+ auto iter = fetch_callbacks_.find(registration_id);
+
+ // The fetch might have been abandoned already if the Service Worker was
+ // unregistered or corrupted while registration was in progress.
+ if (iter == fetch_callbacks_.end())
return;
- }
- DCHECK(registration);
+ if (error == blink::mojom::BackgroundFetchError::NONE)
+ std::move(iter->second).Run(error, registration);
+ else
+ std::move(iter->second).Run(error, base::nullopt /* registration */);
- // Create the BackgroundFetchJobController to do the actual fetching.
- CreateController(registration_id, options, icon, options.title,
- 0u /* num_completed_requests */, num_requests,
- {} /* outstanding_guids */, std::move(registration));
+ fetch_callbacks_.erase(registration_id);
}
void BackgroundFetchContext::AddRegistrationObserver(
@@ -192,7 +236,8 @@ void BackgroundFetchContext::AddRegistrationObserver(
void BackgroundFetchContext::UpdateUI(
const BackgroundFetchRegistrationId& registration_id,
- const std::string& title,
+ const base::Optional<std::string>& title,
+ const base::Optional<SkBitmap>& icon,
blink::mojom::BackgroundFetchService::UpdateUICallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -203,7 +248,7 @@ void BackgroundFetchContext::UpdateUI(
return;
}
- data_manager_->UpdateRegistrationUI(registration_id, title,
+ data_manager_->UpdateRegistrationUI(registration_id, title, icon,
std::move(callback));
}
@@ -212,6 +257,13 @@ void BackgroundFetchContext::OnServiceWorkerDatabaseCorrupted(
AbandonFetches(service_worker_registration_id);
}
+void BackgroundFetchContext::OnQuotaExceeded(
+ const BackgroundFetchRegistrationId& registration_id) {
+ auto job_it = job_controllers_.find(registration_id.unique_id());
+ if (job_it != job_controllers_.end() && job_it->second)
+ job_it->second->Abort(BackgroundFetchReasonToAbort::QUOTA_EXCEEDED);
+}
+
void BackgroundFetchContext::AbandonFetches(
int64_t service_worker_registration_id) {
// Abandon all active fetches associated with this service worker.
@@ -228,6 +280,7 @@ void BackgroundFetchContext::AbandonFetches(
.service_worker_registration_id() ==
service_worker_registration_id) {
DCHECK(saved_iter->second);
+
saved_iter->second->Abort(
BackgroundFetchReasonToAbort::SERVICE_WORKER_UNAVAILABLE);
}
@@ -249,14 +302,38 @@ void BackgroundFetchContext::AbandonFetches(
}
}
+void BackgroundFetchContext::OnRegistrationCreated(
+ const BackgroundFetchRegistrationId& registration_id,
+ const BackgroundFetchRegistration& registration,
+ const BackgroundFetchOptions& options,
+ const SkBitmap& icon,
+ int num_requests) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (hang_registration_creation_for_testing_) {
+ // Hang here, to allow time for testing races. For instance, this helps us
+ // test the behavior when a service worker gets unregistered before the
+ // controller can be created.
+ return;
+ }
+
+ // TODO(peter): When this moves to the BackgroundFetchScheduler, only create
+ // a controller when the background fetch can actually be started.
+
+ CreateController(registration_id, registration, options, icon, options.title,
+ 0u /* num_completed_requests */, num_requests,
+ {} /* active_fetch_requests */);
+}
+
void BackgroundFetchContext::OnUpdatedUI(
const BackgroundFetchRegistrationId& registration_id,
- const std::string& title) {
+ const base::Optional<std::string>& title,
+ const base::Optional<SkBitmap>& icon) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
auto iter = job_controllers_.find(registration_id.unique_id());
if (iter != job_controllers_.end())
- iter->second->UpdateUI(title);
+ iter->second->UpdateUI(title, icon);
}
void BackgroundFetchContext::OnRegistrationDeleted(
@@ -273,18 +350,19 @@ void BackgroundFetchContext::OnStorageWiped() {
void BackgroundFetchContext::CreateController(
const BackgroundFetchRegistrationId& registration_id,
+ const BackgroundFetchRegistration& registration,
const BackgroundFetchOptions& options,
const SkBitmap& icon,
const std::string& ui_title,
size_t num_completed_requests,
size_t num_requests,
- const std::vector<std::string>& outstanding_guids,
- std::unique_ptr<BackgroundFetchRegistration> registration) {
+ std::vector<scoped_refptr<BackgroundFetchRequestInfo>>
+ active_fetch_requests) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
auto controller = std::make_unique<BackgroundFetchJobController>(
- &delegate_proxy_, registration_id, options, icon,
- registration->downloaded, scheduler_.get(),
+ &delegate_proxy_, scheduler_.get(), registration_id, options, icon,
+ registration.downloaded,
// Safe because JobControllers are destroyed before RegistrationNotifier.
base::BindRepeating(&BackgroundFetchRegistrationNotifier::Notify,
base::Unretained(registration_notifier_.get())),
@@ -293,16 +371,10 @@ void BackgroundFetchContext::CreateController(
base::Bind(&background_fetch::RecordSchedulerFinishedError)));
controller->InitializeRequestStatus(num_completed_requests, num_requests,
- outstanding_guids, ui_title);
+ std::move(active_fetch_requests),
+ ui_title);
scheduler_->AddJobController(controller.get());
job_controllers_.emplace(registration_id.unique_id(), std::move(controller));
-
- auto fetch_callback_iter = fetch_callbacks_.find(registration_id);
- if (fetch_callback_iter != fetch_callbacks_.end()) {
- std::move(fetch_callback_iter->second)
- .Run(blink::mojom::BackgroundFetchError::NONE, *registration);
- fetch_callbacks_.erase(fetch_callback_iter);
- }
}
void BackgroundFetchContext::Abort(
@@ -344,34 +416,45 @@ void BackgroundFetchContext::DidMarkForDeletion(
if (error != blink::mojom::BackgroundFetchError::NONE)
return;
+ auto controllers_iter = job_controllers_.find(registration_id.unique_id());
+
if (reason_to_abort == BackgroundFetchReasonToAbort::ABORTED_BY_DEVELOPER) {
- DCHECK(job_controllers_.count(registration_id.unique_id()));
- job_controllers_[registration_id.unique_id()]->Abort(reason_to_abort);
+ DCHECK(controllers_iter != job_controllers_.end());
+ controllers_iter->second->Abort(reason_to_abort);
}
+ auto registration = controllers_iter->second->NewRegistration(
+ blink::mojom::BackgroundFetchState::FAILURE);
switch (reason_to_abort) {
case BackgroundFetchReasonToAbort::ABORTED_BY_DEVELOPER:
case BackgroundFetchReasonToAbort::CANCELLED_FROM_UI:
CleanupRegistration(registration_id, {},
- mojom::BackgroundFetchState::FAILED);
- // TODO(rayankans): Send fetches to the event dispatcher.
+ blink::mojom::BackgroundFetchState::FAILURE);
event_dispatcher_.DispatchBackgroundFetchAbortEvent(
- registration_id, {} /* settled_fetches */, base::DoNothing());
+ registration_id, std::move(registration), base::DoNothing());
return;
case BackgroundFetchReasonToAbort::TOTAL_DOWNLOAD_SIZE_EXCEEDED:
case BackgroundFetchReasonToAbort::SERVICE_WORKER_UNAVAILABLE:
+ case BackgroundFetchReasonToAbort::QUOTA_EXCEEDED:
case BackgroundFetchReasonToAbort::NONE:
// This will send a BackgroundFetchFetched or BackgroundFetchFail event.
+ // We still need this to figure out which event to send.
+ // TODO(crbug.com/699957, crbug.com/874092): Add a method to only return
+ // the information needed to dispatch these events, instead of settled
+ // fetches.
data_manager_->GetSettledFetchesForRegistration(
registration_id,
+ std::make_unique<BackgroundFetchRequestMatchParams>(),
base::BindOnce(&BackgroundFetchContext::DidGetSettledFetches,
- weak_factory_.GetWeakPtr(), registration_id));
+ weak_factory_.GetWeakPtr(), registration_id,
+ std::move(registration)));
return;
}
}
void BackgroundFetchContext::DidGetSettledFetches(
const BackgroundFetchRegistrationId& registration_id,
+ std::unique_ptr<BackgroundFetchRegistration> registration,
blink::mojom::BackgroundFetchError error,
bool background_fetch_succeeded,
std::vector<BackgroundFetchSettledFetch> settled_fetches,
@@ -380,17 +463,26 @@ void BackgroundFetchContext::DidGetSettledFetches(
if (error != blink::mojom::BackgroundFetchError::NONE) {
CleanupRegistration(registration_id, {} /* fetches */,
- mojom::BackgroundFetchState::FAILED,
+ blink::mojom::BackgroundFetchState::FAILURE,
true /* preserve_info_to_dispatch_click_event */);
return;
}
- // The `backgroundfetched` event will be invoked when all requests in the
+ DCHECK(job_controllers_.count(registration_id.unique_id()));
+
+ if (job_controllers_[registration_id.unique_id()]->total_downloads() !=
+ static_cast<int>(settled_fetches.size())) {
+ // Something went wrong, and some information was lost.
+ background_fetch_succeeded = false;
+ }
+
+ // The `backgroundfetchsuccess` event will be invoked when all requests in the
// registration have completed successfully. In all other cases, the
// `backgroundfetchfail` event will be invoked instead.
if (background_fetch_succeeded) {
- event_dispatcher_.DispatchBackgroundFetchedEvent(
- registration_id, std::move(settled_fetches),
+ registration->state = blink::mojom::BackgroundFetchState::SUCCESS;
+ event_dispatcher_.DispatchBackgroundFetchSuccessEvent(
+ registration_id, std::move(registration),
base::BindOnce(
&BackgroundFetchContext::CleanupRegistration,
weak_factory_.GetWeakPtr(), registration_id,
@@ -398,18 +490,20 @@ void BackgroundFetchContext::DidGetSettledFetches(
// |blob_data_handles| to the callback to keep them alive
// until the waitUntil event is resolved.
std::move(blob_data_handles),
- mojom::BackgroundFetchState::SUCCEEDED,
+ blink::mojom::BackgroundFetchState::SUCCESS,
true /* preserve_info_to_dispatch_click_event */));
} else {
+ registration->state = blink::mojom::BackgroundFetchState::FAILURE;
event_dispatcher_.DispatchBackgroundFetchFailEvent(
- registration_id, std::move(settled_fetches),
+ registration_id, std::move(registration),
base::BindOnce(
&BackgroundFetchContext::CleanupRegistration,
weak_factory_.GetWeakPtr(), registration_id,
// The blob uuid is sent as part of |settled_fetches|. Bind
// |blob_data_handles| to the callback to keep them alive
// until the waitUntil event is resolved.
- std::move(blob_data_handles), mojom::BackgroundFetchState::FAILED,
+ std::move(blob_data_handles),
+ blink::mojom::BackgroundFetchState::FAILURE,
true /* preserve_info_to_dispatch_click_event */));
}
}
@@ -417,19 +511,22 @@ void BackgroundFetchContext::DidGetSettledFetches(
void BackgroundFetchContext::CleanupRegistration(
const BackgroundFetchRegistrationId& registration_id,
const std::vector<std::unique_ptr<storage::BlobDataHandle>>& blob_handles,
- mojom::BackgroundFetchState background_fetch_state,
+ blink::mojom::BackgroundFetchState background_fetch_state,
bool preserve_info_to_dispatch_click_event) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// If we had an active JobController, it is no longer necessary, as the
// notification's UI can no longer be updated after the fetch is aborted, or
- // after the waitUntil promise of the backgroundfetched/backgroundfetchfail
- // event has been resolved. Store the information we want to persist after
- // the controller is gone, in completed_fetches_.
- scheduler_->RemoveJobController(registration_id);
+ // after the waitUntil promise of the
+ // backgroundfetchsuccess/backgroundfetchfail event has been resolved. Store
+ // the information we want to persist after the controller is gone, in
+ // completed_fetches_.
+ auto controllers_iter = job_controllers_.find(registration_id.unique_id());
+ DCHECK(controllers_iter != job_controllers_.end());
if (preserve_info_to_dispatch_click_event) {
- completed_fetches_[registration_id.unique_id()] = {registration_id,
- background_fetch_state};
+ completed_fetches_[registration_id.unique_id()] = std::make_pair(
+ registration_id,
+ controllers_iter->second->NewRegistration(background_fetch_state));
}
job_controllers_.erase(registration_id.unique_id());
@@ -453,7 +550,7 @@ void BackgroundFetchContext::DispatchClickEvent(const std::string& unique_id) {
// The fetch has succeeded or failed. (not aborted/cancelled).
event_dispatcher_.DispatchBackgroundFetchClickEvent(
iter->second.first /* registration_id */,
- iter->second.second /* background_fetch_state */, base::DoNothing());
+ std::move(iter->second.second) /* registration */, base::DoNothing());
completed_fetches_.erase(iter);
return;
}
@@ -462,9 +559,41 @@ void BackgroundFetchContext::DispatchClickEvent(const std::string& unique_id) {
auto controllers_iter = job_controllers_.find(unique_id);
if (controllers_iter == job_controllers_.end())
return;
+ // TODO(crbug.com/873630): Implement a background fetch state manager to
+ // keep track of states, and stop hard-coding it here.
+ auto registration = controllers_iter->second->NewRegistration(
+ blink::mojom::BackgroundFetchState::PENDING);
event_dispatcher_.DispatchBackgroundFetchClickEvent(
- controllers_iter->second->registration_id(),
- mojom::BackgroundFetchState::PENDING, base::DoNothing());
+ controllers_iter->second->registration_id(), std::move(registration),
+ base::DoNothing());
+}
+
+void BackgroundFetchContext::MatchRequests(
+ const BackgroundFetchRegistrationId& registration_id,
+ std::unique_ptr<BackgroundFetchRequestMatchParams> match_params,
+ blink::mojom::BackgroundFetchService::MatchRequestsCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ data_manager_->GetSettledFetchesForRegistration(
+ registration_id, std::move(match_params),
+ base::BindOnce(&BackgroundFetchContext::DidGetMatchingRequests,
+ weak_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void BackgroundFetchContext::DidGetMatchingRequests(
+ blink::mojom::BackgroundFetchService::MatchRequestsCallback callback,
+ blink::mojom::BackgroundFetchError error,
+ bool background_fetch_succeeded,
+ std::vector<BackgroundFetchSettledFetch> settled_fetches,
+ std::vector<std::unique_ptr<storage::BlobDataHandle>> blob_data_handles) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // TODO(crbug.com/863016): Update to 0u once we've stopped sending an
+ // uncached response.
+ if (error != blink::mojom::BackgroundFetchError::NONE)
+ DCHECK_EQ(settled_fetches.size(), 1u);
+
+ std::move(callback).Run(std::move(settled_fetches));
}
void BackgroundFetchContext::LastObserverGarbageCollected(
diff --git a/chromium/content/browser/background_fetch/background_fetch_context.h b/chromium/content/browser/background_fetch/background_fetch_context.h
index a6b05e1267a..e25b9151c53 100644
--- a/chromium/content/browser/background_fetch/background_fetch_context.h
+++ b/chromium/content/browser/background_fetch/background_fetch_context.h
@@ -13,6 +13,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
#include "content/browser/background_fetch/background_fetch_data_manager_observer.h"
#include "content/browser/background_fetch/background_fetch_delegate_proxy.h"
#include "content/browser/background_fetch/background_fetch_event_dispatcher.h"
@@ -24,6 +25,7 @@
namespace storage {
class BlobDataHandle;
+class QuotaManagerProxy;
}
namespace content {
@@ -33,9 +35,12 @@ class BackgroundFetchDataManager;
struct BackgroundFetchOptions;
class BackgroundFetchRegistrationId;
class BackgroundFetchRegistrationNotifier;
+class BackgroundFetchRequestMatchParams;
+class BackgroundFetchRequestInfo;
class BackgroundFetchScheduler;
class BrowserContext;
class CacheStorageContextImpl;
+class RenderFrameHost;
class ServiceWorkerContextWrapper;
struct ServiceWorkerFetchRequest;
@@ -55,7 +60,8 @@ class CONTENT_EXPORT BackgroundFetchContext
BrowserContext* browser_context,
const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context,
const scoped_refptr<content::CacheStorageContextImpl>&
- cache_storage_context);
+ cache_storage_context,
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy);
void InitializeOnIOThread();
@@ -85,6 +91,7 @@ class CONTENT_EXPORT BackgroundFetchContext
const std::vector<ServiceWorkerFetchRequest>& requests,
const BackgroundFetchOptions& options,
const SkBitmap& icon,
+ RenderFrameHost* render_frame_host,
blink::mojom::BackgroundFetchService::FetchCallback callback);
// Gets display size for the icon for Background Fetch UI.
@@ -92,6 +99,12 @@ class CONTENT_EXPORT BackgroundFetchContext
blink::mojom::BackgroundFetchService::GetIconDisplaySizeCallback
callback);
+ // Matches Background Fetch requests from the cache and returns responses.
+ void MatchRequests(
+ const BackgroundFetchRegistrationId& registration_id,
+ std::unique_ptr<BackgroundFetchRequestMatchParams> match_params,
+ blink::mojom::BackgroundFetchService::MatchRequestsCallback callback);
+
// Aborts the Background Fetch for the |registration_id|. The callback will be
// invoked with INVALID_ID if the registration has already completed or
// aborted, STORAGE_ERROR if an I/O error occurs, or NONE for success.
@@ -105,19 +118,31 @@ class CONTENT_EXPORT BackgroundFetchContext
const std::string& unique_id,
blink::mojom::BackgroundFetchRegistrationObserverPtr observer);
- // Updates the title of the Background Fetch identified by |registration_id|.
- // The |callback| will be invoked when the title has been updated, or an error
- // occurred that prevents it from doing so.
+ // Updates the title or icon of the Background Fetch identified by
+ // |registration_id|. The |callback| will be invoked when the title has been
+ // updated, or an error occurred that prevents it from doing so.
+ // The icon is wrapped in an optional. If the optional has a value then the
+ // internal |icon| is guarnteed to be not null.
void UpdateUI(
const BackgroundFetchRegistrationId& registration_id,
- const std::string& title,
+ const base::Optional<std::string>& title,
+ const base::Optional<SkBitmap>& icon,
blink::mojom::BackgroundFetchService::UpdateUICallback callback);
// BackgroundFetchDataManagerObserver implementation.
+ void OnRegistrationCreated(
+ const BackgroundFetchRegistrationId& registration_id,
+ const BackgroundFetchRegistration& registration,
+ const BackgroundFetchOptions& options,
+ const SkBitmap& icon,
+ int num_requests) override;
void OnUpdatedUI(const BackgroundFetchRegistrationId& registration_id,
- const std::string& title) override;
+ const base::Optional<std::string>& title,
+ const base::Optional<SkBitmap>& icon) override;
void OnServiceWorkerDatabaseCorrupted(
int64_t service_worker_registration_id) override;
+ void OnQuotaExceeded(
+ const BackgroundFetchRegistrationId& registration_id) override;
// ServiceWorkerContextCoreObserver implementation.
void OnRegistrationDeleted(int64_t registration_id,
@@ -125,6 +150,10 @@ class CONTENT_EXPORT BackgroundFetchContext
void OnStorageWiped() override;
private:
+ using GetPermissionCallback = base::OnceCallback<void(bool)>;
+
+ FRIEND_TEST_ALL_PREFIXES(BackgroundFetchServiceTest,
+ JobsInitializedOnBrowserRestart);
friend class BackgroundFetchServiceTest;
friend class BackgroundFetchJobControllerTest;
friend class base::DeleteHelper<BackgroundFetchContext>;
@@ -138,31 +167,28 @@ class CONTENT_EXPORT BackgroundFetchContext
// Creates a new Job Controller for the given |registration_id| and |options|,
// which will start fetching the files that are part of the registration.
- void CreateController(
- const BackgroundFetchRegistrationId& registration_id,
- const BackgroundFetchOptions& options,
- const SkBitmap& icon,
- const std::string& ui_title,
- size_t num_completed_requests,
- size_t num_requests,
- const std::vector<std::string>& outstanding_guids,
- std::unique_ptr<BackgroundFetchRegistration> registration);
+ void CreateController(const BackgroundFetchRegistrationId& registration_id,
+ const BackgroundFetchRegistration& registration,
+ const BackgroundFetchOptions& options,
+ const SkBitmap& icon,
+ const std::string& ui_title,
+ size_t num_completed_requests,
+ size_t num_requests,
+ std::vector<scoped_refptr<BackgroundFetchRequestInfo>>
+ active_fetch_requests);
// Called when an existing registration has been retrieved from the data
// manager. If the registration does not exist then |registration| is nullptr.
void DidGetRegistration(
blink::mojom::BackgroundFetchService::GetRegistrationCallback callback,
blink::mojom::BackgroundFetchError error,
- std::unique_ptr<BackgroundFetchRegistration> registration);
+ const BackgroundFetchRegistration& registration);
// Called when a new registration has been created by the data manager.
void DidCreateRegistration(
const BackgroundFetchRegistrationId& registration_id,
- const BackgroundFetchOptions& options,
- const SkBitmap& icon,
- size_t num_requests,
blink::mojom::BackgroundFetchError error,
- std::unique_ptr<BackgroundFetchRegistration> registration);
+ const BackgroundFetchRegistration& registration);
// Called by a JobController when it finishes processing. Also used to
// implement |Abort|.
@@ -182,6 +208,17 @@ class CONTENT_EXPORT BackgroundFetchContext
// retrieved from storage, and the Service Worker event can be invoked.
void DidGetSettledFetches(
const BackgroundFetchRegistrationId& registration_id,
+ std::unique_ptr<BackgroundFetchRegistration> registration,
+ blink::mojom::BackgroundFetchError error,
+ bool background_fetch_succeeded,
+ std::vector<BackgroundFetchSettledFetch> settled_fetches,
+ std::vector<std::unique_ptr<storage::BlobDataHandle>> blob_data_handles);
+
+ // Called when the sequence of matching settled fetches have been received
+ // from storage, and |callback| can be invoked to pass these on to the
+ // renderer.
+ void DidGetMatchingRequests(
+ blink::mojom::BackgroundFetchService::MatchRequestsCallback callback,
blink::mojom::BackgroundFetchError error,
bool background_fetch_succeeded,
std::vector<BackgroundFetchSettledFetch> settled_fetches,
@@ -208,7 +245,7 @@ class CONTENT_EXPORT BackgroundFetchContext
const BackgroundFetchRegistrationId& registration_id,
const std::vector<std::unique_ptr<storage::BlobDataHandle>>&
blob_data_handles,
- mojom::BackgroundFetchState background_fetch_state,
+ blink::mojom::BackgroundFetchState background_fetch_state,
bool preserve_info_to_dispatch_click_event = false);
// Called when the last JavaScript BackgroundFetchRegistration object has been
@@ -227,6 +264,17 @@ class CONTENT_EXPORT BackgroundFetchContext
// blink::mojom::kInvalidServiceWorkerRegistrationId.
void AbandonFetches(int64_t service_worker_registration_id);
+ // Check if |origin| has permission to start a fetch.
+ // virtual for testing.
+ void GetPermissionForOrigin(const url::Origin& origin,
+ RenderFrameHost* render_frame_host,
+ GetPermissionCallback callback);
+
+ // Callback for GetPermissionForOrigin.
+ void DidGetPermission(base::OnceClosure permission_closure,
+ const BackgroundFetchRegistrationId& registration_id,
+ bool has_permission);
+
// |this| is owned, indirectly, by the BrowserContext.
BrowserContext* browser_context_;
@@ -238,20 +286,19 @@ class CONTENT_EXPORT BackgroundFetchContext
std::unique_ptr<BackgroundFetchScheduler> scheduler_;
// Map from background fetch registration |unique_id|s to active job
- // controllers. Must be destroyed before |data_manager_| and
+ // controllers. Must be destroyed before |data_manager_|, |scheduler_| and
// |registration_notifier_|.
std::map<std::string, std::unique_ptr<BackgroundFetchJobController>>
job_controllers_;
- // Map from background fetch registration |unique_ids|s to {background fetch
- // registration id, fetch state}. An entry in here means the fetch has
- // completed. This information is needed after the fetch has completed.
+ // Map from |unique_id|s to {|registration_id|, |registration|}.
+ // An entry in here means the fetch has completed. This information is needed
+ // after the fetch has completed to dispatch the backgroundfetchclick event.
// TODO(crbug.com/857122): Clean this up when the UI is no longer showing.
- std::map<
- std::string,
- std::pair<BackgroundFetchRegistrationId, mojom::BackgroundFetchState>>
+ std::map<std::string,
+ std::pair<BackgroundFetchRegistrationId,
+ std::unique_ptr<BackgroundFetchRegistration>>>
completed_fetches_;
-
// Map from BackgroundFetchRegistrationIds to FetchCallbacks for active
// fetches. Must be destroyed before |data_manager_| and
// |registration_notifier_|. Since FetchCallback is a OnceCallback, please
diff --git a/chromium/content/browser/background_fetch/background_fetch_data_manager.cc b/chromium/content/browser/background_fetch/background_fetch_data_manager.cc
index c326cdc1da3..1fac2a819f9 100644
--- a/chromium/content/browser/background_fetch/background_fetch_data_manager.cc
+++ b/chromium/content/browser/background_fetch/background_fetch_data_manager.cc
@@ -18,6 +18,7 @@
#include "content/browser/background_fetch/storage/delete_registration_task.h"
#include "content/browser/background_fetch/storage/get_developer_ids_task.h"
#include "content/browser/background_fetch/storage/get_metadata_task.h"
+#include "content/browser/background_fetch/storage/get_registration_task.h"
#include "content/browser/background_fetch/storage/get_settled_fetches_task.h"
#include "content/browser/background_fetch/storage/mark_registration_for_deletion_task.h"
#include "content/browser/background_fetch/storage/mark_request_complete_task.h"
@@ -28,44 +29,19 @@
#include "content/browser/storage_partition_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
#include "third_party/blink/public/mojom/blob/blob.mojom.h"
namespace content {
-namespace {
-
-// Helper function to convert a BackgroundFetchRegistration proto into a
-// BackgroundFetchRegistration struct, and call the appropriate callback.
-void GetRegistrationFromMetadata(
- BackgroundFetchDataManager::GetRegistrationCallback callback,
- blink::mojom::BackgroundFetchError error,
- std::unique_ptr<proto::BackgroundFetchMetadata> metadata_proto) {
- if (!metadata_proto) {
- std::move(callback).Run(error, nullptr);
- return;
- }
-
- const auto& registration_proto = metadata_proto->registration();
- auto registration = std::make_unique<BackgroundFetchRegistration>();
- registration->developer_id = registration_proto.developer_id();
- registration->unique_id = registration_proto.unique_id();
- // TODO(crbug.com/774054): Uploads are not yet supported.
- registration->upload_total = registration_proto.upload_total();
- registration->uploaded = registration_proto.uploaded();
- registration->download_total = registration_proto.download_total();
- registration->downloaded = registration_proto.downloaded();
-
- std::move(callback).Run(error, std::move(registration));
-}
-
-} // namespace
-
BackgroundFetchDataManager::BackgroundFetchDataManager(
BrowserContext* browser_context,
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
- scoped_refptr<CacheStorageContextImpl> cache_storage_context)
+ scoped_refptr<CacheStorageContextImpl> cache_storage_context,
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy)
: service_worker_context_(std::move(service_worker_context)),
cache_storage_context_(std::move(cache_storage_context)),
+ quota_manager_proxy_(std::move(quota_manager_proxy)),
weak_ptr_factory_(this) {
// Constructed on the UI thread, then used on the IO thread.
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -125,23 +101,8 @@ void BackgroundFetchDataManager::CreateRegistration(
GetRegistrationCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- auto registration_callback =
- base::BindOnce(&GetRegistrationFromMetadata, std::move(callback));
AddDatabaseTask(std::make_unique<background_fetch::CreateMetadataTask>(
- this, registration_id, requests, options, icon,
- std::move(registration_callback)));
-}
-
-void BackgroundFetchDataManager::GetMetadata(
- int64_t service_worker_registration_id,
- const url::Origin& origin,
- const std::string& developer_id,
- GetMetadataCallback callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- AddDatabaseTask(std::make_unique<background_fetch::GetMetadataTask>(
- this, service_worker_registration_id, origin, developer_id,
- std::move(callback)));
+ this, registration_id, requests, options, icon, std::move(callback)));
}
void BackgroundFetchDataManager::GetRegistration(
@@ -151,20 +112,20 @@ void BackgroundFetchDataManager::GetRegistration(
GetRegistrationCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- auto registration_callback =
- base::BindOnce(&GetRegistrationFromMetadata, std::move(callback));
- GetMetadata(service_worker_registration_id, origin, developer_id,
- std::move(registration_callback));
+ AddDatabaseTask(std::make_unique<background_fetch::GetRegistrationTask>(
+ this, service_worker_registration_id, origin, developer_id,
+ std::move(callback)));
}
void BackgroundFetchDataManager::UpdateRegistrationUI(
const BackgroundFetchRegistrationId& registration_id,
- const std::string& title,
+ const base::Optional<std::string>& title,
+ const base::Optional<SkBitmap>& icon,
blink::mojom::BackgroundFetchService::UpdateUICallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
AddDatabaseTask(std::make_unique<background_fetch::UpdateRegistrationUITask>(
- this, registration_id, title, std::move(callback)));
+ this, registration_id, title, icon, std::move(callback)));
}
void BackgroundFetchDataManager::PopNextRequest(
@@ -174,50 +135,49 @@ void BackgroundFetchDataManager::PopNextRequest(
auto start_next_request = base::BindOnce(
&BackgroundFetchDataManager::AddStartNextPendingRequestTask,
- weak_ptr_factory_.GetWeakPtr(),
- registration_id.service_worker_registration_id(), std::move(callback));
+ weak_ptr_factory_.GetWeakPtr(), registration_id, std::move(callback));
// Get the associated metadata, and add a StartNextPendingRequestTask.
- GetMetadata(registration_id.service_worker_registration_id(),
- registration_id.origin(), registration_id.developer_id(),
- std::move(start_next_request));
+ AddDatabaseTask(std::make_unique<background_fetch::GetRegistrationTask>(
+ this, registration_id.service_worker_registration_id(),
+ registration_id.origin(), registration_id.developer_id(),
+ std::move(start_next_request)));
}
void BackgroundFetchDataManager::AddStartNextPendingRequestTask(
- int64_t service_worker_registration_id,
+ const BackgroundFetchRegistrationId& registration_id,
NextRequestCallback callback,
blink::mojom::BackgroundFetchError error,
- std::unique_ptr<proto::BackgroundFetchMetadata> metadata) {
- if (!metadata) {
+ const BackgroundFetchRegistration& registration) {
+ if (error != blink::mojom::BackgroundFetchError::NONE) {
// Stop giving out requests as registration aborted (or otherwise finished).
std::move(callback).Run(nullptr /* request */);
return;
}
- DCHECK_EQ(error, blink::mojom::BackgroundFetchError::NONE);
AddDatabaseTask(
std::make_unique<background_fetch::StartNextPendingRequestTask>(
- this, service_worker_registration_id, std::move(metadata),
- std::move(callback)));
+ this, registration_id, registration, std::move(callback)));
}
void BackgroundFetchDataManager::MarkRequestAsComplete(
const BackgroundFetchRegistrationId& registration_id,
- BackgroundFetchRequestInfo* request,
- BackgroundFetchScheduler::MarkedCompleteCallback callback) {
+ scoped_refptr<BackgroundFetchRequestInfo> request_info,
+ base::OnceClosure closure) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
AddDatabaseTask(std::make_unique<background_fetch::MarkRequestCompleteTask>(
- this, registration_id, request, std::move(callback)));
+ this, registration_id, std::move(request_info), std::move(closure)));
}
void BackgroundFetchDataManager::GetSettledFetchesForRegistration(
const BackgroundFetchRegistrationId& registration_id,
+ std::unique_ptr<BackgroundFetchRequestMatchParams> match_params,
SettledFetchesCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
AddDatabaseTask(std::make_unique<background_fetch::GetSettledFetchesTask>(
- this, registration_id, std::move(callback)));
+ this, registration_id, std::move(match_params), std::move(callback)));
}
void BackgroundFetchDataManager::MarkRegistrationForDeletion(
diff --git a/chromium/content/browser/background_fetch/background_fetch_data_manager.h b/chromium/content/browser/background_fetch/background_fetch_data_manager.h
index 56119296c98..253831a6deb 100644
--- a/chromium/content/browser/background_fetch/background_fetch_data_manager.h
+++ b/chromium/content/browser/background_fetch/background_fetch_data_manager.h
@@ -18,6 +18,7 @@
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/observer_list.h"
+#include "base/optional.h"
#include "content/browser/background_fetch/background_fetch.pb.h"
#include "content/browser/background_fetch/background_fetch_registration_id.h"
#include "content/browser/background_fetch/background_fetch_scheduler.h"
@@ -30,12 +31,14 @@
namespace storage {
class BlobDataHandle;
+class QuotaManagerProxy;
}
namespace content {
class BackgroundFetchDataManagerObserver;
class BackgroundFetchRequestInfo;
+class BackgroundFetchRequestMatchParams;
struct BackgroundFetchSettledFetch;
class BrowserContext;
class CacheStorageManager;
@@ -65,20 +68,17 @@ class CONTENT_EXPORT BackgroundFetchDataManager
bool /* background_fetch_succeeded */,
std::vector<BackgroundFetchSettledFetch>,
std::vector<std::unique_ptr<storage::BlobDataHandle>>)>;
- using GetMetadataCallback =
- base::OnceCallback<void(blink::mojom::BackgroundFetchError,
- std::unique_ptr<proto::BackgroundFetchMetadata>)>;
using GetRegistrationCallback =
base::OnceCallback<void(blink::mojom::BackgroundFetchError,
- std::unique_ptr<BackgroundFetchRegistration>)>;
+ const BackgroundFetchRegistration&)>;
using NextRequestCallback =
base::OnceCallback<void(scoped_refptr<BackgroundFetchRequestInfo>)>;
- using NumRequestsCallback = base::OnceCallback<void(size_t)>;
BackgroundFetchDataManager(
BrowserContext* browser_context,
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
- scoped_refptr<CacheStorageContextImpl> cache_storage_context);
+ scoped_refptr<CacheStorageContextImpl> cache_storage_context,
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy);
~BackgroundFetchDataManager() override;
@@ -104,12 +104,6 @@ class CONTENT_EXPORT BackgroundFetchDataManager
const SkBitmap& icon,
GetRegistrationCallback callback);
- // Get the BackgroundFetchMetadata.
- void GetMetadata(int64_t service_worker_registration_id,
- const url::Origin& origin,
- const std::string& developer_id,
- GetMetadataCallback callback);
-
// Get the BackgroundFetchRegistration.
void GetRegistration(int64_t service_worker_registration_id,
const url::Origin& origin,
@@ -119,26 +113,30 @@ class CONTENT_EXPORT BackgroundFetchDataManager
// Updates the UI values for a Background Fetch registration.
void UpdateRegistrationUI(
const BackgroundFetchRegistrationId& registration_id,
- const std::string& title,
+ const base::Optional<std::string>& title,
+ const base::Optional<SkBitmap>& icon,
blink::mojom::BackgroundFetchService::UpdateUICallback callback);
- // Reads all settled fetches for the given |registration_id|. Both the Request
- // and Response objects will be initialised based on the stored data. Will
- // invoke the |callback| when the list of fetches has been compiled.
+ // Reads the settled fetches for the given |registration_id| based on
+ // |match_params|. Both the Request and Response objects will be initialised
+ // based on the stored data. Will invoke the |callback| when the list of
+ // fetches has been compiled.
void GetSettledFetchesForRegistration(
const BackgroundFetchRegistrationId& registration_id,
+ std::unique_ptr<BackgroundFetchRequestMatchParams> match_params,
SettledFetchesCallback callback);
- // Marks that the backgroundfetched/backgroundfetchfail/backgroundfetchabort
- // event is being dispatched. It's not possible to call DeleteRegistration at
- // this point as JavaScript may hold a reference to a
- // BackgroundFetchRegistration object and we need to keep the corresponding
- // data around until the last such reference is released (or until shutdown).
- // We can't just move the Background Fetch registration's data to RAM as it
- // might consume too much memory. So instead this step disassociates the
- // |developer_id| from the |unique_id|, so that existing JS objects with a
- // reference to |unique_id| can still access the data, but it can no longer be
- // reached using GetIds or GetRegistration.
+ // Marks that the
+ // backgroundfetchsuccess/backgroundfetchfail/backgroundfetchabort event is
+ // being dispatched. It's not possible to call DeleteRegistration at this
+ // point as JavaScript may hold a reference to a BackgroundFetchRegistration
+ // object and we need to keep the corresponding data around until the last
+ // such reference is released (or until shutdown). We can't just move the
+ // Background Fetch registration's data to RAM as it might consume too much
+ // memory. So instead this step disassociates the |developer_id| from the
+ // |unique_id|, so that existing JS objects with a reference to |unique_id|
+ // can still access the data, but it can no longer be reached using GetIds or
+ // GetRegistration.
void MarkRegistrationForDeletion(
const BackgroundFetchRegistrationId& registration_id,
HandleBackgroundFetchErrorCallback callback);
@@ -157,18 +155,18 @@ class CONTENT_EXPORT BackgroundFetchDataManager
const url::Origin& origin,
blink::mojom::BackgroundFetchService::GetDeveloperIdsCallback callback);
- const base::ObserverList<BackgroundFetchDataManagerObserver>& observers() {
+ const base::ObserverList<BackgroundFetchDataManagerObserver>::Unchecked&
+ observers() {
return observers_;
}
// BackgroundFetchScheduler::RequestProvider implementation:
void PopNextRequest(const BackgroundFetchRegistrationId& registration_id,
NextRequestCallback callback) override;
-
void MarkRequestAsComplete(
const BackgroundFetchRegistrationId& registration_id,
- BackgroundFetchRequestInfo* request,
- BackgroundFetchScheduler::MarkedCompleteCallback callback) override;
+ scoped_refptr<BackgroundFetchRequestInfo> request_info,
+ base::OnceClosure closure) override;
void ShutdownOnIO();
@@ -191,12 +189,15 @@ class CONTENT_EXPORT BackgroundFetchDataManager
ChromeBlobStorageContext* blob_storage_context() const {
return blob_storage_context_.get();
}
+ storage::QuotaManagerProxy* quota_manager_proxy() const {
+ return quota_manager_proxy_.get();
+ }
void AddStartNextPendingRequestTask(
- int64_t service_worker_registration_id,
+ const BackgroundFetchRegistrationId& registration_id,
NextRequestCallback callback,
blink::mojom::BackgroundFetchError error,
- std::unique_ptr<proto::BackgroundFetchMetadata> metadata);
+ const BackgroundFetchRegistration& registration);
void AddDatabaseTask(std::unique_ptr<background_fetch::DatabaseTask> task);
@@ -213,6 +214,8 @@ class CONTENT_EXPORT BackgroundFetchDataManager
scoped_refptr<CacheStorageContextImpl> cache_storage_context_;
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
+
// The BackgroundFetch stores its own reference to CacheStorageManager
// in case StoragePartitionImpl is destoyed, which releases the reference.
scoped_refptr<CacheStorageManager> cache_manager_;
@@ -224,7 +227,7 @@ class CONTENT_EXPORT BackgroundFetchDataManager
// Invariant: the frontmost task, if any, has already been started.
base::queue<std::unique_ptr<background_fetch::DatabaseTask>> database_tasks_;
- base::ObserverList<BackgroundFetchDataManagerObserver> observers_;
+ base::ObserverList<BackgroundFetchDataManagerObserver>::Unchecked observers_;
// The |unique_id|s of registrations that have been deactivated since the
// browser was last started. They will be automatically deleted when the
diff --git a/chromium/content/browser/background_fetch/background_fetch_data_manager_observer.h b/chromium/content/browser/background_fetch/background_fetch_data_manager_observer.h
index 12981a841ba..ab1a9f2aca0 100644
--- a/chromium/content/browser/background_fetch/background_fetch_data_manager_observer.h
+++ b/chromium/content/browser/background_fetch/background_fetch_data_manager_observer.h
@@ -5,8 +5,16 @@
#ifndef CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_DATA_MANAGER_OBSERVER_H_
#define CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_DATA_MANAGER_OBSERVER_H_
+#include <memory>
+
+#include "base/optional.h"
+
+class SkBitmap;
+
namespace content {
+struct BackgroundFetchOptions;
+struct BackgroundFetchRegistration;
class BackgroundFetchRegistrationId;
// Observer interface for objects that would like to be notified about changes
@@ -14,15 +22,28 @@ class BackgroundFetchRegistrationId;
// will be invoked on the IO thread.
class BackgroundFetchDataManagerObserver {
public:
- // Called when the |title| for the Background Fetch |registration_id| has been
- // updated in the data store.
+ // Called when the Background Fetch |registration| has been created.
+ virtual void OnRegistrationCreated(
+ const BackgroundFetchRegistrationId& registration_id,
+ const BackgroundFetchRegistration& registration,
+ const BackgroundFetchOptions& options,
+ const SkBitmap& icon,
+ int num_requests) = 0;
+
+ // Called when the UI options for the Background Fetch |registration_id| have
+ // been updated in the data store.
virtual void OnUpdatedUI(const BackgroundFetchRegistrationId& registration_id,
- const std::string& title) = 0;
+ const base::Optional<std::string>& title,
+ const base::Optional<SkBitmap>& icon) = 0;
// Called if corrupted data is found in the Service Worker database.
virtual void OnServiceWorkerDatabaseCorrupted(
int64_t service_worker_registration_id) = 0;
+ // Called if the origin is out of quota during the fetch.
+ virtual void OnQuotaExceeded(
+ const BackgroundFetchRegistrationId& registration_id) = 0;
+
virtual ~BackgroundFetchDataManagerObserver() {}
};
diff --git a/chromium/content/browser/background_fetch/background_fetch_data_manager_unittest.cc b/chromium/content/browser/background_fetch/background_fetch_data_manager_unittest.cc
index acd1d25f874..4b2a1074e78 100644
--- a/chromium/content/browser/background_fetch/background_fetch_data_manager_unittest.cc
+++ b/chromium/content/browser/background_fetch/background_fetch_data_manager_unittest.cc
@@ -16,18 +16,25 @@
#include "base/guid.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "content/browser/background_fetch/background_fetch.pb.h"
#include "content/browser/background_fetch/background_fetch_data_manager_observer.h"
#include "content/browser/background_fetch/background_fetch_request_info.h"
+#include "content/browser/background_fetch/background_fetch_request_match_params.h"
#include "content/browser/background_fetch/background_fetch_test_base.h"
#include "content/browser/background_fetch/background_fetch_test_data_manager.h"
#include "content/browser/background_fetch/storage/database_helpers.h"
+#include "content/browser/background_fetch/storage/image_helpers.h"
+#include "content/browser/cache_storage/cache_storage_cache_handle.h"
#include "content/browser/cache_storage/cache_storage_manager.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/public/browser/background_fetch_response.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
+#include "services/network/public/mojom/fetch_api.mojom.h"
#include "storage/browser/blob/blob_data_handle.h"
#include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -35,6 +42,7 @@ namespace content {
namespace {
using background_fetch::BackgroundFetchInitializationData;
+using ::testing::_;
using ::testing::UnorderedElementsAre;
using ::testing::IsEmpty;
@@ -60,16 +68,15 @@ void DidGetInitializationData(
std::move(quit_closure).Run();
}
-void DidCreateRegistration(
- base::Closure quit_closure,
- blink::mojom::BackgroundFetchError* out_error,
- blink::mojom::BackgroundFetchError error,
- std::unique_ptr<BackgroundFetchRegistration> registration) {
+void DidCreateRegistration(base::OnceClosure quit_closure,
+ blink::mojom::BackgroundFetchError* out_error,
+ blink::mojom::BackgroundFetchError error,
+ const BackgroundFetchRegistration& registration) {
*out_error = error;
std::move(quit_closure).Run();
}
-void DidGetError(base::Closure quit_closure,
+void DidGetError(base::OnceClosure quit_closure,
blink::mojom::BackgroundFetchError* out_error,
blink::mojom::BackgroundFetchError error) {
*out_error = error;
@@ -89,7 +96,8 @@ void DidGetRegistrationUserDataByKeyPrefix(
void AnnotateRequestInfoWithFakeDownloadManagerData(
BackgroundFetchRequestInfo* request_info,
- bool success = false) {
+ bool success = false,
+ bool over_quota = false) {
DCHECK(request_info);
std::string headers =
@@ -109,7 +117,7 @@ void AnnotateRequestInfoWithFakeDownloadManagerData(
// |kResponseFileSize| for tests that use filesize.
request_info->SetResult(std::make_unique<BackgroundFetchResult>(
base::Time::Now(), base::FilePath(), base::nullopt /* blob_handle */,
- kResponseFileSize));
+ over_quota ? kBackgroundFetchMaxQuotaBytes + 1 : kResponseFileSize));
}
void GetNumUserData(base::Closure quit_closure,
@@ -145,6 +153,32 @@ std::vector<ServiceWorkerFetchRequest> CreateValidRequests(
return requests;
}
+ServiceWorkerFetchRequest CreateValidRequestWithMethod(
+ const url::Origin& origin,
+ const std::string& method) {
+ ServiceWorkerFetchRequest request;
+ request.url = origin.GetURL();
+ request.method = method;
+ return request;
+}
+
+SkBitmap CreateTestIcon(int size = 42, SkColor color = SK_ColorGREEN) {
+ SkBitmap icon;
+ icon.allocN32Pixels(size, size);
+ icon.eraseColor(SK_ColorGREEN);
+ return icon;
+}
+
+void ExpectIconProperties(const SkBitmap& icon, int size, SkColor color) {
+ EXPECT_FALSE(icon.isNull());
+ EXPECT_EQ(icon.width(), size);
+ EXPECT_EQ(icon.height(), size);
+ for (int i = 0; i < icon.width(); i++) {
+ for (int j = 0; j < icon.height(); j++)
+ EXPECT_EQ(icon.getColor(i, j), color);
+ }
+}
+
} // namespace
class BackgroundFetchDataManagerTest
@@ -204,14 +238,14 @@ class BackgroundFetchDataManagerTest
run_loop.Run();
}
- std::unique_ptr<BackgroundFetchRegistration> GetRegistration(
+ BackgroundFetchRegistration GetRegistration(
int64_t service_worker_registration_id,
const url::Origin& origin,
const std::string developer_id,
blink::mojom::BackgroundFetchError* out_error) {
DCHECK(out_error);
- std::unique_ptr<BackgroundFetchRegistration> registration;
+ BackgroundFetchRegistration registration;
base::RunLoop run_loop;
background_fetch_data_manager_->GetRegistration(
service_worker_registration_id, origin, developer_id,
@@ -225,18 +259,16 @@ class BackgroundFetchDataManagerTest
std::unique_ptr<proto::BackgroundFetchMetadata> GetMetadata(
int64_t service_worker_registration_id,
- const url::Origin& origin,
- const std::string developer_id,
- blink::mojom::BackgroundFetchError* out_error) {
- DCHECK(out_error);
-
+ const std::string& unique_id) {
std::unique_ptr<proto::BackgroundFetchMetadata> metadata;
+
base::RunLoop run_loop;
- background_fetch_data_manager_->GetMetadata(
- service_worker_registration_id, origin, developer_id,
+ embedded_worker_test_helper()->context_wrapper()->GetRegistrationUserData(
+ service_worker_registration_id,
+ {background_fetch::RegistrationKey(unique_id)},
base::BindOnce(&BackgroundFetchDataManagerTest::DidGetMetadata,
base::Unretained(this), run_loop.QuitClosure(),
- out_error, &metadata));
+ &metadata));
run_loop.Run();
return metadata;
@@ -244,13 +276,14 @@ class BackgroundFetchDataManagerTest
void UpdateRegistrationUI(
const BackgroundFetchRegistrationId& registration_id,
- const std::string& updated_title,
+ const base::Optional<std::string>& updated_title,
+ const base::Optional<SkBitmap>& updated_icon,
blink::mojom::BackgroundFetchError* out_error) {
DCHECK(out_error);
base::RunLoop run_loop;
background_fetch_data_manager_->UpdateRegistrationUI(
- registration_id, updated_title,
+ registration_id, updated_title, updated_icon,
base::BindOnce(&BackgroundFetchDataManagerTest::DidUpdateRegistrationUI,
base::Unretained(this), run_loop.QuitClosure(),
out_error));
@@ -334,6 +367,9 @@ class BackgroundFetchDataManagerTest
// BackgroundFetchDataManager::GetSettledFetchesForRegistration().
void GetSettledFetchesForRegistration(
const BackgroundFetchRegistrationId& registration_id,
+ base::Optional<ServiceWorkerFetchRequest> request_to_match,
+ blink::mojom::QueryParamsPtr cache_query_params,
+ bool match_all,
blink::mojom::BackgroundFetchError* out_error,
bool* out_succeeded,
std::vector<BackgroundFetchSettledFetch>* out_settled_fetches) {
@@ -342,8 +378,10 @@ class BackgroundFetchDataManagerTest
DCHECK(out_settled_fetches);
base::RunLoop run_loop;
+ auto match_params = std::make_unique<BackgroundFetchRequestMatchParams>(
+ request_to_match, std::move(cache_query_params), match_all);
background_fetch_data_manager_->GetSettledFetchesForRegistration(
- registration_id,
+ registration_id, std::move(match_params),
base::BindOnce(&BackgroundFetchDataManagerTest::
DidGetSettledFetchesForRegistration,
base::Unretained(this), run_loop.QuitClosure(),
@@ -402,6 +440,78 @@ class BackgroundFetchDataManagerTest
return result;
}
+ void DeleteFromCache(const ServiceWorkerFetchRequest& request) {
+ CacheStorageCacheHandle handle;
+ {
+ base::RunLoop run_loop;
+ background_fetch_data_manager_->cache_manager()->OpenCache(
+ origin(), CacheStorageOwner::kBackgroundFetch,
+ kExampleUniqueId /* cache_name */,
+ base::BindOnce(&BackgroundFetchDataManagerTest::DidOpenCache,
+ base::Unretained(this), run_loop.QuitClosure(),
+ &handle));
+ run_loop.Run();
+ }
+
+ DCHECK(handle.value());
+
+ {
+ base::RunLoop run_loop;
+ std::vector<blink::mojom::BatchOperationPtr> operation_ptr_vec;
+ operation_ptr_vec.push_back(blink::mojom::BatchOperation::New());
+ operation_ptr_vec[0]->operation_type =
+ blink::mojom::OperationType::kDelete;
+ operation_ptr_vec[0]->request = request;
+
+ handle.value()->BatchOperation(
+ std::move(operation_ptr_vec), true /* fail_on_duplicates */,
+ base::BindOnce(&BackgroundFetchDataManagerTest::DidDeleteFromCache,
+ base::Unretained(this), run_loop.QuitClosure()),
+ base::DoNothing());
+
+ run_loop.Run();
+ }
+ }
+
+ // Returns the title and the icon.
+ std::pair<std::string, SkBitmap> GetUIOptions(
+ int64_t service_worker_registration_id) {
+ auto results = GetRegistrationUserDataByKeyPrefix(
+ service_worker_registration_id, background_fetch::kUIOptionsKeyPrefix);
+ DCHECK_LT(results.size(), 2u)
+ << "Using GetUIOptions with multiple registrations is unimplemented";
+
+ proto::BackgroundFetchUIOptions ui_options;
+ if (results.empty())
+ return {"", SkBitmap()};
+
+ bool did_parse = ui_options.ParseFromString(results[0]);
+ DCHECK(did_parse);
+
+ std::pair<std::string, SkBitmap> result{ui_options.title(), SkBitmap()};
+
+ if (ui_options.icon().empty())
+ return result;
+
+ // Deserialize icon.
+ {
+ base::RunLoop run_loop;
+ background_fetch::DeserializeIcon(
+ std::unique_ptr<std::string>(ui_options.release_icon()),
+ base::BindOnce(
+ [](base::OnceClosure quit_closure, SkBitmap* out_icon,
+ SkBitmap icon) {
+ DCHECK(out_icon);
+ *out_icon = std::move(icon);
+ std::move(quit_closure).Run();
+ },
+ run_loop.QuitClosure(), &result.second));
+ run_loop.Run();
+ }
+
+ return result;
+ }
+
// Gets information about the number of background fetch requests by state.
ResponseStateStats GetRequestStats(int64_t service_worker_registration_id) {
ResponseStateStats stats;
@@ -442,39 +552,45 @@ class BackgroundFetchDataManagerTest
}
// BackgroundFetchDataManagerObserver mocks:
- MOCK_METHOD2(OnUpdatedUI,
+ MOCK_METHOD5(OnRegistrationCreated,
+ void(const BackgroundFetchRegistrationId& registration_id,
+ const BackgroundFetchRegistration& registration,
+ const BackgroundFetchOptions& options,
+ const SkBitmap& icon,
+ int num_requests));
+ MOCK_METHOD3(OnUpdatedUI,
void(const BackgroundFetchRegistrationId& registration,
- const std::string& title));
+ const base::Optional<std::string>& title,
+ const base::Optional<SkBitmap>& icon));
MOCK_METHOD1(OnServiceWorkerDatabaseCorrupted,
void(int64_t service_worker_registration_id));
+ MOCK_METHOD1(OnQuotaExceeded,
+ void(const BackgroundFetchRegistrationId& registration_id));
protected:
- void DidGetRegistration(
- base::Closure quit_closure,
- blink::mojom::BackgroundFetchError* out_error,
- std::unique_ptr<BackgroundFetchRegistration>* out_registration,
- blink::mojom::BackgroundFetchError error,
- std::unique_ptr<BackgroundFetchRegistration> registration) {
- if (error == blink::mojom::BackgroundFetchError::NONE) {
- DCHECK(registration);
- }
+ void DidGetRegistration(base::OnceClosure quit_closure,
+ blink::mojom::BackgroundFetchError* out_error,
+ BackgroundFetchRegistration* out_registration,
+ blink::mojom::BackgroundFetchError error,
+ const BackgroundFetchRegistration& registration) {
*out_error = error;
- *out_registration = std::move(registration);
+ *out_registration = registration;
std::move(quit_closure).Run();
}
void DidGetMetadata(
base::OnceClosure quit_closure,
- blink::mojom::BackgroundFetchError* out_error,
std::unique_ptr<proto::BackgroundFetchMetadata>* out_metadata,
- blink::mojom::BackgroundFetchError error,
- std::unique_ptr<proto::BackgroundFetchMetadata> metadata) {
- if (error == blink::mojom::BackgroundFetchError::NONE) {
- DCHECK(metadata);
+ const std::vector<std::string>& data,
+ blink::ServiceWorkerStatusCode status) {
+ if (status == blink::ServiceWorkerStatusCode::kOk) {
+ DCHECK_EQ(data.size(), 1u);
+
+ auto metadata = std::make_unique<proto::BackgroundFetchMetadata>();
+ if (metadata->ParseFromString(data[0]))
+ *out_metadata = std::move(metadata);
}
- *out_error = error;
- *out_metadata = std::move(metadata);
std::move(quit_closure).Run();
}
@@ -537,7 +653,7 @@ class BackgroundFetchDataManagerTest
void DidMatchCache(base::OnceClosure quit_closure,
bool* out_result,
blink::mojom::CacheStorageError error,
- std::unique_ptr<ServiceWorkerResponse> response) {
+ blink::mojom::FetchAPIResponsePtr response) {
if (error == blink::mojom::CacheStorageError::kSuccess) {
DCHECK(response);
*out_result = true;
@@ -547,6 +663,22 @@ class BackgroundFetchDataManagerTest
std::move(quit_closure).Run();
}
+ void DidOpenCache(base::OnceClosure quit_closure,
+ CacheStorageCacheHandle* out_handle,
+ CacheStorageCacheHandle handle,
+ blink::mojom::CacheStorageError error) {
+ DCHECK(out_handle);
+ DCHECK_EQ(error, blink::mojom::CacheStorageError::kSuccess);
+ *out_handle = std::move(handle);
+ std::move(quit_closure).Run();
+ }
+
+ void DidDeleteFromCache(base::OnceClosure quit_closure,
+ blink::mojom::CacheStorageVerboseErrorPtr error) {
+ DCHECK_EQ(error->value, blink::mojom::CacheStorageError::kSuccess);
+ std::move(quit_closure).Run();
+ }
+
std::unique_ptr<BackgroundFetchTestDataManager>
background_fetch_data_manager_;
};
@@ -574,8 +706,12 @@ TEST_F(BackgroundFetchDataManagerTest, NoDuplicateRegistrations) {
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ID);
// Creating the initial registration should succeed.
- CreateRegistration(registration_id1, requests, options, SkBitmap(), &error);
- EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id1, _, _, _, _));
+
+ CreateRegistration(registration_id1, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
// Different |unique_id|, since this is a new Background Fetch registration,
// even though it shares the same |developer_id|.
@@ -599,8 +735,33 @@ TEST_F(BackgroundFetchDataManagerTest, NoDuplicateRegistrations) {
// And now registering the second registration should work fine, since there
// is no longer an *active* registration with the same |developer_id|, even
// though the initial registration has not yet been deleted.
- CreateRegistration(registration_id2, requests, options, SkBitmap(), &error);
- EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id2, _, _, _, _));
+
+ CreateRegistration(registration_id2, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
+}
+
+TEST_F(BackgroundFetchDataManagerTest, ExceedingQuotaFailsCreation) {
+ // Tests that the BackgroundFetchDataManager correctly rejects creating a
+ // registration where the provided download total exceeds the available quota.
+
+ int64_t service_worker_registration_id = RegisterServiceWorker();
+ ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId,
+ service_worker_registration_id);
+
+ BackgroundFetchRegistrationId registration_id(service_worker_registration_id,
+ origin(), kExampleDeveloperId,
+ kExampleUniqueId);
+ std::vector<ServiceWorkerFetchRequest> requests;
+ BackgroundFetchOptions options;
+ options.download_total = kBackgroundFetchMaxQuotaBytes + 1;
+
+ blink::mojom::BackgroundFetchError error;
+
+ CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::QUOTA_EXCEEDED);
}
TEST_F(BackgroundFetchDataManagerTest, GetDeveloperIds) {
@@ -619,8 +780,12 @@ TEST_F(BackgroundFetchDataManagerTest, GetDeveloperIds) {
// Create a single registration.
BackgroundFetchRegistrationId registration_id1(
sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
- CreateRegistration(registration_id1, requests, options, SkBitmap(), &error);
- EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id1, _, _, _, _));
+
+ CreateRegistration(registration_id1, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
// Verify that the developer ID can be found.
developer_ids = GetDeveloperIds(sw_id, origin(), &error);
@@ -637,9 +802,12 @@ TEST_F(BackgroundFetchDataManagerTest, GetDeveloperIds) {
// Create another registration.
BackgroundFetchRegistrationId registration_id2(
sw_id, origin(), kAlternativeDeveloperId, kAlternativeUniqueId);
- CreateRegistration(registration_id2, requests, options, SkBitmap(), &error);
- EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id2, _, _, _, _));
+ CreateRegistration(registration_id2, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
// Verify that both developer IDs can be found.
developer_ids = GetDeveloperIds(sw_id, origin(), &error);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
@@ -666,31 +834,34 @@ TEST_F(BackgroundFetchDataManagerTest, GetRegistration) {
blink::mojom::BackgroundFetchError error;
// Create a single registration.
- CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
- EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+ CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
// Verify that the registration can be retrieved.
auto registration =
GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
- ASSERT_TRUE(registration);
- EXPECT_EQ(kExampleUniqueId, registration->unique_id);
- EXPECT_EQ(kExampleDeveloperId, registration->developer_id);
+
+ EXPECT_EQ(kExampleUniqueId, registration.unique_id);
+ EXPECT_EQ(kExampleDeveloperId, registration.developer_id);
// Verify that retrieving using the wrong developer id doesn't work.
registration =
GetRegistration(sw_id, origin(), kAlternativeDeveloperId, &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ID);
- ASSERT_FALSE(registration);
RestartDataManagerFromPersistentStorage();
// After a restart, GetRegistration should still find the registration.
registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
- ASSERT_TRUE(registration);
- EXPECT_EQ(kExampleUniqueId, registration->unique_id);
- EXPECT_EQ(kExampleDeveloperId, registration->developer_id);
+
+ EXPECT_EQ(kExampleUniqueId, registration.unique_id);
+ EXPECT_EQ(kExampleDeveloperId, registration.developer_id);
}
TEST_F(BackgroundFetchDataManagerTest, GetMetadata) {
@@ -705,27 +876,23 @@ TEST_F(BackgroundFetchDataManagerTest, GetMetadata) {
blink::mojom::BackgroundFetchError error;
// Create a single registration.
- CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
- EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+ CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
// Verify that the metadata can be retrieved.
- auto metadata = GetMetadata(sw_id, origin(), kExampleDeveloperId, &error);
- ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ auto metadata = GetMetadata(sw_id, kExampleUniqueId);
ASSERT_TRUE(metadata);
EXPECT_EQ(metadata->origin(), origin().Serialize());
EXPECT_NE(metadata->creation_microseconds_since_unix_epoch(), 0);
EXPECT_EQ(metadata->num_fetches(), static_cast<int>(requests.size()));
- // Verify that retrieving using the wrong developer id doesn't work.
- metadata = GetMetadata(sw_id, origin(), kAlternativeDeveloperId, &error);
- ASSERT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ID);
- ASSERT_FALSE(metadata);
-
RestartDataManagerFromPersistentStorage();
// After a restart, GetMetadata should still find the registration.
- metadata = GetMetadata(sw_id, origin(), kExampleDeveloperId, &error);
- ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ metadata = GetMetadata(sw_id, kExampleUniqueId);
ASSERT_TRUE(metadata);
EXPECT_EQ(metadata->origin(), origin().Serialize());
EXPECT_NE(metadata->creation_microseconds_since_unix_epoch(), 0);
@@ -743,22 +910,24 @@ TEST_F(BackgroundFetchDataManagerTest, LargeIconNotPersisted) {
BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error;
- SkBitmap icon;
- icon.allocN32Pixels(512, 512);
- icon.eraseColor(SK_ColorGREEN);
+ SkBitmap icon = CreateTestIcon(512 /* size */);
+ ASSERT_FALSE(background_fetch::ShouldPersistIcon(icon));
// Create a single registration.
- CreateRegistration(registration_id, requests, options, icon, &error);
- EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+ CreateRegistration(registration_id, requests, options, icon, &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
// Verify that the metadata can be retrieved.
- auto metadata = GetMetadata(sw_id, origin(), kExampleDeveloperId, &error);
- ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ auto metadata = GetMetadata(sw_id, kExampleUniqueId);
ASSERT_TRUE(metadata);
EXPECT_EQ(metadata->origin(), origin().Serialize());
EXPECT_NE(metadata->creation_microseconds_since_unix_epoch(), 0);
EXPECT_EQ(metadata->num_fetches(), static_cast<int>(requests.size()));
- EXPECT_TRUE(metadata->icon().empty());
+ EXPECT_TRUE(GetUIOptions(sw_id).second.isNull());
}
TEST_F(BackgroundFetchDataManagerTest, UpdateRegistrationUI) {
@@ -774,35 +943,93 @@ TEST_F(BackgroundFetchDataManagerTest, UpdateRegistrationUI) {
blink::mojom::BackgroundFetchError error;
// There should be no title before the registration.
- std::vector<std::string> title = GetRegistrationUserDataByKeyPrefix(
- sw_id, background_fetch::kTitleKeyPrefix);
- EXPECT_TRUE(title.empty());
+ EXPECT_TRUE(GetUIOptions(sw_id).first.empty());
// Create a single registration.
- CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
- EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+ CreateRegistration(registration_id, requests, options, CreateTestIcon(),
+ &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
- // Verify that the title can be retrieved.
- title = GetRegistrationUserDataByKeyPrefix(sw_id,
- background_fetch::kTitleKeyPrefix);
- EXPECT_EQ(title.size(), 1u);
- ASSERT_EQ(title.front(), kInitialTitle);
+ // Verify that the UI Options can be retrieved.
+ {
+ auto ui_options = GetUIOptions(sw_id);
+ EXPECT_EQ(ui_options.first, kInitialTitle);
+ EXPECT_NO_FATAL_FAILURE(
+ ExpectIconProperties(ui_options.second, 42, SK_ColorGREEN));
+ }
- // Update the title.
+ // Update only the title.
{
- EXPECT_CALL(*this, OnUpdatedUI(registration_id, kUpdatedTitle));
+ EXPECT_CALL(*this,
+ OnUpdatedUI(registration_id,
+ base::Optional<std::string>(kUpdatedTitle), _));
- UpdateRegistrationUI(registration_id, kUpdatedTitle, &error);
+ UpdateRegistrationUI(registration_id, kUpdatedTitle, base::nullopt, &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+
+ auto ui_options = GetUIOptions(sw_id);
+ // Expect new title.
+ EXPECT_EQ(ui_options.first, kUpdatedTitle);
+ // Expect same icon as before.
+ EXPECT_NO_FATAL_FAILURE(
+ ExpectIconProperties(ui_options.second, 42, SK_ColorGREEN));
}
- RestartDataManagerFromPersistentStorage();
+ // Update only the icon.
+ {
+ EXPECT_CALL(*this, OnUpdatedUI(registration_id, _, _));
+
+ UpdateRegistrationUI(registration_id, base::nullopt,
+ CreateTestIcon(24 /* size */), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+
+ auto ui_options = GetUIOptions(sw_id);
+ // Expect the same title as before.
+ EXPECT_EQ(ui_options.first, kUpdatedTitle);
+ // Expect the new icon with the different size.
+ EXPECT_NO_FATAL_FAILURE(
+ ExpectIconProperties(ui_options.second, 24, SK_ColorGREEN));
+ }
+
+ // Update both the title and icon.
+ {
+ EXPECT_CALL(*this,
+ OnUpdatedUI(registration_id,
+ base::Optional<std::string>(kInitialTitle), _));
+
+ UpdateRegistrationUI(registration_id, kInitialTitle,
+ CreateTestIcon(66 /* size */), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
- // After a restart, GetMetadata should find the new title.
- title = GetRegistrationUserDataByKeyPrefix(sw_id,
- background_fetch::kTitleKeyPrefix);
- EXPECT_EQ(title.size(), 1u);
- ASSERT_EQ(title.front(), kUpdatedTitle);
+ auto ui_options = GetUIOptions(sw_id);
+ // Expect the initial title again.
+ EXPECT_EQ(ui_options.first, kInitialTitle);
+ // Expect the new icon with the different size.
+ EXPECT_NO_FATAL_FAILURE(
+ ExpectIconProperties(ui_options.second, 66, SK_ColorGREEN));
+ }
+
+ // New title and an icon that's too large.
+ {
+ EXPECT_CALL(*this,
+ OnUpdatedUI(registration_id,
+ base::Optional<std::string>(kUpdatedTitle), _));
+
+ UpdateRegistrationUI(registration_id, kUpdatedTitle,
+ CreateTestIcon(512 /* size */), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+
+ auto ui_options = GetUIOptions(sw_id);
+ // Expect the new title.
+ EXPECT_EQ(ui_options.first, kUpdatedTitle);
+ // Expect same icon as before.
+ EXPECT_NO_FATAL_FAILURE(
+ ExpectIconProperties(ui_options.second, 66, SK_ColorGREEN));
+ }
}
TEST_F(BackgroundFetchDataManagerTest, CreateAndDeleteRegistration) {
@@ -816,8 +1043,12 @@ TEST_F(BackgroundFetchDataManagerTest, CreateAndDeleteRegistration) {
BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error;
- CreateRegistration(registration_id1, requests, options, SkBitmap(), &error);
- EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id1, _, _, _, _));
+
+ CreateRegistration(registration_id1, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
RestartDataManagerFromPersistentStorage();
@@ -830,15 +1061,15 @@ TEST_F(BackgroundFetchDataManagerTest, CreateAndDeleteRegistration) {
// |service_worker_registration_id| should yield an error, even after
// restarting.
CreateRegistration(registration_id2, requests, options, SkBitmap(), &error);
- EXPECT_EQ(error, blink::mojom::BackgroundFetchError::DUPLICATED_DEVELOPER_ID);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::DUPLICATED_DEVELOPER_ID);
// Verify that the registration can be retrieved before deletion.
auto registration =
GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
- ASSERT_TRUE(registration);
- EXPECT_EQ(kExampleUniqueId, registration->unique_id);
- EXPECT_EQ(kExampleDeveloperId, registration->developer_id);
+
+ EXPECT_EQ(kExampleUniqueId, registration.unique_id);
+ EXPECT_EQ(kExampleDeveloperId, registration.developer_id);
// Deactivating the registration should succeed.
MarkRegistrationForDeletion(registration_id1, &error);
@@ -847,7 +1078,6 @@ TEST_F(BackgroundFetchDataManagerTest, CreateAndDeleteRegistration) {
// Verify that the registration cannot be retrieved after deletion
registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ID);
- ASSERT_FALSE(registration);
RestartDataManagerFromPersistentStorage();
@@ -855,14 +1085,17 @@ TEST_F(BackgroundFetchDataManagerTest, CreateAndDeleteRegistration) {
// a restart.
registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ID);
- ASSERT_FALSE(registration);
// And now registering the second registration should work fine, even after
// restarting, since there is no longer an *active* registration with the same
// |developer_id|, even though the initial registration has not yet been
// deleted.
- CreateRegistration(registration_id2, requests, options, SkBitmap(), &error);
- EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id2, _, _, _, _));
+
+ CreateRegistration(registration_id2, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
RestartDataManagerFromPersistentStorage();
@@ -893,8 +1126,13 @@ TEST_F(BackgroundFetchDataManagerTest, PopNextRequestAndMarkAsComplete) {
BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error;
- CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
- EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+ CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
+
EXPECT_EQ(
GetRequestStats(sw_id),
(ResponseStateStats{2 /* pending_requests */, 0 /* active_requests */,
@@ -956,13 +1194,17 @@ TEST_F(BackgroundFetchDataManagerTest, DownloadTotalUpdated) {
BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error;
- CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
- EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+ CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
auto registration =
GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
- EXPECT_EQ(registration->download_total, 0u);
+ EXPECT_EQ(registration.download_total, 0u);
scoped_refptr<BackgroundFetchRequestInfo> request_info;
PopNextRequest(registration_id, &request_info);
@@ -972,7 +1214,7 @@ TEST_F(BackgroundFetchDataManagerTest, DownloadTotalUpdated) {
registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
- EXPECT_EQ(registration->download_total, kResponseFileSize);
+ EXPECT_EQ(registration.download_total, kResponseFileSize);
PopNextRequest(registration_id, &request_info);
AnnotateRequestInfoWithFakeDownloadManagerData(request_info.get(),
@@ -981,7 +1223,7 @@ TEST_F(BackgroundFetchDataManagerTest, DownloadTotalUpdated) {
registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
- EXPECT_EQ(registration->download_total, 2 * kResponseFileSize);
+ EXPECT_EQ(registration.download_total, 2 * kResponseFileSize);
PopNextRequest(registration_id, &request_info);
AnnotateRequestInfoWithFakeDownloadManagerData(request_info.get(),
@@ -991,7 +1233,34 @@ TEST_F(BackgroundFetchDataManagerTest, DownloadTotalUpdated) {
registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
// |download_total| is unchanged.
- EXPECT_EQ(registration->download_total, 2 * kResponseFileSize);
+ EXPECT_EQ(registration.download_total, 2 * kResponseFileSize);
+}
+
+TEST_F(BackgroundFetchDataManagerTest, ExceedingQuotaAbandonsFetch) {
+ int64_t sw_id = RegisterServiceWorker();
+ ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, sw_id);
+
+ BackgroundFetchRegistrationId registration_id(
+ sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
+ auto requests = CreateValidRequests(origin(), 3u /* num_requests */);
+
+ BackgroundFetchOptions options;
+ blink::mojom::BackgroundFetchError error;
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+ CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
+
+ scoped_refptr<BackgroundFetchRequestInfo> request_info;
+ PopNextRequest(registration_id, &request_info);
+ AnnotateRequestInfoWithFakeDownloadManagerData(
+ request_info.get(), true /* succeeded */, true /* over_quota */);
+ {
+ EXPECT_CALL(*this, OnQuotaExceeded(registration_id));
+ MarkRequestAsComplete(registration_id, request_info.get());
+ }
}
TEST_F(BackgroundFetchDataManagerTest, WriteToCache) {
@@ -1004,9 +1273,12 @@ TEST_F(BackgroundFetchDataManagerTest, WriteToCache) {
BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error;
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
- CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
- EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
scoped_refptr<BackgroundFetchRequestInfo> request_info;
PopNextRequest(registration_id, &request_info);
@@ -1048,9 +1320,12 @@ TEST_F(BackgroundFetchDataManagerTest, CacheDeleted) {
BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error;
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
- CreateRegistration(registration_id, {request}, options, SkBitmap(), &error);
- EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ CreateRegistration(registration_id, {request}, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
scoped_refptr<BackgroundFetchRequestInfo> request_info;
PopNextRequest(registration_id, &request_info);
@@ -1075,14 +1350,20 @@ TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesForRegistration) {
int64_t sw_id = RegisterServiceWorker();
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, sw_id);
- std::vector<ServiceWorkerFetchRequest> requests(2u);
+ std::vector<ServiceWorkerFetchRequest> requests =
+ CreateValidRequests(origin(), 2u /* num_requests */);
BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error;
BackgroundFetchRegistrationId registration_id(
sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
- CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
- ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+ CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
+
EXPECT_EQ(
GetRequestStats(sw_id),
(ResponseStateStats{2 /* pending_requests */, 0 /* active_requests */,
@@ -1091,8 +1372,10 @@ TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesForRegistration) {
// Nothing is downloaded yet.
bool succeeded = false;
std::vector<BackgroundFetchSettledFetch> settled_fetches;
- GetSettledFetchesForRegistration(registration_id, &error, &succeeded,
- &settled_fetches);
+ GetSettledFetchesForRegistration(
+ registration_id, base::nullopt /* request_to_match */,
+ nullptr /* cache_query_params */, false /* match_all */, &error,
+ &succeeded, &settled_fetches);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
EXPECT_TRUE(succeeded);
EXPECT_EQ(settled_fetches.size(), 0u);
@@ -1112,8 +1395,10 @@ TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesForRegistration) {
(ResponseStateStats{0 /* pending_requests */, 0 /* active_requests */,
requests.size() /* completed_requests */}));
- GetSettledFetchesForRegistration(registration_id, &error, &succeeded,
- &settled_fetches);
+ GetSettledFetchesForRegistration(
+ registration_id, base::nullopt /* request_to_match */,
+ nullptr /* cache_query_params */, false /* match_all */, &error,
+ &succeeded, &settled_fetches);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
// We are marking the responses as failed in Download Manager.
@@ -1131,14 +1416,20 @@ TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesFromCache) {
BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error;
- CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
- EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+ CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
bool succeeded = false;
std::vector<BackgroundFetchSettledFetch> settled_fetches;
// Nothing is downloaded yet.
- GetSettledFetchesForRegistration(registration_id, &error, &succeeded,
- &settled_fetches);
+ GetSettledFetchesForRegistration(
+ registration_id, base::nullopt /* request_to_match */,
+ nullptr /* cache_query_params */, false /* match_all */, &error,
+ &succeeded, &settled_fetches);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
EXPECT_TRUE(succeeded);
EXPECT_EQ(settled_fetches.size(), 0u);
@@ -1150,8 +1441,10 @@ TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesFromCache) {
true /* success */);
MarkRequestAsComplete(registration_id, request_info.get());
- GetSettledFetchesForRegistration(registration_id, &error, &succeeded,
- &settled_fetches);
+ GetSettledFetchesForRegistration(
+ registration_id, base::nullopt /* request_to_match */,
+ nullptr /* cache_query_params */, false /* match_all */, &error,
+ &succeeded, &settled_fetches);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
EXPECT_TRUE(succeeded);
EXPECT_EQ(settled_fetches.size(), 1u);
@@ -1162,8 +1455,10 @@ TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesFromCache) {
true /* success */);
MarkRequestAsComplete(registration_id, request_info.get());
- GetSettledFetchesForRegistration(registration_id, &error, &succeeded,
- &settled_fetches);
+ GetSettledFetchesForRegistration(
+ registration_id, base::nullopt /* request_to_match */,
+ nullptr /* cache_query_params */, false /* match_all */, &error,
+ &succeeded, &settled_fetches);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
EXPECT_TRUE(succeeded);
ASSERT_EQ(settled_fetches.size(), 2u);
@@ -1171,20 +1466,164 @@ TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesFromCache) {
// Sanity check that the responses are written to / read from the cache.
EXPECT_TRUE(MatchCache(requests[0]));
EXPECT_TRUE(MatchCache(requests[1]));
- EXPECT_EQ(settled_fetches[0].response.cache_storage_cache_name,
+ EXPECT_EQ(settled_fetches[0].response->cache_storage_cache_name,
kExampleUniqueId);
- EXPECT_EQ(settled_fetches[1].response.cache_storage_cache_name,
+ EXPECT_EQ(settled_fetches[1].response->cache_storage_cache_name,
kExampleUniqueId);
RestartDataManagerFromPersistentStorage();
- GetSettledFetchesForRegistration(registration_id, &error, &succeeded,
- &settled_fetches);
+ GetSettledFetchesForRegistration(
+ registration_id, base::nullopt /* request_to_match */,
+ nullptr /* cache_query_params */, false /* match_all */, &error,
+ &succeeded, &settled_fetches);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
EXPECT_TRUE(succeeded);
EXPECT_EQ(settled_fetches.size(), 2u);
}
+TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesForASpecificRequest) {
+ int64_t sw_id = RegisterServiceWorker();
+ ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, sw_id);
+
+ auto requests = CreateValidRequests(origin(), 2u /* num_requests */);
+ BackgroundFetchOptions options;
+ blink::mojom::BackgroundFetchError error;
+ BackgroundFetchRegistrationId registration_id(
+ sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
+
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+ CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
+
+ for (size_t i = 0; i < requests.size(); i++) {
+ SCOPED_TRACE(i);
+ scoped_refptr<BackgroundFetchRequestInfo> request_info;
+ PopNextRequest(registration_id, &request_info);
+ ASSERT_TRUE(request_info);
+ AnnotateRequestInfoWithFakeDownloadManagerData(request_info.get());
+ MarkRequestAsComplete(registration_id, request_info.get());
+ }
+
+ EXPECT_EQ(
+ GetRequestStats(sw_id),
+ (ResponseStateStats{0 /* pending_requests */, 0 /* active_requests */,
+ requests.size() /* completed_requests */}));
+
+ bool succeeded = false;
+ std::vector<BackgroundFetchSettledFetch> settled_fetches;
+ GetSettledFetchesForRegistration(
+ registration_id, requests[0] /* request_to_match */,
+ nullptr /* cache_query_params */, false /* match_all */, &error,
+ &succeeded, &settled_fetches);
+
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ // We are marking the responses as failed in Download Manager.
+ EXPECT_FALSE(succeeded);
+ EXPECT_EQ(settled_fetches.size(), 1u);
+}
+
+TEST_F(BackgroundFetchDataManagerTest,
+ GetSettledFetchesForANonMatchingRequest) {
+ int64_t sw_id = RegisterServiceWorker();
+ ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, sw_id);
+
+ auto requests = CreateValidRequests(origin(), 3u /* num_requests */);
+ BackgroundFetchOptions options;
+ blink::mojom::BackgroundFetchError error;
+ BackgroundFetchRegistrationId registration_id(
+ sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
+
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+ CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
+
+ for (size_t i = 0; i < requests.size() - 1; i++) {
+ SCOPED_TRACE(i);
+ scoped_refptr<BackgroundFetchRequestInfo> request_info;
+ PopNextRequest(registration_id, &request_info);
+ ASSERT_TRUE(request_info);
+ AnnotateRequestInfoWithFakeDownloadManagerData(request_info.get());
+ MarkRequestAsComplete(registration_id, request_info.get());
+ }
+
+ EXPECT_EQ(
+ GetRequestStats(sw_id),
+ (ResponseStateStats{1 /* pending_requests */, 0 /* active_requests */,
+ requests.size() - 1 /* completed_requests */}));
+
+ bool succeeded = false;
+ std::vector<BackgroundFetchSettledFetch> settled_fetches;
+ GetSettledFetchesForRegistration(
+ registration_id, requests[2] /* request_to_match */,
+ nullptr /* cache_query_params */, false /* match_all */, &error,
+ &succeeded, &settled_fetches);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ EXPECT_EQ(settled_fetches.size(), 1u);
+ EXPECT_EQ(settled_fetches[0].response->response_type,
+ network::mojom::FetchResponseType::kError);
+}
+
+TEST_F(BackgroundFetchDataManagerTest, IgnoreMethodAndMatchAll) {
+ int64_t sw_id = RegisterServiceWorker();
+ ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, sw_id);
+
+ std::vector<ServiceWorkerFetchRequest> requests = {
+ CreateValidRequestWithMethod(origin(), "GET"),
+ CreateValidRequestWithMethod(origin(), "POST")};
+
+ BackgroundFetchOptions options;
+ blink::mojom::BackgroundFetchError error;
+ BackgroundFetchRegistrationId registration_id(
+ sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
+
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+ CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
+
+ for (size_t i = 0; i < requests.size(); i++) {
+ SCOPED_TRACE(i);
+ scoped_refptr<BackgroundFetchRequestInfo> request_info;
+ PopNextRequest(registration_id, &request_info);
+ ASSERT_TRUE(request_info);
+ AnnotateRequestInfoWithFakeDownloadManagerData(request_info.get());
+ MarkRequestAsComplete(registration_id, request_info.get());
+ }
+
+ EXPECT_EQ(
+ GetRequestStats(sw_id),
+ (ResponseStateStats{0 /* pending_requests */, 0 /* active_requests */,
+ requests.size() /* completed_requests */}));
+
+ bool succeeded = false;
+ std::vector<BackgroundFetchSettledFetch> settled_fetches;
+ blink::mojom::QueryParamsPtr cache_query_params =
+ blink::mojom::QueryParams::New();
+ cache_query_params->ignore_method = true;
+ GetSettledFetchesForRegistration(
+ registration_id, requests[0] /* request_to_match */,
+ std::move(cache_query_params), true /* match_all */, &error, &succeeded,
+ &settled_fetches);
+
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ // We are marking the responses as failed in Download Manager.
+ EXPECT_FALSE(succeeded);
+ // If the ASSERT below fails, the Cache Storage API implementation has likely
+ // changed to distinguish keys by request data other than just the URL.
+ // Thank you! Please can you update the 1u below to 2u, or file a bug against
+ // component Background Fetch to do so.
+ ASSERT_EQ(settled_fetches.size(), 1u);
+}
+
TEST_F(BackgroundFetchDataManagerTest, Cleanup) {
// Tests that the BackgroundFetchDataManager cleans up registrations
// marked for deletion.
@@ -1202,8 +1641,12 @@ TEST_F(BackgroundFetchDataManagerTest, Cleanup) {
EXPECT_EQ(0u,
GetRegistrationUserDataByKeyPrefix(sw_id, kUserDataPrefix).size());
// Create a registration.
- CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
- ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+ CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
// We expect as many pending entries as there are requests.
EXPECT_EQ(requests.size(),
@@ -1263,13 +1706,15 @@ TEST_F(BackgroundFetchDataManagerTest, GetInitializationData) {
// Register a Background Fetch.
BackgroundFetchRegistrationId registration_id(
sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
- SkBitmap icon;
- icon.allocN32Pixels(42, 42);
- icon.eraseColor(SK_ColorGREEN);
- CreateRegistration(registration_id, requests, options, icon, &error);
- ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
- UpdateRegistrationUI(registration_id, kUpdatedTitle, &error);
- ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _));
+
+ CreateRegistration(registration_id, requests, options, CreateTestIcon(),
+ &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
+
{
std::vector<BackgroundFetchInitializationData> data =
GetInitializationData();
@@ -1281,19 +1726,14 @@ TEST_F(BackgroundFetchDataManagerTest, GetInitializationData) {
EXPECT_EQ(init.registration.developer_id, kExampleDeveloperId);
EXPECT_EQ(init.options.title, kInitialTitle);
EXPECT_EQ(init.options.download_total, 42u);
- EXPECT_EQ(init.ui_title, kUpdatedTitle);
+ EXPECT_EQ(init.ui_title, kInitialTitle);
EXPECT_EQ(init.num_requests, requests.size());
EXPECT_EQ(init.num_completed_requests, 0u);
- EXPECT_TRUE(init.active_fetch_guids.empty());
+ EXPECT_TRUE(init.active_fetch_requests.empty());
// Check icon.
ASSERT_FALSE(init.icon.drawsNothing());
- EXPECT_EQ(icon.width(), init.icon.width());
- EXPECT_EQ(icon.height(), init.icon.height());
- for (int i = 0; i < icon.width(); i++) {
- for (int j = 0; j < icon.height(); j++)
- EXPECT_EQ(init.icon.getColor(i, j), SK_ColorGREEN);
- }
+ EXPECT_NO_FATAL_FAILURE(ExpectIconProperties(init.icon, 42, SK_ColorGREEN));
}
// Mark one request as complete and start another.
@@ -1311,14 +1751,28 @@ TEST_F(BackgroundFetchDataManagerTest, GetInitializationData) {
EXPECT_EQ(data[0].num_requests, requests.size());
EXPECT_EQ(data[0].num_completed_requests, 1u);
- EXPECT_EQ(data[0].active_fetch_guids.size(), 1u);
+ ASSERT_EQ(data[0].active_fetch_requests.size(), 1u);
+
+ const auto& init_request_info = data[0].active_fetch_requests[0];
+ ASSERT_TRUE(init_request_info);
+ EXPECT_EQ(request_info->download_guid(),
+ init_request_info->download_guid());
+ EXPECT_EQ(request_info->request_index(),
+ init_request_info->request_index());
+ EXPECT_EQ(request_info->fetch_request().Serialize(),
+ init_request_info->fetch_request().Serialize());
}
// Create another registration.
BackgroundFetchRegistrationId registration_id2(
sw_id, origin(), kAlternativeDeveloperId, kAlternativeUniqueId);
- CreateRegistration(registration_id2, requests, options, SkBitmap(), &error);
- EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ {
+ EXPECT_CALL(*this, OnRegistrationCreated(registration_id2, _, _, _, _));
+
+ CreateRegistration(registration_id2, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
+
{
std::vector<BackgroundFetchInitializationData> data =
GetInitializationData();
@@ -1339,11 +1793,15 @@ TEST_F(BackgroundFetchDataManagerTest, CreateInParallel) {
std::vector<blink::mojom::BackgroundFetchError> errors(5);
+ // We expect a single successful registration to be created.
+ EXPECT_CALL(*this, OnRegistrationCreated(_, _, _, _, _));
+
const int num_parallel_creates = 5;
base::RunLoop run_loop;
base::RepeatingClosure quit_once_all_finished_closure =
base::BarrierClosure(num_parallel_creates, run_loop.QuitClosure());
+
for (int i = 0; i < num_parallel_creates; i++) {
// New |unique_id| per iteration, since each is a distinct registration.
BackgroundFetchRegistrationId registration_id(
@@ -1377,4 +1835,74 @@ TEST_F(BackgroundFetchDataManagerTest, CreateInParallel) {
EXPECT_EQ(num_parallel_creates - 1, duplicated_developer_id_count);
}
+TEST_F(BackgroundFetchDataManagerTest, StorageErrorsReported) {
+ int64_t sw_id = RegisterServiceWorker();
+ ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, sw_id);
+
+ auto requests = CreateValidRequests(origin(), 3u /* num_requests */);
+ BackgroundFetchOptions options;
+ blink::mojom::BackgroundFetchError error;
+ BackgroundFetchRegistrationId registration_id(
+ sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
+
+ {
+ base::HistogramTester histogram_tester;
+ CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ histogram_tester.ExpectBucketCount(
+ "BackgroundFetch.Storage.CreateMetadataTask", 0 /* kNone */, 1);
+ }
+
+ BackgroundFetchRegistrationId registration_id2(
+ sw_id, url::Origin::Create(GURL("https://examplebad.com")),
+ kAlternativeDeveloperId, kAlternativeUniqueId);
+
+ {
+ base::HistogramTester histogram_tester;
+ // This should fail because the Service Worker doesn't exist.
+ CreateRegistration(registration_id2, requests, options, SkBitmap(), &error);
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::STORAGE_ERROR);
+ histogram_tester.ExpectBucketCount(
+ "BackgroundFetch.Storage.CreateMetadataTask",
+ 1 /* kServiceWorkerStorageError */, 1);
+ }
+
+ scoped_refptr<BackgroundFetchRequestInfo> request_info;
+ PopNextRequest(registration_id, &request_info);
+ ASSERT_TRUE(request_info);
+ AnnotateRequestInfoWithFakeDownloadManagerData(request_info.get(),
+ true /* success */);
+ MarkRequestAsComplete(registration_id, request_info.get());
+
+ bool succeeded = false;
+ std::vector<BackgroundFetchSettledFetch> settled_fetches;
+
+ {
+ GetSettledFetchesForRegistration(
+ registration_id, base::nullopt /* request_to_match */,
+ nullptr /* cache_query_params */, false /* match_all */, &error,
+ &succeeded, &settled_fetches);
+
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+ }
+
+ // Delete an expected entry to get a CachStorageError.
+ EXPECT_TRUE(MatchCache(requests[0]));
+ DeleteFromCache(requests[0]);
+ ASSERT_FALSE(MatchCache(requests[0]));
+
+ {
+ base::HistogramTester histogram_tester;
+ GetSettledFetchesForRegistration(
+ registration_id, base::nullopt /* request_to_match */,
+ nullptr /* cache_query_params */, false /* match_all */, &error,
+ &succeeded, &settled_fetches);
+
+ ASSERT_EQ(error, blink::mojom::BackgroundFetchError::STORAGE_ERROR);
+ histogram_tester.ExpectBucketCount(
+ "BackgroundFetch.Storage.GetSettledFetchesTask",
+ 2 /* kCacheStorageError */, 1);
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/background_fetch/background_fetch_delegate_proxy.cc b/chromium/content/browser/background_fetch/background_fetch_delegate_proxy.cc
index 90f63f92b31..c8048feda17 100644
--- a/chromium/content/browser/background_fetch/background_fetch_delegate_proxy.cc
+++ b/chromium/content/browser/background_fetch/background_fetch_delegate_proxy.cc
@@ -41,6 +41,29 @@ class BackgroundFetchDelegateProxy::Core
return weak_ptr_factory_.GetWeakPtr();
}
+ void ForwardGetPermissionForOriginCallbackToIO(
+ BackgroundFetchDelegate::GetPermissionForOriginCallback callback,
+ bool has_permission) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(std::move(callback), has_permission));
+ }
+
+ void GetPermissionForOrigin(
+ const url::Origin& origin,
+ const ResourceRequestInfo::WebContentsGetter& wc_getter,
+ BackgroundFetchDelegate::GetPermissionForOriginCallback callback) {
+ if (delegate_) {
+ delegate_->GetPermissionForOrigin(
+ origin, wc_getter,
+ base::BindOnce(&Core::ForwardGetPermissionForOriginCallbackToIO,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+ } else {
+ std::move(callback).Run(false /* has_permission */);
+ }
+ }
+
void ForwardGetIconDisplaySizeCallbackToIO(
BackgroundFetchDelegate::GetIconDisplaySizeCallback callback,
const gfx::Size& display_size) {
@@ -127,7 +150,7 @@ class BackgroundFetchDelegateProxy::Core
if (fetch_request.mode == network::mojom::FetchRequestMode::kCORS ||
fetch_request.mode ==
network::mojom::FetchRequestMode::kCORSWithForcedPreflight ||
- (fetch_request.method != "GET" && fetch_request.method != "POST")) {
+ (fetch_request.method != "GET" && fetch_request.method != "HEAD")) {
headers.SetHeader("Origin", origin.Serialize());
}
@@ -143,11 +166,13 @@ class BackgroundFetchDelegateProxy::Core
delegate_->Abort(job_unique_id);
}
- void UpdateUI(const std::string& job_unique_id, const std::string& title) {
+ void UpdateUI(const std::string& job_unique_id,
+ const base::Optional<std::string>& title,
+ const base::Optional<SkBitmap>& icon) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (delegate_)
- delegate_->UpdateUI(job_unique_id, title);
+ delegate_->UpdateUI(job_unique_id, title, icon);
}
// BackgroundFetchDelegate::Client implementation:
@@ -239,8 +264,16 @@ void BackgroundFetchDelegateProxy::Core::OnDelegateShutdown() {
}
BackgroundFetchDelegateProxy::JobDetails::JobDetails(
- base::WeakPtr<Controller> controller)
- : controller(controller) {}
+ base::WeakPtr<Controller> controller,
+ std::vector<scoped_refptr<BackgroundFetchRequestInfo>>
+ active_fetch_requests)
+ : controller(controller) {
+ for (auto& request_info : active_fetch_requests) {
+ DCHECK(request_info);
+ std::string download_guid = request_info->download_guid();
+ current_request_map[std::move(download_guid)] = std::move(request_info);
+ }
+}
BackgroundFetchDelegateProxy::JobDetails::JobDetails(JobDetails&& details) =
default;
@@ -279,14 +312,28 @@ void BackgroundFetchDelegateProxy::GetIconDisplaySize(
ui_core_ptr_, std::move(callback)));
}
+void BackgroundFetchDelegateProxy::GetPermissionForOrigin(
+ const url::Origin& origin,
+ const ResourceRequestInfo::WebContentsGetter& wc_getter,
+ BackgroundFetchDelegate::GetPermissionForOriginCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&Core::GetPermissionForOrigin, ui_core_ptr_, origin,
+ wc_getter, std::move(callback)));
+}
+
void BackgroundFetchDelegateProxy::CreateDownloadJob(
base::WeakPtr<Controller> controller,
- std::unique_ptr<BackgroundFetchDescription> fetch_description) {
+ std::unique_ptr<BackgroundFetchDescription> fetch_description,
+ std::vector<scoped_refptr<BackgroundFetchRequestInfo>>
+ active_fetch_requests) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(!job_details_map_.count(fetch_description->job_unique_id));
- job_details_map_.emplace(fetch_description->job_unique_id,
- JobDetails(controller));
+ job_details_map_.emplace(
+ fetch_description->job_unique_id,
+ JobDetails(controller, std::move(active_fetch_requests)));
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::BindOnce(&Core::CreateDownloadJob, ui_core_ptr_,
@@ -313,13 +360,15 @@ void BackgroundFetchDelegateProxy::StartRequest(
job_unique_id, origin, request));
}
-void BackgroundFetchDelegateProxy::UpdateUI(const std::string& job_unique_id,
- const std::string& title) {
+void BackgroundFetchDelegateProxy::UpdateUI(
+ const std::string& job_unique_id,
+ const base::Optional<std::string>& title,
+ const base::Optional<SkBitmap>& icon) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::BindOnce(&Core::UpdateUI, ui_core_ptr_, job_unique_id, title));
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&Core::UpdateUI, ui_core_ptr_,
+ job_unique_id, title, icon));
}
void BackgroundFetchDelegateProxy::Abort(const std::string& job_unique_id) {
@@ -329,7 +378,7 @@ void BackgroundFetchDelegateProxy::Abort(const std::string& job_unique_id) {
BrowserThread::UI, FROM_HERE,
base::BindOnce(&Core::Abort, ui_core_ptr_, job_unique_id));
- job_details_map_.erase(job_details_map_.find(job_unique_id));
+ job_details_map_.erase(job_unique_id);
}
void BackgroundFetchDelegateProxy::OnJobCancelled(
@@ -367,6 +416,7 @@ void BackgroundFetchDelegateProxy::DidStartRequest(
const scoped_refptr<BackgroundFetchRequestInfo>& request_info =
job_details.current_request_map[guid];
+ DCHECK(request_info);
DCHECK_EQ(guid, request_info->download_guid());
request_info->PopulateWithResponse(std::move(response));
@@ -399,6 +449,7 @@ void BackgroundFetchDelegateProxy::OnDownloadUpdated(
if (job_details.controller) {
const scoped_refptr<BackgroundFetchRequestInfo>& request_info =
job_details.current_request_map[guid];
+ DCHECK(request_info);
DCHECK_EQ(guid, request_info->download_guid());
job_details.controller->DidUpdateRequest(request_info, bytes_downloaded);
}
@@ -420,6 +471,7 @@ void BackgroundFetchDelegateProxy::OnDownloadComplete(
const scoped_refptr<BackgroundFetchRequestInfo>& request_info =
job_details.current_request_map[guid];
+ DCHECK(request_info);
DCHECK_EQ(guid, request_info->download_guid());
request_info->SetResult(std::move(result));
diff --git a/chromium/content/browser/background_fetch/background_fetch_delegate_proxy.h b/chromium/content/browser/background_fetch/background_fetch_delegate_proxy.h
index 1084985b3be..d393db41cfc 100644
--- a/chromium/content/browser/background_fetch/background_fetch_delegate_proxy.h
+++ b/chromium/content/browser/background_fetch/background_fetch_delegate_proxy.h
@@ -14,6 +14,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
#include "content/browser/background_fetch/background_fetch_request_info.h"
#include "content/public/browser/background_fetch_delegate.h"
#include "content/public/browser/background_fetch_description.h"
@@ -65,6 +66,12 @@ class CONTENT_EXPORT BackgroundFetchDelegateProxy {
void GetIconDisplaySize(
BackgroundFetchDelegate::GetIconDisplaySizeCallback callback);
+ // Checks if the provided origin has permission to start a Background Fetch.
+ void GetPermissionForOrigin(
+ const url::Origin& origin,
+ const ResourceRequestInfo::WebContentsGetter& wc_getter,
+ BackgroundFetchDelegate::GetPermissionForOriginCallback callback);
+
// Creates a new download grouping described by |fetch_description|. Further
// downloads started by StartRequest will also use
// |fetch_description.job_unique_id| so that a notification can be updated
@@ -73,11 +80,15 @@ class CONTENT_EXPORT BackgroundFetchDelegateProxy {
// GUIDs of in progress downloads, while completed downloads are recorded in
// |fetch_description.completed_parts|. The size of the completed parts is
// recorded in |fetch_description.completed_parts_size| and total download
- // size is stored in |fetch_description.total_parts_size|. Should only be
- // called from the Controller (on the IO thread).
+ // size is stored in |fetch_description.total_parts_size|.
+ // |active_fetch_requests| contains the BackgroundFetchRequestInfos
+ // needed to correctly resume an ongoing fetch.
+ // Should only be called from the Controller (on the IO thread).
void CreateDownloadJob(
base::WeakPtr<Controller> controller,
- std::unique_ptr<BackgroundFetchDescription> fetch_description);
+ std::unique_ptr<BackgroundFetchDescription> fetch_description,
+ std::vector<scoped_refptr<BackgroundFetchRequestInfo>>
+ active_fetch_requests);
// Requests that the download manager start fetching |request|.
// Should only be called from the Controller (on the IO
@@ -87,8 +98,11 @@ class CONTENT_EXPORT BackgroundFetchDelegateProxy {
scoped_refptr<BackgroundFetchRequestInfo> request);
// Updates the representation of this registration in the user interface to
- // match the given |title|. Called from the Controller (on the IO thread).
- void UpdateUI(const std::string& job_unique_id, const std::string& title);
+ // match the given |title| or |icon|.
+ // Called from the Controller (on the IO thread).
+ void UpdateUI(const std::string& job_unique_id,
+ const base::Optional<std::string>& title,
+ const base::Optional<SkBitmap>& icon);
// Aborts in progress downloads for the given registration. Called from the
// Controller (on the IO thread) after it is aborted. May occur even if all
@@ -127,7 +141,9 @@ class CONTENT_EXPORT BackgroundFetchDelegateProxy {
base::WeakPtr<Core> ui_core_ptr_;
struct JobDetails {
- explicit JobDetails(base::WeakPtr<Controller> controller);
+ JobDetails(base::WeakPtr<Controller> controller,
+ std::vector<scoped_refptr<BackgroundFetchRequestInfo>>
+ active_fetch_requests);
JobDetails(JobDetails&& details);
~JobDetails();
diff --git a/chromium/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc b/chromium/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc
index 3b3a88a0e2a..8d142789922 100644
--- a/chromium/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc
+++ b/chromium/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc
@@ -33,6 +33,12 @@ class FakeBackgroundFetchDelegate : public BackgroundFetchDelegate {
BackgroundFetchDelegate::GetIconDisplaySizeCallback callback) override {
std::move(callback).Run(gfx::Size(kIconDisplaySize, kIconDisplaySize));
}
+ void GetPermissionForOrigin(
+ const url::Origin& origin,
+ const ResourceRequestInfo::WebContentsGetter& wc_getter,
+ GetPermissionForOriginCallback callback) override {
+ std::move(callback).Run(true /* has_permission */);
+ }
void CreateDownloadJob(
std::unique_ptr<BackgroundFetchDescription> fetch_description) override {}
void DownloadUrl(const std::string& job_unique_id,
@@ -63,15 +69,16 @@ class FakeBackgroundFetchDelegate : public BackgroundFetchDelegate {
}
void UpdateUI(const std::string& job_unique_id,
- const std::string& title) override {
- ++title_update_count_;
+ const base::Optional<std::string>& title,
+ const base::Optional<SkBitmap>& icon) override {
+ ++ui_update_count_;
}
void set_complete_downloads(bool complete_downloads) {
complete_downloads_ = complete_downloads;
}
- int title_update_count_ = 0;
+ int ui_update_count_ = 0;
private:
void CompleteDownload(const std::string& job_unique_id,
@@ -163,7 +170,8 @@ TEST_F(BackgroundFetchDelegateProxyTest, StartRequest) {
0 /* completed_parts_size */, 0 /* total_parts_size */,
std::vector<std::string>());
delegate_proxy_.CreateDownloadJob(controller.weak_ptr_factory_.GetWeakPtr(),
- std::move(fetch_description));
+ std::move(fetch_description),
+ {} /* active_fetch_requests */);
delegate_proxy_.StartRequest(kExampleUniqueId, url::Origin(), request);
base::RunLoop().RunUntilIdle();
@@ -187,7 +195,8 @@ TEST_F(BackgroundFetchDelegateProxyTest, StartRequest_NotCompleted) {
0 /* completed_parts_size */, 0 /* total_parts_size */,
std::vector<std::string>());
delegate_proxy_.CreateDownloadJob(controller.weak_ptr_factory_.GetWeakPtr(),
- std::move(fetch_description));
+ std::move(fetch_description),
+ {} /* active_fetch_requests */);
delegate_proxy_.StartRequest(kExampleUniqueId, url::Origin(), request);
base::RunLoop().RunUntilIdle();
@@ -215,7 +224,8 @@ TEST_F(BackgroundFetchDelegateProxyTest, Abort) {
0 /* completed_parts_size */, 0 /* total_parts_size */,
std::vector<std::string>());
delegate_proxy_.CreateDownloadJob(controller.weak_ptr_factory_.GetWeakPtr(),
- std::move(fetch_description1));
+ std::move(fetch_description1),
+ {} /* active_fetch_requests */);
auto fetch_description2 = std::make_unique<BackgroundFetchDescription>(
kExampleUniqueId2, "Job 2", url::Origin(), SkBitmap(),
@@ -223,7 +233,8 @@ TEST_F(BackgroundFetchDelegateProxyTest, Abort) {
0 /* completed_parts_size */, 0 /* total_parts_size */,
std::vector<std::string>());
delegate_proxy_.CreateDownloadJob(controller2.weak_ptr_factory_.GetWeakPtr(),
- std::move(fetch_description2));
+ std::move(fetch_description2),
+ {} /* active_fetch_requests */);
delegate_proxy_.StartRequest(kExampleUniqueId, url::Origin(), request);
delegate_proxy_.StartRequest(kExampleUniqueId2, url::Origin(), request2);
@@ -259,7 +270,8 @@ TEST_F(BackgroundFetchDelegateProxyTest, UpdateUI) {
std::vector<std::string>());
delegate_proxy_.CreateDownloadJob(controller.weak_ptr_factory_.GetWeakPtr(),
- std::move(fetch_description));
+ std::move(fetch_description),
+ {} /* active_fetch_requests */);
delegate_proxy_.StartRequest(kExampleUniqueId, url::Origin(), request);
base::RunLoop().RunUntilIdle();
@@ -267,9 +279,9 @@ TEST_F(BackgroundFetchDelegateProxyTest, UpdateUI) {
EXPECT_TRUE(controller.request_started_);
EXPECT_TRUE(controller.request_completed_);
- delegate_proxy_.UpdateUI(kExampleUniqueId, "Job 1 Complete!");
+ delegate_proxy_.UpdateUI(kExampleUniqueId, "Job 1 Complete!", base::nullopt);
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(delegate_.title_update_count_, 1);
+ EXPECT_EQ(delegate_.ui_update_count_, 1);
}
} // namespace content
diff --git a/chromium/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.cc b/chromium/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.cc
index 81b2e3ae092..b1ba4db1748 100644
--- a/chromium/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.cc
+++ b/chromium/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.cc
@@ -7,7 +7,6 @@
#include "base/callback.h"
#include "base/time/time.h"
#include "content/common/background_fetch/background_fetch_types.h"
-#include "content/common/service_worker/service_worker.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom.h"
namespace content {
@@ -20,13 +19,9 @@ BackgroundFetchEmbeddedWorkerTestHelper::
~BackgroundFetchEmbeddedWorkerTestHelper() = default;
void BackgroundFetchEmbeddedWorkerTestHelper::OnBackgroundFetchAbortEvent(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ const BackgroundFetchRegistration& registration,
mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback callback) {
- last_developer_id_ = developer_id;
- last_unique_id_ = unique_id;
- last_fetches_ = fetches;
+ last_registration_ = registration;
if (fail_abort_event_) {
std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::REJECTED,
@@ -41,11 +36,9 @@ void BackgroundFetchEmbeddedWorkerTestHelper::OnBackgroundFetchAbortEvent(
}
void BackgroundFetchEmbeddedWorkerTestHelper::OnBackgroundFetchClickEvent(
- const std::string& developer_id,
- mojom::BackgroundFetchState state,
+ const BackgroundFetchRegistration& registration,
mojom::ServiceWorker::DispatchBackgroundFetchClickEventCallback callback) {
- last_developer_id_ = developer_id;
- last_state_ = state;
+ last_registration_ = registration;
if (fail_click_event_) {
std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::REJECTED,
@@ -60,13 +53,9 @@ void BackgroundFetchEmbeddedWorkerTestHelper::OnBackgroundFetchClickEvent(
}
void BackgroundFetchEmbeddedWorkerTestHelper::OnBackgroundFetchFailEvent(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ const BackgroundFetchRegistration& registration,
mojom::ServiceWorker::DispatchBackgroundFetchFailEventCallback callback) {
- last_developer_id_ = developer_id;
- last_unique_id_ = unique_id;
- last_fetches_ = fetches;
+ last_registration_ = registration;
if (fail_fetch_fail_event_) {
std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::REJECTED,
@@ -80,14 +69,11 @@ void BackgroundFetchEmbeddedWorkerTestHelper::OnBackgroundFetchFailEvent(
fetch_fail_event_closure_.Run();
}
-void BackgroundFetchEmbeddedWorkerTestHelper::OnBackgroundFetchedEvent(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
- mojom::ServiceWorker::DispatchBackgroundFetchedEventCallback callback) {
- last_developer_id_ = developer_id;
- last_unique_id_ = unique_id;
- last_fetches_ = fetches;
+void BackgroundFetchEmbeddedWorkerTestHelper::OnBackgroundFetchSuccessEvent(
+ const BackgroundFetchRegistration& registration,
+ mojom::ServiceWorker::DispatchBackgroundFetchSuccessEventCallback
+ callback) {
+ last_registration_ = registration;
if (fail_fetched_event_) {
std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::REJECTED,
diff --git a/chromium/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.h b/chromium/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.h
index 312debdfb4e..9836bd9a72a 100644
--- a/chromium/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.h
+++ b/chromium/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.h
@@ -15,12 +15,6 @@
namespace content {
-struct BackgroundFetchSettledFetch;
-
-namespace mojom {
-enum class BackgroundFetchState;
-}
-
// Extension of the EmbeddedWorkerTestHelper that enables instrumentation of the
// events related to the Background Fetch API. Storage for these tests will
// always be kept in memory, as data persistence is tested elsewhere.
@@ -50,45 +44,28 @@ class BackgroundFetchEmbeddedWorkerTestHelper
fetched_event_closure_ = closure;
}
- const base::Optional<std::string>& last_developer_id() const {
- return last_developer_id_;
- }
- const base::Optional<std::string>& last_unique_id() const {
- return last_unique_id_;
- }
- const base::Optional<mojom::BackgroundFetchState>& last_state() const {
- return last_state_;
- }
- const base::Optional<std::vector<BackgroundFetchSettledFetch>> last_fetches()
- const {
- return last_fetches_;
+ const base::Optional<BackgroundFetchRegistration>& last_registration() const {
+ return last_registration_;
}
protected:
// EmbeddedWorkerTestHelper overrides:
void OnBackgroundFetchAbortEvent(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ const BackgroundFetchRegistration& registration,
mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback callback)
override;
void OnBackgroundFetchClickEvent(
- const std::string& developer_id,
- mojom::BackgroundFetchState state,
+ const BackgroundFetchRegistration& registration,
mojom::ServiceWorker::DispatchBackgroundFetchClickEventCallback callback)
override;
void OnBackgroundFetchFailEvent(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ const BackgroundFetchRegistration& registration,
mojom::ServiceWorker::DispatchBackgroundFetchFailEventCallback callback)
override;
- void OnBackgroundFetchedEvent(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
- mojom::ServiceWorker::DispatchBackgroundFetchedEventCallback callback)
- override;
+ void OnBackgroundFetchSuccessEvent(
+ const BackgroundFetchRegistration& registration,
+ mojom::ServiceWorker::DispatchBackgroundFetchSuccessEventCallback
+ callback) override;
private:
bool fail_abort_event_ = false;
@@ -101,10 +78,7 @@ class BackgroundFetchEmbeddedWorkerTestHelper
base::Closure fetch_fail_event_closure_;
base::Closure fetched_event_closure_;
- base::Optional<std::string> last_developer_id_;
- base::Optional<std::string> last_unique_id_;
- base::Optional<mojom::BackgroundFetchState> last_state_;
- base::Optional<std::vector<BackgroundFetchSettledFetch>> last_fetches_;
+ base::Optional<BackgroundFetchRegistration> last_registration_;
DISALLOW_COPY_AND_ASSIGN(BackgroundFetchEmbeddedWorkerTestHelper);
};
diff --git a/chromium/content/browser/background_fetch/background_fetch_event_dispatcher.cc b/chromium/content/browser/background_fetch/background_fetch_event_dispatcher.cc
index e80dd43eb28..caa02e975b4 100644
--- a/chromium/content/browser/background_fetch/background_fetch_event_dispatcher.cc
+++ b/chromium/content/browser/background_fetch/background_fetch_event_dispatcher.cc
@@ -6,12 +6,14 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/stringprintf.h"
#include "content/browser/background_fetch/background_fetch_registration_id.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_version.h"
+#include "content/common/background_fetch/background_fetch_types.h"
#include "content/public/browser/browser_thread.h"
namespace content {
@@ -27,8 +29,8 @@ std::string HistogramSuffixForEventType(ServiceWorkerMetrics::EventType event) {
return "ClickEvent";
case ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_FAIL:
return "FailEvent";
- case ServiceWorkerMetrics::EventType::BACKGROUND_FETCHED:
- return "FetchedEvent";
+ case ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_SUCCESS:
+ return "SuccessEvent";
default:
NOTREACHED();
return std::string();
@@ -75,103 +77,99 @@ BackgroundFetchEventDispatcher::~BackgroundFetchEventDispatcher() {
void BackgroundFetchEventDispatcher::DispatchBackgroundFetchAbortEvent(
const BackgroundFetchRegistrationId& registration_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ std::unique_ptr<BackgroundFetchRegistration> registration,
base::OnceClosure finished_closure) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
LoadServiceWorkerRegistrationForDispatch(
registration_id, ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_ABORT,
std::move(finished_closure),
- base::Bind(
+ base::AdaptCallbackForRepeating(base::BindOnce(
&BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchAbortEvent,
- registration_id.developer_id(), registration_id.unique_id(),
- fetches));
+ std::move(registration))));
}
void BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchAbortEvent(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ std::unique_ptr<BackgroundFetchRegistration> registration,
scoped_refptr<ServiceWorkerVersion> service_worker_version,
int request_id) {
DCHECK(service_worker_version);
+ DCHECK(registration);
service_worker_version->endpoint()->DispatchBackgroundFetchAbortEvent(
- developer_id, unique_id, fetches,
+ *registration,
service_worker_version->CreateSimpleEventCallback(request_id));
}
void BackgroundFetchEventDispatcher::DispatchBackgroundFetchClickEvent(
const BackgroundFetchRegistrationId& registration_id,
- mojom::BackgroundFetchState state,
+ std::unique_ptr<BackgroundFetchRegistration> registration,
base::OnceClosure finished_closure) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
LoadServiceWorkerRegistrationForDispatch(
registration_id, ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_CLICK,
std::move(finished_closure),
- base::Bind(
+ base::AdaptCallbackForRepeating(base::BindOnce(
&BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchClickEvent,
- registration_id.developer_id(), state));
+ std::move(registration))));
}
void BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchClickEvent(
- const std::string& developer_id,
- mojom::BackgroundFetchState state,
+ std::unique_ptr<BackgroundFetchRegistration> registration,
scoped_refptr<ServiceWorkerVersion> service_worker_version,
int request_id) {
DCHECK(service_worker_version);
+ DCHECK(registration);
service_worker_version->endpoint()->DispatchBackgroundFetchClickEvent(
- developer_id, state,
+ *registration,
service_worker_version->CreateSimpleEventCallback(request_id));
}
void BackgroundFetchEventDispatcher::DispatchBackgroundFetchFailEvent(
const BackgroundFetchRegistrationId& registration_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ std::unique_ptr<BackgroundFetchRegistration> registration,
base::OnceClosure finished_closure) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
LoadServiceWorkerRegistrationForDispatch(
registration_id, ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_FAIL,
std::move(finished_closure),
- base::Bind(
+ base::AdaptCallbackForRepeating(base::BindOnce(
&BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchFailEvent,
- registration_id.developer_id(), registration_id.unique_id(),
- fetches));
+ std::move(registration))));
}
void BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchFailEvent(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ std::unique_ptr<BackgroundFetchRegistration> registration,
scoped_refptr<ServiceWorkerVersion> service_worker_version,
int request_id) {
DCHECK(service_worker_version);
+ DCHECK(registration);
service_worker_version->endpoint()->DispatchBackgroundFetchFailEvent(
- developer_id, unique_id, fetches,
+ *registration,
service_worker_version->CreateSimpleEventCallback(request_id));
}
-void BackgroundFetchEventDispatcher::DispatchBackgroundFetchedEvent(
+void BackgroundFetchEventDispatcher::DispatchBackgroundFetchSuccessEvent(
const BackgroundFetchRegistrationId& registration_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ std::unique_ptr<BackgroundFetchRegistration> registration,
base::OnceClosure finished_closure) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
LoadServiceWorkerRegistrationForDispatch(
- registration_id, ServiceWorkerMetrics::EventType::BACKGROUND_FETCHED,
+ registration_id,
+ ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_SUCCESS,
std::move(finished_closure),
- base::Bind(
- &BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchedEvent,
- registration_id.developer_id(), registration_id.unique_id(),
- fetches));
+ base::AdaptCallbackForRepeating(
+ base::BindOnce(&BackgroundFetchEventDispatcher::
+ DoDispatchBackgroundFetchSuccessEvent,
+ std::move(registration))));
}
-void BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchedEvent(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+void BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchSuccessEvent(
+ std::unique_ptr<BackgroundFetchRegistration> registration,
scoped_refptr<ServiceWorkerVersion> service_worker_version,
int request_id) {
DCHECK(service_worker_version);
- service_worker_version->endpoint()->DispatchBackgroundFetchedEvent(
- developer_id, unique_id, fetches,
+ DCHECK(registration);
+ service_worker_version->endpoint()->DispatchBackgroundFetchSuccessEvent(
+ *registration,
service_worker_version->CreateSimpleEventCallback(request_id));
}
diff --git a/chromium/content/browser/background_fetch/background_fetch_event_dispatcher.h b/chromium/content/browser/background_fetch/background_fetch_event_dispatcher.h
index f5358207186..4ab631be9a7 100644
--- a/chromium/content/browser/background_fetch/background_fetch_event_dispatcher.h
+++ b/chromium/content/browser/background_fetch/background_fetch_event_dispatcher.h
@@ -18,7 +18,6 @@
namespace content {
class BackgroundFetchRegistrationId;
-struct BackgroundFetchSettledFetch;
class ServiceWorkerContextWrapper;
class ServiceWorkerRegistration;
class ServiceWorkerVersion;
@@ -45,29 +44,28 @@ class CONTENT_EXPORT BackgroundFetchEventDispatcher {
// background fetch was aborted by the user or another external event.
void DispatchBackgroundFetchAbortEvent(
const BackgroundFetchRegistrationId& registration_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ std::unique_ptr<BackgroundFetchRegistration> registration,
base::OnceClosure finished_closure);
// Dispatches the `backgroundfetchclick` event, which indicates that the user
// interface displayed for an active background fetch was activated.
void DispatchBackgroundFetchClickEvent(
const BackgroundFetchRegistrationId& registration_id,
- mojom::BackgroundFetchState state,
+ std::unique_ptr<BackgroundFetchRegistration> registration,
base::OnceClosure finished_closure);
// Dispatches the `backgroundfetchfail` event, which indicates that a
- // background fetch has finished with one or more failed fetches. The request-
- // response pairs are included.
+ // background fetch has finished with one or more failed fetches.
void DispatchBackgroundFetchFailEvent(
const BackgroundFetchRegistrationId& registration_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ std::unique_ptr<BackgroundFetchRegistration> registration,
base::OnceClosure finished_closure);
- // Dispatches the `backgroundfetched` event, which indicates that a background
- // fetch has successfully completed. The request-response pairs are included.
- void DispatchBackgroundFetchedEvent(
+ // Dispatches the `backgroundfetchsuccess` event, which indicates that a
+ // background fetch has successfully completed.
+ void DispatchBackgroundFetchSuccessEvent(
const BackgroundFetchRegistrationId& registration_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ std::unique_ptr<BackgroundFetchRegistration> registration,
base::OnceClosure finished_closure);
private:
@@ -114,26 +112,19 @@ class CONTENT_EXPORT BackgroundFetchEventDispatcher {
// Methods that actually invoke the event on an activated Service Worker.
static void DoDispatchBackgroundFetchAbortEvent(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ std::unique_ptr<BackgroundFetchRegistration> registration,
scoped_refptr<ServiceWorkerVersion> service_worker_version,
int request_id);
static void DoDispatchBackgroundFetchClickEvent(
- const std::string& developer_id,
- mojom::BackgroundFetchState state,
+ std::unique_ptr<BackgroundFetchRegistration> registration,
scoped_refptr<ServiceWorkerVersion> service_worker_version,
int request_id);
static void DoDispatchBackgroundFetchFailEvent(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ std::unique_ptr<BackgroundFetchRegistration> registration,
scoped_refptr<ServiceWorkerVersion> service_worker_version,
int request_id);
- static void DoDispatchBackgroundFetchedEvent(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ static void DoDispatchBackgroundFetchSuccessEvent(
+ std::unique_ptr<BackgroundFetchRegistration> registration,
scoped_refptr<ServiceWorkerVersion> service_worker_version,
int request_id);
diff --git a/chromium/content/browser/background_fetch/background_fetch_event_dispatcher_unittest.cc b/chromium/content/browser/background_fetch/background_fetch_event_dispatcher_unittest.cc
index dd6655ef7b2..415e48ebf61 100644
--- a/chromium/content/browser/background_fetch/background_fetch_event_dispatcher_unittest.cc
+++ b/chromium/content/browser/background_fetch/background_fetch_event_dispatcher_unittest.cc
@@ -16,6 +16,7 @@
#include "content/browser/background_fetch/background_fetch_test_base.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom.h"
namespace content {
namespace {
@@ -44,8 +45,13 @@ TEST_F(BackgroundFetchEventDispatcherTest, DispatchInvalidRegistration) {
kExampleUniqueId);
base::RunLoop run_loop;
+ auto registration = CreateBackgroundFetchRegistration(
+ invalid_registration_id.developer_id(),
+ invalid_registration_id.unique_id(),
+ blink::mojom::BackgroundFetchState::FAILURE,
+ blink::mojom::BackgroundFetchFailureReason::QUOTA_EXCEEDED);
event_dispatcher_.DispatchBackgroundFetchAbortEvent(
- invalid_registration_id, {}, run_loop.QuitClosure());
+ invalid_registration_id, std::move(registration), run_loop.QuitClosure());
run_loop.Run();
@@ -71,19 +77,23 @@ TEST_F(BackgroundFetchEventDispatcherTest, DispatchAbortEvent) {
{
base::RunLoop run_loop;
+ auto registration = CreateBackgroundFetchRegistration(
+ kExampleDeveloperId, kExampleUniqueId,
+ blink::mojom::BackgroundFetchState::FAILURE,
+ blink::mojom::BackgroundFetchFailureReason::CANCELLED_FROM_UI);
event_dispatcher_.DispatchBackgroundFetchAbortEvent(
- registration_id, fetches, run_loop.QuitClosure());
+ registration_id, std::move(registration), run_loop.QuitClosure());
run_loop.Run();
}
- ASSERT_TRUE(embedded_worker_test_helper()->last_developer_id().has_value());
+ ASSERT_TRUE(embedded_worker_test_helper()->last_registration().has_value());
EXPECT_EQ(kExampleDeveloperId,
- embedded_worker_test_helper()->last_developer_id().value());
- ASSERT_TRUE(embedded_worker_test_helper()->last_unique_id().has_value());
+ embedded_worker_test_helper()->last_registration()->developer_id);
EXPECT_EQ(kExampleUniqueId,
- embedded_worker_test_helper()->last_unique_id().value());
- ASSERT_TRUE(embedded_worker_test_helper()->last_fetches().has_value());
+ embedded_worker_test_helper()->last_registration()->unique_id);
+ EXPECT_EQ(blink::mojom::BackgroundFetchFailureReason::CANCELLED_FROM_UI,
+ embedded_worker_test_helper()->last_registration()->failure_reason);
histogram_tester_.ExpectUniqueSample(
"BackgroundFetch.EventDispatchResult.AbortEvent",
@@ -97,19 +107,22 @@ TEST_F(BackgroundFetchEventDispatcherTest, DispatchAbortEvent) {
{
base::RunLoop run_loop;
- event_dispatcher_.DispatchBackgroundFetchAbortEvent(
- second_registration_id, fetches, run_loop.QuitClosure());
+ auto registration = CreateBackgroundFetchRegistration(
+ kExampleDeveloperId2, kExampleUniqueId2,
+ blink::mojom::BackgroundFetchState::FAILURE,
+ blink::mojom::BackgroundFetchFailureReason::QUOTA_EXCEEDED);
+ event_dispatcher_.DispatchBackgroundFetchAbortEvent(second_registration_id,
+ std::move(registration),
+ run_loop.QuitClosure());
run_loop.Run();
}
- ASSERT_TRUE(embedded_worker_test_helper()->last_developer_id().has_value());
+ ASSERT_TRUE(embedded_worker_test_helper()->last_registration().has_value());
EXPECT_EQ(kExampleDeveloperId2,
- embedded_worker_test_helper()->last_developer_id().value());
- ASSERT_TRUE(embedded_worker_test_helper()->last_unique_id().has_value());
+ embedded_worker_test_helper()->last_registration()->developer_id);
EXPECT_EQ(kExampleUniqueId2,
- embedded_worker_test_helper()->last_unique_id().value());
- ASSERT_TRUE(embedded_worker_test_helper()->last_fetches().has_value());
+ embedded_worker_test_helper()->last_registration()->unique_id);
histogram_tester_.ExpectBucketCount(
"BackgroundFetch.EventDispatchResult.AbortEvent",
@@ -133,20 +146,21 @@ TEST_F(BackgroundFetchEventDispatcherTest, DispatchClickEvent) {
{
base::RunLoop run_loop;
+ auto registration = CreateBackgroundFetchRegistration(
+ kExampleDeveloperId, kExampleUniqueId,
+ blink::mojom::BackgroundFetchState::PENDING,
+ blink::mojom::BackgroundFetchFailureReason::NONE);
event_dispatcher_.DispatchBackgroundFetchClickEvent(
- registration_id, mojom::BackgroundFetchState::PENDING,
- run_loop.QuitClosure());
+ registration_id, std::move(registration), run_loop.QuitClosure());
run_loop.Run();
}
- ASSERT_TRUE(embedded_worker_test_helper()->last_developer_id().has_value());
+ ASSERT_TRUE(embedded_worker_test_helper()->last_registration().has_value());
EXPECT_EQ(kExampleDeveloperId,
- embedded_worker_test_helper()->last_developer_id().value());
-
- ASSERT_TRUE(embedded_worker_test_helper()->last_state().has_value());
- EXPECT_EQ(mojom::BackgroundFetchState::PENDING,
- embedded_worker_test_helper()->last_state());
+ embedded_worker_test_helper()->last_registration()->developer_id);
+ EXPECT_EQ(blink::mojom::BackgroundFetchState::PENDING,
+ embedded_worker_test_helper()->last_registration()->state);
histogram_tester_.ExpectUniqueSample(
"BackgroundFetch.EventDispatchResult.ClickEvent",
@@ -160,20 +174,22 @@ TEST_F(BackgroundFetchEventDispatcherTest, DispatchClickEvent) {
{
base::RunLoop run_loop;
- event_dispatcher_.DispatchBackgroundFetchClickEvent(
- second_registration_id, mojom::BackgroundFetchState::SUCCEEDED,
- run_loop.QuitClosure());
+ auto registration = CreateBackgroundFetchRegistration(
+ kExampleDeveloperId2, kExampleUniqueId2,
+ blink::mojom::BackgroundFetchState::FAILURE,
+ blink::mojom::BackgroundFetchFailureReason::QUOTA_EXCEEDED);
+ event_dispatcher_.DispatchBackgroundFetchClickEvent(second_registration_id,
+ std::move(registration),
+ run_loop.QuitClosure());
run_loop.Run();
}
- ASSERT_TRUE(embedded_worker_test_helper()->last_developer_id().has_value());
+ ASSERT_TRUE(embedded_worker_test_helper()->last_registration().has_value());
EXPECT_EQ(kExampleDeveloperId2,
- embedded_worker_test_helper()->last_developer_id().value());
-
- ASSERT_TRUE(embedded_worker_test_helper()->last_state().has_value());
- EXPECT_EQ(mojom::BackgroundFetchState::SUCCEEDED,
- embedded_worker_test_helper()->last_state());
+ embedded_worker_test_helper()->last_registration()->developer_id);
+ EXPECT_EQ(blink::mojom::BackgroundFetchState::FAILURE,
+ embedded_worker_test_helper()->last_registration()->state);
histogram_tester_.ExpectBucketCount(
"BackgroundFetch.EventDispatchResult.ClickEvent",
@@ -195,31 +211,26 @@ TEST_F(BackgroundFetchEventDispatcherTest, DispatchFailEvent) {
origin(), kExampleDeveloperId,
kExampleUniqueId);
- std::vector<BackgroundFetchSettledFetch> fetches;
- fetches.push_back(BackgroundFetchSettledFetch());
-
{
base::RunLoop run_loop;
- event_dispatcher_.DispatchBackgroundFetchFailEvent(registration_id, fetches,
- run_loop.QuitClosure());
+ auto registration = CreateBackgroundFetchRegistration(
+ kExampleDeveloperId, kExampleUniqueId,
+ blink::mojom::BackgroundFetchState::FAILURE,
+ blink::mojom::BackgroundFetchFailureReason::QUOTA_EXCEEDED);
+ event_dispatcher_.DispatchBackgroundFetchFailEvent(
+ registration_id, std::move(registration), run_loop.QuitClosure());
run_loop.Run();
}
- ASSERT_TRUE(embedded_worker_test_helper()->last_developer_id().has_value());
+ ASSERT_TRUE(embedded_worker_test_helper()->last_registration().has_value());
EXPECT_EQ(kExampleDeveloperId,
- embedded_worker_test_helper()->last_developer_id().value());
-
- ASSERT_TRUE(embedded_worker_test_helper()->last_fetches().has_value());
- EXPECT_EQ(fetches.size(),
- embedded_worker_test_helper()->last_fetches()->size());
+ embedded_worker_test_helper()->last_registration()->developer_id);
histogram_tester_.ExpectUniqueSample(
"BackgroundFetch.EventDispatchResult.FailEvent",
BackgroundFetchEventDispatcher::DISPATCH_RESULT_SUCCESS, 1);
- fetches.push_back(BackgroundFetchSettledFetch());
-
embedded_worker_test_helper()->set_fail_fetch_fail_event(true);
BackgroundFetchRegistrationId second_registration_id(
@@ -228,19 +239,19 @@ TEST_F(BackgroundFetchEventDispatcherTest, DispatchFailEvent) {
{
base::RunLoop run_loop;
- event_dispatcher_.DispatchBackgroundFetchFailEvent(
- second_registration_id, fetches, run_loop.QuitClosure());
-
+ auto registration = CreateBackgroundFetchRegistration(
+ kExampleDeveloperId2, kExampleUniqueId2,
+ blink::mojom::BackgroundFetchState::FAILURE,
+ blink::mojom::BackgroundFetchFailureReason::QUOTA_EXCEEDED);
+ event_dispatcher_.DispatchBackgroundFetchFailEvent(second_registration_id,
+ std::move(registration),
+ run_loop.QuitClosure());
run_loop.Run();
}
- ASSERT_TRUE(embedded_worker_test_helper()->last_developer_id().has_value());
+ ASSERT_TRUE(embedded_worker_test_helper()->last_registration().has_value());
EXPECT_EQ(kExampleDeveloperId2,
- embedded_worker_test_helper()->last_developer_id().value());
-
- ASSERT_TRUE(embedded_worker_test_helper()->last_fetches().has_value());
- EXPECT_EQ(fetches.size(),
- embedded_worker_test_helper()->last_fetches()->size());
+ embedded_worker_test_helper()->last_registration()->developer_id);
histogram_tester_.ExpectBucketCount(
"BackgroundFetch.EventDispatchResult.FailEvent",
@@ -253,7 +264,7 @@ TEST_F(BackgroundFetchEventDispatcherTest, DispatchFailEvent) {
blink::ServiceWorkerStatusCode::kErrorEventWaitUntilRejected, 1);
}
-TEST_F(BackgroundFetchEventDispatcherTest, DispatchFetchedEvent) {
+TEST_F(BackgroundFetchEventDispatcherTest, DispatchFetchSuccessEvent) {
int64_t service_worker_registration_id = RegisterServiceWorker();
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId,
service_worker_registration_id);
@@ -262,35 +273,29 @@ TEST_F(BackgroundFetchEventDispatcherTest, DispatchFetchedEvent) {
origin(), kExampleDeveloperId,
kExampleUniqueId);
- std::vector<BackgroundFetchSettledFetch> fetches;
- fetches.push_back(BackgroundFetchSettledFetch());
-
{
base::RunLoop run_loop;
- event_dispatcher_.DispatchBackgroundFetchedEvent(registration_id, fetches,
- run_loop.QuitClosure());
+ auto registration = CreateBackgroundFetchRegistration(
+ kExampleDeveloperId, kExampleUniqueId,
+ blink::mojom::BackgroundFetchState::SUCCESS,
+ blink::mojom::BackgroundFetchFailureReason::NONE);
+ event_dispatcher_.DispatchBackgroundFetchSuccessEvent(
+ registration_id, std::move(registration), run_loop.QuitClosure());
run_loop.Run();
}
- ASSERT_TRUE(embedded_worker_test_helper()->last_developer_id().has_value());
+ ASSERT_TRUE(embedded_worker_test_helper()->last_registration().has_value());
EXPECT_EQ(kExampleDeveloperId,
- embedded_worker_test_helper()->last_developer_id().value());
+ embedded_worker_test_helper()->last_registration()->developer_id);
- ASSERT_TRUE(embedded_worker_test_helper()->last_unique_id().has_value());
EXPECT_EQ(kExampleUniqueId,
- embedded_worker_test_helper()->last_unique_id().value());
-
- ASSERT_TRUE(embedded_worker_test_helper()->last_fetches().has_value());
- EXPECT_EQ(fetches.size(),
- embedded_worker_test_helper()->last_fetches()->size());
+ embedded_worker_test_helper()->last_registration()->unique_id);
histogram_tester_.ExpectUniqueSample(
- "BackgroundFetch.EventDispatchResult.FetchedEvent",
+ "BackgroundFetch.EventDispatchResult.SuccessEvent",
BackgroundFetchEventDispatcher::DISPATCH_RESULT_SUCCESS, 1);
- fetches.push_back(BackgroundFetchSettledFetch());
-
embedded_worker_test_helper()->set_fail_fetched_event(true);
BackgroundFetchRegistrationId second_registration_id(
@@ -299,32 +304,31 @@ TEST_F(BackgroundFetchEventDispatcherTest, DispatchFetchedEvent) {
{
base::RunLoop run_loop;
- event_dispatcher_.DispatchBackgroundFetchedEvent(
- second_registration_id, fetches, run_loop.QuitClosure());
+ auto registration = CreateBackgroundFetchRegistration(
+ kExampleDeveloperId2, kExampleUniqueId2,
+ blink::mojom::BackgroundFetchState::SUCCESS,
+ blink::mojom::BackgroundFetchFailureReason::NONE);
+ event_dispatcher_.DispatchBackgroundFetchSuccessEvent(
+ second_registration_id, std::move(registration),
+ run_loop.QuitClosure());
run_loop.Run();
}
- ASSERT_TRUE(embedded_worker_test_helper()->last_developer_id().has_value());
+ ASSERT_TRUE(embedded_worker_test_helper()->last_registration().has_value());
EXPECT_EQ(kExampleDeveloperId2,
- embedded_worker_test_helper()->last_developer_id().value());
-
- ASSERT_TRUE(embedded_worker_test_helper()->last_unique_id().has_value());
+ embedded_worker_test_helper()->last_registration()->developer_id);
EXPECT_EQ(kExampleUniqueId2,
- embedded_worker_test_helper()->last_unique_id().value());
-
- ASSERT_TRUE(embedded_worker_test_helper()->last_fetches().has_value());
- EXPECT_EQ(fetches.size(),
- embedded_worker_test_helper()->last_fetches()->size());
+ embedded_worker_test_helper()->last_registration()->unique_id);
histogram_tester_.ExpectBucketCount(
- "BackgroundFetch.EventDispatchResult.FetchedEvent",
+ "BackgroundFetch.EventDispatchResult.SuccessEvent",
BackgroundFetchEventDispatcher::DISPATCH_RESULT_SUCCESS, 1);
histogram_tester_.ExpectBucketCount(
- "BackgroundFetch.EventDispatchResult.FetchedEvent",
+ "BackgroundFetch.EventDispatchResult.SuccessEvent",
BackgroundFetchEventDispatcher::DISPATCH_RESULT_CANNOT_DISPATCH_EVENT, 1);
histogram_tester_.ExpectUniqueSample(
- "BackgroundFetch.EventDispatchFailure.Dispatch.FetchedEvent",
+ "BackgroundFetch.EventDispatchFailure.Dispatch.SuccessEvent",
blink::ServiceWorkerStatusCode::kErrorEventWaitUntilRejected, 1);
}
diff --git a/chromium/content/browser/background_fetch/background_fetch_job_controller.cc b/chromium/content/browser/background_fetch/background_fetch_job_controller.cc
index 2b9a7e6681a..a2e82ba7bdd 100644
--- a/chromium/content/browser/background_fetch/background_fetch_job_controller.cc
+++ b/chromium/content/browser/background_fetch/background_fetch_job_controller.cc
@@ -3,29 +3,29 @@
// found in the LICENSE file.
#include "content/browser/background_fetch/background_fetch_job_controller.h"
+#include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom.h"
#include <utility>
-#include "content/browser/background_fetch/background_fetch_request_manager.h"
#include "content/public/browser/browser_thread.h"
namespace content {
BackgroundFetchJobController::BackgroundFetchJobController(
BackgroundFetchDelegateProxy* delegate_proxy,
+ BackgroundFetchScheduler* scheduler,
const BackgroundFetchRegistrationId& registration_id,
const BackgroundFetchOptions& options,
const SkBitmap& icon,
uint64_t bytes_downloaded,
- BackgroundFetchRequestManager* request_manager,
ProgressCallback progress_callback,
BackgroundFetchScheduler::FinishedCallback finished_callback)
- : BackgroundFetchScheduler::Controller(registration_id,
+ : BackgroundFetchScheduler::Controller(scheduler,
+ registration_id,
std::move(finished_callback)),
options_(options),
icon_(icon),
complete_requests_downloaded_bytes_cache_(bytes_downloaded),
- request_manager_(request_manager),
delegate_proxy_(delegate_proxy),
progress_callback_(std::move(progress_callback)),
weak_ptr_factory_(this) {
@@ -35,7 +35,8 @@ BackgroundFetchJobController::BackgroundFetchJobController(
void BackgroundFetchJobController::InitializeRequestStatus(
int completed_downloads,
int total_downloads,
- const std::vector<std::string>& outstanding_guids,
+ std::vector<scoped_refptr<BackgroundFetchRequestInfo>>
+ active_fetch_requests,
const std::string& ui_title) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -47,16 +48,21 @@ void BackgroundFetchJobController::InitializeRequestStatus(
total_downloads_ = total_downloads;
// TODO(nator): Update this when we support uploads.
- int total_downloads_size = options_.download_total;
+ total_downloads_size_ = options_.download_total;
+
+ std::vector<std::string> active_guids;
+ active_guids.reserve(active_fetch_requests.size());
+ for (const auto& request_info : active_fetch_requests)
+ active_guids.push_back(request_info->download_guid());
auto fetch_description = std::make_unique<BackgroundFetchDescription>(
registration_id().unique_id(), ui_title, registration_id().origin(),
icon_, completed_downloads, total_downloads,
- complete_requests_downloaded_bytes_cache_, total_downloads_size,
- outstanding_guids);
+ complete_requests_downloaded_bytes_cache_, total_downloads_size_,
+ std::move(active_guids));
- delegate_proxy_->CreateDownloadJob(GetWeakPtr(),
- std::move(fetch_description));
+ delegate_proxy_->CreateDownloadJob(GetWeakPtr(), std::move(fetch_description),
+ std::move(active_fetch_requests));
}
BackgroundFetchJobController::~BackgroundFetchJobController() {
@@ -68,12 +74,15 @@ bool BackgroundFetchJobController::HasMoreRequests() {
}
void BackgroundFetchJobController::StartRequest(
- scoped_refptr<BackgroundFetchRequestInfo> request) {
+ scoped_refptr<BackgroundFetchRequestInfo> request,
+ RequestFinishedCallback request_finished_callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_LT(completed_downloads_, total_downloads_);
+ DCHECK(request_finished_callback);
DCHECK(request);
- active_request_download_bytes_[request->download_guid()] = 0;
+ active_request_downloaded_bytes_ = 0;
+ active_request_finished_callback_ = std::move(request_finished_callback);
delegate_proxy_->StartRequest(registration_id().unique_id(),
registration_id().origin(), request);
@@ -93,11 +102,10 @@ void BackgroundFetchJobController::DidUpdateRequest(
uint64_t bytes_downloaded) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- const std::string& download_guid = request->download_guid();
- if (active_request_download_bytes_[download_guid] == bytes_downloaded)
+ if (active_request_downloaded_bytes_ == bytes_downloaded)
return;
- active_request_download_bytes_[download_guid] = bytes_downloaded;
+ active_request_downloaded_bytes_ = bytes_downloaded;
progress_callback_.Run(registration_id().unique_id(), options_.download_total,
complete_requests_downloaded_bytes_cache_ +
@@ -108,43 +116,75 @@ void BackgroundFetchJobController::DidCompleteRequest(
const scoped_refptr<BackgroundFetchRequestInfo>& request) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- active_request_download_bytes_.erase(request->download_guid());
+ // It's possible for the DidCompleteRequest() callback to have been in-flight
+ // while this Job Controller was being aborted, in which case the
+ // |active_request_finished_callback_| will have been reset.
+ if (!active_request_finished_callback_)
+ return;
+
+ active_request_downloaded_bytes_ = 0;
+
complete_requests_downloaded_bytes_cache_ += request->GetFileSize();
++completed_downloads_;
- request_manager_->MarkRequestAsComplete(registration_id(), request.get());
+ std::move(active_request_finished_callback_).Run(request);
}
-void BackgroundFetchJobController::UpdateUI(const std::string& title) {
+void BackgroundFetchJobController::UpdateUI(
+ const base::Optional<std::string>& title,
+ const base::Optional<SkBitmap>& icon) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- delegate_proxy_->UpdateUI(registration_id().unique_id(), title);
+ delegate_proxy_->UpdateUI(registration_id().unique_id(), title, icon);
+}
+
+std::unique_ptr<BackgroundFetchRegistration>
+BackgroundFetchJobController::NewRegistration(
+ blink::mojom::BackgroundFetchState state) const {
+ return std::make_unique<BackgroundFetchRegistration>(
+ registration_id().developer_id(), registration_id().unique_id(),
+ 0 /* upload_total */, 0 /* uploaded */, total_downloads_size_,
+ complete_requests_downloaded_bytes_cache_, state, MojoFailureReason());
}
uint64_t BackgroundFetchJobController::GetInProgressDownloadedBytes() {
- uint64_t sum = 0;
- for (const auto& entry : active_request_download_bytes_)
- sum += entry.second;
- return sum;
+ return active_request_downloaded_bytes_;
+}
+
+// TODO(crbug.com/876691): Get rid of BackgroundFetchReasonToAbort and remove
+// this method.
+blink::mojom::BackgroundFetchFailureReason
+BackgroundFetchJobController::MojoFailureReason() const {
+ switch (reason_to_abort_) {
+ case BackgroundFetchReasonToAbort::NONE:
+ return blink::mojom::BackgroundFetchFailureReason::NONE;
+ case BackgroundFetchReasonToAbort::CANCELLED_FROM_UI:
+ return blink::mojom::BackgroundFetchFailureReason::CANCELLED_FROM_UI;
+ case BackgroundFetchReasonToAbort::ABORTED_BY_DEVELOPER:
+ return blink::mojom::BackgroundFetchFailureReason::CANCELLED_BY_DEVELOPER;
+ case BackgroundFetchReasonToAbort::TOTAL_DOWNLOAD_SIZE_EXCEEDED:
+ return blink::mojom::BackgroundFetchFailureReason::
+ TOTAL_DOWNLOAD_SIZE_EXCEEDED;
+ case BackgroundFetchReasonToAbort::SERVICE_WORKER_UNAVAILABLE:
+ return blink::mojom::BackgroundFetchFailureReason::
+ SERVICE_WORKER_UNAVAILABLE;
+ case BackgroundFetchReasonToAbort::QUOTA_EXCEEDED:
+ return blink::mojom::BackgroundFetchFailureReason::QUOTA_EXCEEDED;
+ }
+ NOTREACHED();
}
void BackgroundFetchJobController::Abort(
BackgroundFetchReasonToAbort reason_to_abort) {
+ reason_to_abort_ = reason_to_abort;
+
+ // Stop propagating any in-flight events to the scheduler.
+ active_request_finished_callback_.Reset();
+
+ // Cancel any in-flight downloads and UI through the BGFetchDelegate.
delegate_proxy_->Abort(registration_id().unique_id());
- std::vector<std::string> aborted_guids;
- for (const auto& pair : active_request_download_bytes_)
- aborted_guids.push_back(pair.first);
- request_manager_->OnJobAborted(registration_id(), std::move(aborted_guids));
- if (reason_to_abort != BackgroundFetchReasonToAbort::ABORTED_BY_DEVELOPER) {
- // Don't call Finish() here, so that we don't mark data for deletion while
- // there are active fetches.
- // Once the controller finishes processing, this function will be called
- // again. (BackgroundFetchScheduler's finished_callback_ will call
- // BackgroundFetchJobController::Abort() with |cancel_download| set to
- // true.)
- Finish(reason_to_abort);
- }
+ Finish(reason_to_abort);
}
} // namespace content
diff --git a/chromium/content/browser/background_fetch/background_fetch_job_controller.h b/chromium/content/browser/background_fetch/background_fetch_job_controller.h
index 780791dda8b..7bc8b2fbf9e 100644
--- a/chromium/content/browser/background_fetch/background_fetch_job_controller.h
+++ b/chromium/content/browser/background_fetch/background_fetch_job_controller.h
@@ -12,7 +12,9 @@
#include "base/callback.h"
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
#include "content/browser/background_fetch/background_fetch_delegate_proxy.h"
#include "content/browser/background_fetch/background_fetch_registration_id.h"
#include "content/browser/background_fetch/background_fetch_request_info.h"
@@ -24,8 +26,6 @@
namespace content {
-class BackgroundFetchRequestManager;
-
// The JobController will be responsible for coordinating communication with the
// DownloadManager. It will get requests from the RequestManager and dispatch
// them to the DownloadService. It lives entirely on the IO thread.
@@ -46,13 +46,14 @@ class CONTENT_EXPORT BackgroundFetchJobController final
base::RepeatingCallback<void(const std::string& /* unique_id */,
uint64_t /* download_total */,
uint64_t /* downloaded */)>;
+
BackgroundFetchJobController(
BackgroundFetchDelegateProxy* delegate_proxy,
+ BackgroundFetchScheduler* scheduler,
const BackgroundFetchRegistrationId& registration_id,
const BackgroundFetchOptions& options,
const SkBitmap& icon,
uint64_t bytes_downloaded,
- BackgroundFetchRequestManager* request_manager,
ProgressCallback progress_callback,
BackgroundFetchScheduler::FinishedCallback finished_callback);
~BackgroundFetchJobController() override;
@@ -63,19 +64,35 @@ class CONTENT_EXPORT BackgroundFetchJobController final
void InitializeRequestStatus(
int completed_downloads,
int total_downloads,
- const std::vector<std::string>& outstanding_guids,
+ std::vector<scoped_refptr<BackgroundFetchRequestInfo>>
+ active_fetch_requests,
const std::string& ui_title);
// Gets the number of bytes downloaded for jobs that are currently running.
uint64_t GetInProgressDownloadedBytes();
- // Updates the UI (currently only job title) that's shown to the user as part
- // of a notification for instance.
- void UpdateUI(const std::string& title);
+ // Updates the UI that's shown to the user as part of a notification for
+ // instance.
+ void UpdateUI(const base::Optional<std::string>& title,
+ const base::Optional<SkBitmap>& icon);
+
+ // Returns a unique_ptr to a BackgroundFetchRegistration object
+ // created with member fields.
+ std::unique_ptr<BackgroundFetchRegistration> NewRegistration(
+ blink::mojom::BackgroundFetchState state) const;
// Returns the options with which this job is fetching data.
const BackgroundFetchOptions& options() const { return options_; }
+ // Returns total downloaded bytes.
+ int downloaded() const { return complete_requests_downloaded_bytes_cache_; }
+
+ // Returns total size of downloads, as indicated by the developer.
+ int download_total() const { return total_downloads_size_; }
+
+ // Returns the number of requests that comprise the whole job.
+ int total_downloads() const { return total_downloads_; }
+
base::WeakPtr<BackgroundFetchJobController> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
@@ -91,10 +108,15 @@ class CONTENT_EXPORT BackgroundFetchJobController final
// BackgroundFetchScheduler::Controller implementation:
bool HasMoreRequests() override;
- void StartRequest(scoped_refptr<BackgroundFetchRequestInfo> request) override;
+ void StartRequest(scoped_refptr<BackgroundFetchRequestInfo> request,
+ RequestFinishedCallback request_finished_callback) override;
void Abort(BackgroundFetchReasonToAbort reason_to_abort) override;
private:
+ // Returns reason_to_abort_ as blink::mojom::BackgroundFetchFailureReason.
+ // TODO(crbug.com/876691): Get rid of BackgroundFetchReasonToAbort and remove
+ // this converter.
+ blink::mojom::BackgroundFetchFailureReason MojoFailureReason() const;
// Options for the represented background fetch registration.
BackgroundFetchOptions options_;
@@ -102,16 +124,18 @@ class CONTENT_EXPORT BackgroundFetchJobController final
// Icon for the represented background fetch registration.
SkBitmap icon_;
- // Map from in-progress |download_guid|s to number of bytes downloaded.
- base::flat_map<std::string, uint64_t> active_request_download_bytes_;
+ // Number of bytes downloaded for the active request.
+ uint64_t active_request_downloaded_bytes_ = 0;
+
+ // Finished callback to invoke when the active request has finished.
+ RequestFinishedCallback active_request_finished_callback_;
// Cache of downloaded byte count stored by the DataManager, to enable
// delivering progress events without having to read from the database.
uint64_t complete_requests_downloaded_bytes_cache_;
- // The RequestManager's lifetime is controlled by the BackgroundFetchContext
- // and will be kept alive until after the JobController is destroyed.
- BackgroundFetchRequestManager* request_manager_;
+ // Total downloads size, as indicated by the developer.
+ int total_downloads_size_ = 0;
// Proxy for interacting with the BackgroundFetchDelegate across thread
// boundaries. It is owned by the BackgroundFetchContext.
@@ -126,6 +150,10 @@ class CONTENT_EXPORT BackgroundFetchJobController final
// Number of the requests that have been completed so far.
int completed_downloads_ = 0;
+ // The reason background fetch was aborted.
+ BackgroundFetchReasonToAbort reason_to_abort_ =
+ BackgroundFetchReasonToAbort::NONE;
+
base::WeakPtrFactory<BackgroundFetchJobController> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(BackgroundFetchJobController);
diff --git a/chromium/content/browser/background_fetch/background_fetch_job_controller_unittest.cc b/chromium/content/browser/background_fetch/background_fetch_job_controller_unittest.cc
index 423fc1eb36d..b231b85f93f 100644
--- a/chromium/content/browser/background_fetch/background_fetch_job_controller_unittest.cc
+++ b/chromium/content/browser/background_fetch/background_fetch_job_controller_unittest.cc
@@ -20,6 +20,7 @@
#include "content/browser/background_fetch/background_fetch_context.h"
#include "content/browser/background_fetch/background_fetch_data_manager.h"
#include "content/browser/background_fetch/background_fetch_registration_id.h"
+#include "content/browser/background_fetch/background_fetch_scheduler.h"
#include "content/browser/background_fetch/background_fetch_test_base.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/storage_partition_impl.h"
@@ -40,63 +41,41 @@ const char kExampleResponseData[] = "My response data";
enum class JobCompletionStatus { kRunning, kCompleted, kAborted };
-class FakeBackgroundFetchRequestManager : public BackgroundFetchRequestManager {
- public:
- void AddDownloadJob(const BackgroundFetchRegistrationId& registration_id,
- const std::set<std::string>& download_guids) {
- DCHECK(!registration_status_map_.count(registration_id.unique_id()));
- registration_status_map_.emplace(registration_id.unique_id(),
- RegistrationState(download_guids));
- }
-
- // BackgroundFetchRequestManager implementation:
- void MarkRequestAsComplete(
- const BackgroundFetchRegistrationId& registration_id,
- scoped_refptr<BackgroundFetchRequestInfo> request) override {
- DCHECK(registration_status_map_.count(registration_id.unique_id()));
- auto& state = registration_status_map_[registration_id.unique_id()];
-
- DCHECK_EQ(state.status, JobCompletionStatus::kRunning);
- DCHECK(state.uncompleted_downloads.count(request->download_guid()));
- state.uncompleted_downloads.erase(request->download_guid());
-
- if (state.uncompleted_downloads.size() == 0) {
- state.status = JobCompletionStatus::kCompleted;
- }
- }
+} // namespace
- void OnJobAborted(const BackgroundFetchRegistrationId& registration_id,
- std::vector<std::string> aborted_guids) override {
- DCHECK(registration_status_map_.count(registration_id.unique_id()));
- auto& state = registration_status_map_[registration_id.unique_id()];
- DCHECK_EQ(state.status, JobCompletionStatus::kRunning);
- state.status = JobCompletionStatus::kAborted;
- }
+class BackgroundFetchJobControllerTest : public BackgroundFetchTestBase {
+ public:
+ BackgroundFetchJobControllerTest() = default;
+ ~BackgroundFetchJobControllerTest() override = default;
+ // Returns the status for the active job for |registration_id|. The
+ // registration should only ever exist in |finished_requests_| in case the
+ // request was aborted, given the absence of a scheduler.
JobCompletionStatus GetCompletionStatus(
const BackgroundFetchRegistrationId& registration_id) {
- DCHECK(registration_status_map_.count(registration_id.unique_id()));
- return registration_status_map_[registration_id.unique_id()].status;
- }
+ if (finished_requests_.count(registration_id)) {
+ DCHECK_NE(finished_requests_[registration_id],
+ BackgroundFetchReasonToAbort::NONE);
- struct RegistrationState {
- RegistrationState() = default;
- explicit RegistrationState(const std::set<std::string>& downloads)
- : uncompleted_downloads(downloads) {}
- JobCompletionStatus status = JobCompletionStatus::kRunning;
- std::set<std::string> uncompleted_downloads;
- };
+ return JobCompletionStatus::kAborted;
+ }
- std::map<std::string, RegistrationState> registration_status_map_;
-};
+ DCHECK(pending_requests_counts_.count(registration_id));
+ if (!pending_requests_counts_[registration_id])
+ return JobCompletionStatus::kCompleted;
-} // namespace
+ return JobCompletionStatus::kRunning;
+ }
-class BackgroundFetchJobControllerTest : public BackgroundFetchTestBase {
- public:
- BackgroundFetchJobControllerTest() = default;
+ // To be called when a request for |registration_id| has finished.
+ void OnRequestFinished(
+ const BackgroundFetchRegistrationId& registration_id,
+ scoped_refptr<content::BackgroundFetchRequestInfo> request_info) {
+ DCHECK(pending_requests_counts_.count(registration_id));
- ~BackgroundFetchJobControllerTest() override = default;
+ EXPECT_GE(pending_requests_counts_[registration_id], 1);
+ pending_requests_counts_[registration_id]--;
+ }
// Creates a new Background Fetch registration, whose id will be stored in the
// |*registration_id|, and registers it with the DataManager for the included
@@ -116,7 +95,6 @@ class BackgroundFetchJobControllerTest : public BackgroundFetchTestBase {
base::GenerateGUID());
std::vector<scoped_refptr<BackgroundFetchRequestInfo>> request_infos;
- std::set<std::string> uncompleted_downloads_guids;
int request_counter = 0;
for (const auto& pair : request_data) {
ServiceWorkerFetchRequest fetch_request(
@@ -126,11 +104,9 @@ class BackgroundFetchJobControllerTest : public BackgroundFetchTestBase {
request_counter++, fetch_request);
request->InitializeDownloadGuid();
request_infos.push_back(request);
- uncompleted_downloads_guids.insert(request->download_guid());
}
- request_manager_.AddDownloadJob(*registration_id,
- uncompleted_downloads_guids);
+ pending_requests_counts_[*registration_id] = request_data.size();
if (auto_complete_requests) {
// Provide fake responses for the given |request_data| pairs.
@@ -155,15 +131,17 @@ class BackgroundFetchJobControllerTest : public BackgroundFetchTestBase {
delegate_proxy_ = std::make_unique<BackgroundFetchDelegateProxy>(delegate_);
auto controller = std::make_unique<BackgroundFetchJobController>(
- delegate_proxy_.get(), registration_id, BackgroundFetchOptions(),
- SkBitmap(), 0 /* bytes_downloaded */, &request_manager_,
+ delegate_proxy_.get(), context_->scheduler_.get(), registration_id,
+ BackgroundFetchOptions(), SkBitmap(), 0 /* bytes_downloaded */,
base::BindRepeating(
&BackgroundFetchJobControllerTest::DidUpdateProgress,
base::Unretained(this)),
- base::BindOnce(&BackgroundFetchJobControllerTest::OnJobFinished));
+ base::BindOnce(&BackgroundFetchJobControllerTest::DidFinishJob,
+ base::Unretained(this)));
controller->InitializeRequestStatus(
0, total_downloads, {} /* outstanding_guids */, "" /* ui_title */);
+
return controller;
}
@@ -180,10 +158,11 @@ class BackgroundFetchJobControllerTest : public BackgroundFetchTestBase {
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
BrowserContext::GetDefaultStoragePartition(browser_context()));
- context_ = new BackgroundFetchContext(
+ context_ = base::MakeRefCounted<BackgroundFetchContext>(
browser_context(),
base::WrapRefCounted(embedded_worker_test_helper()->context_wrapper()),
- base::WrapRefCounted(partition->GetCacheStorageContext()));
+ base::WrapRefCounted(partition->GetCacheStorageContext()),
+ nullptr /* quota_manager_proxy */);
}
void TearDown() override {
@@ -195,11 +174,14 @@ class BackgroundFetchJobControllerTest : public BackgroundFetchTestBase {
}
protected:
- FakeBackgroundFetchRequestManager request_manager_;
scoped_refptr<BackgroundFetchContext> context_;
uint64_t last_downloaded_ = 0;
+ std::map<BackgroundFetchRegistrationId, int> pending_requests_counts_;
+ std::map<BackgroundFetchRegistrationId, BackgroundFetchReasonToAbort>
+ finished_requests_;
+
// Closure that will be invoked every time the JobController receives a
// progress update from a download.
base::RepeatingClosure job_progress_closure_;
@@ -217,8 +199,14 @@ class BackgroundFetchJobControllerTest : public BackgroundFetchTestBase {
job_progress_closure_.Run();
}
- static void OnJobFinished(const BackgroundFetchRegistrationId&,
- BackgroundFetchReasonToAbort reason_to_abort) {}
+ void DidFinishJob(const BackgroundFetchRegistrationId& registration_id,
+ BackgroundFetchReasonToAbort reason_to_abort) {
+ auto iter = pending_requests_counts_.find(registration_id);
+ DCHECK(iter != pending_requests_counts_.end());
+
+ finished_requests_[registration_id] = reason_to_abort;
+ pending_requests_counts_.erase(iter);
+ }
DISALLOW_COPY_AND_ASSIGN(BackgroundFetchJobControllerTest);
};
@@ -231,17 +219,20 @@ TEST_F(BackgroundFetchJobControllerTest, SingleRequestJob) {
true /* auto_complete_requests */);
EXPECT_EQ(JobCompletionStatus::kRunning,
- request_manager_.GetCompletionStatus(registration_id));
+ GetCompletionStatus(registration_id));
std::unique_ptr<BackgroundFetchJobController> controller =
CreateJobController(registration_id, requests.size());
- controller->StartRequest(requests[0]);
+ controller->StartRequest(
+ requests[0],
+ base::BindOnce(&BackgroundFetchJobControllerTest::OnRequestFinished,
+ base::Unretained(this), registration_id));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(JobCompletionStatus::kCompleted,
- request_manager_.GetCompletionStatus(registration_id));
+ GetCompletionStatus(registration_id));
}
TEST_F(BackgroundFetchJobControllerTest, MultipleRequestJob) {
@@ -255,31 +246,40 @@ TEST_F(BackgroundFetchJobControllerTest, MultipleRequestJob) {
true /* auto_complete_requests */);
EXPECT_EQ(JobCompletionStatus::kRunning,
- request_manager_.GetCompletionStatus(registration_id));
+ GetCompletionStatus(registration_id));
std::unique_ptr<BackgroundFetchJobController> controller =
CreateJobController(registration_id, requests.size());
- controller->StartRequest(requests[0]);
+ controller->StartRequest(
+ requests[0],
+ base::BindOnce(&BackgroundFetchJobControllerTest::OnRequestFinished,
+ base::Unretained(this), registration_id));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(JobCompletionStatus::kRunning,
- request_manager_.GetCompletionStatus(registration_id));
+ GetCompletionStatus(registration_id));
- controller->StartRequest(requests[1]);
+ controller->StartRequest(
+ requests[1],
+ base::BindOnce(&BackgroundFetchJobControllerTest::OnRequestFinished,
+ base::Unretained(this), registration_id));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(JobCompletionStatus::kRunning,
- request_manager_.GetCompletionStatus(registration_id));
+ GetCompletionStatus(registration_id));
- controller->StartRequest(requests[2]);
+ controller->StartRequest(
+ requests[2],
+ base::BindOnce(&BackgroundFetchJobControllerTest::OnRequestFinished,
+ base::Unretained(this), registration_id));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(JobCompletionStatus::kCompleted,
- request_manager_.GetCompletionStatus(registration_id));
+ GetCompletionStatus(registration_id));
}
TEST_F(BackgroundFetchJobControllerTest, Abort) {
@@ -290,18 +290,22 @@ TEST_F(BackgroundFetchJobControllerTest, Abort) {
true /* auto_complete_requests */);
EXPECT_EQ(JobCompletionStatus::kRunning,
- request_manager_.GetCompletionStatus(registration_id));
+ GetCompletionStatus(registration_id));
std::unique_ptr<BackgroundFetchJobController> controller =
CreateJobController(registration_id, requests.size());
- controller->StartRequest(requests[0]);
+ controller->StartRequest(
+ requests[0],
+ base::BindOnce(&BackgroundFetchJobControllerTest::OnRequestFinished,
+ base::Unretained(this), registration_id));
+
controller->Abort(BackgroundFetchReasonToAbort::CANCELLED_FROM_UI);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(JobCompletionStatus::kAborted,
- request_manager_.GetCompletionStatus(registration_id));
+ GetCompletionStatus(registration_id));
}
TEST_F(BackgroundFetchJobControllerTest, Progress) {
@@ -312,12 +316,15 @@ TEST_F(BackgroundFetchJobControllerTest, Progress) {
true /* auto_complete_requests */);
EXPECT_EQ(JobCompletionStatus::kRunning,
- request_manager_.GetCompletionStatus(registration_id));
+ GetCompletionStatus(registration_id));
std::unique_ptr<BackgroundFetchJobController> controller =
CreateJobController(registration_id, requests.size());
- controller->StartRequest(requests[0]);
+ controller->StartRequest(
+ requests[0],
+ base::BindOnce(&BackgroundFetchJobControllerTest::OnRequestFinished,
+ base::Unretained(this), registration_id));
{
base::RunLoop run_loop;
@@ -328,12 +335,12 @@ TEST_F(BackgroundFetchJobControllerTest, Progress) {
EXPECT_GT(last_downloaded_, 0u);
EXPECT_LT(last_downloaded_, strlen(kExampleResponseData));
EXPECT_EQ(JobCompletionStatus::kRunning,
- request_manager_.GetCompletionStatus(registration_id));
+ GetCompletionStatus(registration_id));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(JobCompletionStatus::kCompleted,
- request_manager_.GetCompletionStatus(registration_id));
+ GetCompletionStatus(registration_id));
EXPECT_EQ(last_downloaded_, strlen(kExampleResponseData));
}
@@ -345,7 +352,7 @@ TEST_F(BackgroundFetchJobControllerTest, ServiceWorkerRegistrationDeleted) {
true /* auto_complete_requests */);
EXPECT_EQ(JobCompletionStatus::kRunning,
- request_manager_.GetCompletionStatus(registration_id));
+ GetCompletionStatus(registration_id));
std::unique_ptr<BackgroundFetchJobController> controller =
CreateJobController(registration_id, requests.size());
@@ -357,7 +364,7 @@ TEST_F(BackgroundFetchJobControllerTest, ServiceWorkerRegistrationDeleted) {
base::RunLoop().RunUntilIdle();
EXPECT_EQ(JobCompletionStatus::kAborted,
- request_manager_.GetCompletionStatus(registration_id));
+ GetCompletionStatus(registration_id));
}
TEST_F(BackgroundFetchJobControllerTest, ServiceWorkerDatabaseDeleted) {
@@ -368,7 +375,7 @@ TEST_F(BackgroundFetchJobControllerTest, ServiceWorkerDatabaseDeleted) {
true /* auto_complete_requests */);
EXPECT_EQ(JobCompletionStatus::kRunning,
- request_manager_.GetCompletionStatus(registration_id));
+ GetCompletionStatus(registration_id));
std::unique_ptr<BackgroundFetchJobController> controller =
CreateJobController(registration_id, requests.size());
@@ -380,7 +387,7 @@ TEST_F(BackgroundFetchJobControllerTest, ServiceWorkerDatabaseDeleted) {
base::RunLoop().RunUntilIdle();
EXPECT_EQ(JobCompletionStatus::kAborted,
- request_manager_.GetCompletionStatus(registration_id));
+ GetCompletionStatus(registration_id));
}
} // namespace content
diff --git a/chromium/content/browser/background_fetch/background_fetch_request_manager.h b/chromium/content/browser/background_fetch/background_fetch_request_manager.h
deleted file mode 100644
index 6a264c80ea1..00000000000
--- a/chromium/content/browser/background_fetch/background_fetch_request_manager.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_REQUEST_MANAGER_H_
-#define CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_REQUEST_MANAGER_H_
-
-#include <string>
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/memory/scoped_refptr.h"
-
-namespace content {
-
-class BackgroundFetchRegistrationId;
-class BackgroundFetchRequestInfo;
-
-// Interface for manager requests that are part of a Background Fetch.
-// Implementations maintain a queue of requests for each given
-// |BackgroundFetchRegistrationId| that may be backed by a database.
-class BackgroundFetchRequestManager {
- public:
- virtual ~BackgroundFetchRequestManager() {}
-
- // Marks that the |request|, part of the Background Fetch identified by
- // |registration_id|, has completed.
- virtual void MarkRequestAsComplete(
- const BackgroundFetchRegistrationId& registration_id,
- scoped_refptr<BackgroundFetchRequestInfo> request) = 0;
-
- // Called when the job identified by |registration_id| has been aborted along
- // with the GUIDs of any associated downloads that were still active.
- virtual void OnJobAborted(
- const BackgroundFetchRegistrationId& registration_id,
- std::vector<std::string> aborted_guids) = 0;
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_REQUEST_MANAGER_H_
diff --git a/chromium/content/browser/background_fetch/background_fetch_request_match_params.cc b/chromium/content/browser/background_fetch/background_fetch_request_match_params.cc
new file mode 100644
index 00000000000..ddea56601a1
--- /dev/null
+++ b/chromium/content/browser/background_fetch/background_fetch_request_match_params.cc
@@ -0,0 +1,22 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/background_fetch/background_fetch_request_match_params.h"
+
+namespace content {
+
+BackgroundFetchRequestMatchParams::BackgroundFetchRequestMatchParams(
+ base::Optional<ServiceWorkerFetchRequest> request_to_match,
+ blink::mojom::QueryParamsPtr cache_query_params,
+ bool match_all)
+ : request_to_match_(std::move(request_to_match)),
+ cache_query_params_(std::move(cache_query_params)),
+ match_all_(match_all) {}
+
+BackgroundFetchRequestMatchParams::BackgroundFetchRequestMatchParams() =
+ default;
+BackgroundFetchRequestMatchParams::~BackgroundFetchRequestMatchParams() =
+ default;
+
+} // namespace content \ No newline at end of file
diff --git a/chromium/content/browser/background_fetch/background_fetch_request_match_params.h b/chromium/content/browser/background_fetch/background_fetch_request_match_params.h
new file mode 100644
index 00000000000..e43148b2a2e
--- /dev/null
+++ b/chromium/content/browser/background_fetch/background_fetch_request_match_params.h
@@ -0,0 +1,58 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_REQUEST_MATCH_PARAMS_H_
+#define CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_REQUEST_MATCH_PARAMS_H_
+
+#include "base/optional.h"
+#include "content/common/service_worker/service_worker_types.h"
+#include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom.h"
+
+namespace content {
+
+class CONTENT_EXPORT BackgroundFetchRequestMatchParams {
+ public:
+ BackgroundFetchRequestMatchParams();
+ BackgroundFetchRequestMatchParams(
+ base::Optional<ServiceWorkerFetchRequest> request_to_match,
+ blink::mojom::QueryParamsPtr cache_query_params,
+ bool match_all);
+ ~BackgroundFetchRequestMatchParams();
+
+ bool FilterByRequest() const {
+ return request_to_match_.has_value();
+ }
+
+ // Only call this method if a valid request_to_match was previously provided.
+ const ServiceWorkerFetchRequest& request_to_match() const {
+ DCHECK(request_to_match_.has_value());
+ return request_to_match_.value();
+ }
+
+ blink::mojom::QueryParamsPtr cloned_cache_query_params() const {
+ if (!cache_query_params_)
+ return nullptr;
+ return cache_query_params_->Clone();
+ }
+
+ bool match_all() const { return match_all_; }
+
+ private:
+ // If |request_to_match| is present, we get response(s) only for this request.
+ // If not present, response(s) for all requests (contained in the fetch) will
+ // be returned.
+ base::Optional<ServiceWorkerFetchRequest> request_to_match_;
+
+ // When nullptr, this has no effect on the response(s) returned.
+ blink::mojom::QueryParamsPtr cache_query_params_;
+
+ // Whether to return all matching responses from the cache storage.
+ bool match_all_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(BackgroundFetchRequestMatchParams);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_REQUEST_MATCH_PARAMS_H_
diff --git a/chromium/content/browser/background_fetch/background_fetch_scheduler.cc b/chromium/content/browser/background_fetch/background_fetch_scheduler.cc
index ba39a99d590..4fe7cf3fbaf 100644
--- a/chromium/content/browser/background_fetch/background_fetch_scheduler.cc
+++ b/chromium/content/browser/background_fetch/background_fetch_scheduler.cc
@@ -10,10 +10,13 @@
namespace content {
BackgroundFetchScheduler::Controller::Controller(
+ BackgroundFetchScheduler* scheduler,
const BackgroundFetchRegistrationId& registration_id,
FinishedCallback finished_callback)
- : registration_id_(registration_id),
+ : scheduler_(scheduler),
+ registration_id_(registration_id),
finished_callback_(std::move(finished_callback)) {
+ DCHECK(scheduler_);
DCHECK(finished_callback_);
}
@@ -24,104 +27,121 @@ void BackgroundFetchScheduler::Controller::Finish(
DCHECK(reason_to_abort != BackgroundFetchReasonToAbort::NONE ||
!HasMoreRequests());
+ scheduler_->RemoveJobController(this);
+
+ // Developer-initiated abortions will have already marked the registration for
+ // deletion, so make sure that we don't execute the same code-path twice.
+ if (reason_to_abort == BackgroundFetchReasonToAbort::ABORTED_BY_DEVELOPER)
+ return;
+
+ // Race conditions make it possible for a controller to finish twice. This
+ // should be removed when the scheduler starts owning the controllers.
+ if (!finished_callback_)
+ return;
+
std::move(finished_callback_).Run(registration_id_, reason_to_abort);
}
BackgroundFetchScheduler::BackgroundFetchScheduler(
- BackgroundFetchScheduler::RequestProvider* request_provider)
+ RequestProvider* request_provider)
: request_provider_(request_provider) {}
BackgroundFetchScheduler::~BackgroundFetchScheduler() = default;
-void BackgroundFetchScheduler::RemoveJobController(
- const BackgroundFetchRegistrationId& registration_id) {
- for (auto iter = controller_queue_.begin(); iter != controller_queue_.end();
- /* no increment */) {
- if ((**iter).registration_id() == registration_id)
- iter = controller_queue_.erase(iter);
- else
- iter++;
- }
-}
+void BackgroundFetchScheduler::AddJobController(Controller* controller) {
+ DCHECK(controller);
-void BackgroundFetchScheduler::AddJobController(
- BackgroundFetchScheduler::Controller* controller) {
controller_queue_.push_back(controller);
- if (!controller_queue_.empty() &&
- download_controller_map_.size() < max_concurrent_downloads_) {
+ if (!active_controller_)
ScheduleDownload();
- }
}
-void BackgroundFetchScheduler::ScheduleDownload() {
- DCHECK(download_controller_map_.size() < max_concurrent_downloads_);
+void BackgroundFetchScheduler::RemoveJobController(Controller* controller) {
+ DCHECK(controller);
+
+ base::EraseIf(controller_queue_, [controller](Controller* queued_controller) {
+ return controller == queued_controller;
+ });
+
+ if (active_controller_ != controller)
+ return;
+
+ // TODO(peter): Move cancellation of requests to the scheduler.
+ active_controller_ = nullptr;
- if (lock_scheduler_ || controller_queue_.empty())
+ ScheduleDownload();
+}
+
+void BackgroundFetchScheduler::ScheduleDownload() {
+ DCHECK(!active_controller_);
+ if (controller_queue_.empty())
return;
- auto* controller = controller_queue_.front();
+ active_controller_ = controller_queue_.front();
controller_queue_.pop_front();
- // Making an async call, `ScheduleDownload` shouldn't be called anymore.
- lock_scheduler_ = true;
request_provider_->PopNextRequest(
- controller->registration_id(),
+ active_controller_->registration_id(),
base::BindOnce(&BackgroundFetchScheduler::DidPopNextRequest,
- base::Unretained(this), controller));
+ weak_ptr_factory_.GetWeakPtr()));
}
void BackgroundFetchScheduler::DidPopNextRequest(
- BackgroundFetchScheduler::Controller* controller,
scoped_refptr<BackgroundFetchRequestInfo> request_info) {
- DCHECK(controller);
- lock_scheduler_ = false; // Can schedule downloads again.
-
- // Storage error, fetch might have been aborted.
- if (!request_info) {
+ // It's possible for the |active_controller_| to have been aborted while the
+ // next request was being retrieved. Bail out when that happens.
+ if (!active_controller_) {
ScheduleDownload();
return;
}
- download_controller_map_[request_info->download_guid()] = controller;
- controller->StartRequest(request_info);
+ // There might've been a storage error when |request_info| could not be loaded
+ // from the database. Bail out in this case as well.
+ if (!request_info) {
+ // TODO(peter): Should we abort the |active_controller_| in this case?
+ active_controller_ = nullptr;
- if (download_controller_map_.size() < max_concurrent_downloads_)
ScheduleDownload();
+ return;
+ }
+
+ // Otherwise start the |request_info| through the live Job Controller.
+ active_controller_->StartRequest(
+ std::move(request_info),
+ base::BindOnce(&BackgroundFetchScheduler::MarkRequestAsComplete,
+ weak_ptr_factory_.GetWeakPtr()));
}
void BackgroundFetchScheduler::MarkRequestAsComplete(
- const BackgroundFetchRegistrationId& registration_id,
- scoped_refptr<BackgroundFetchRequestInfo> request) {
- DCHECK(download_controller_map_.count(request->download_guid()));
- auto* controller = download_controller_map_[request->download_guid()];
- download_controller_map_.erase(request->download_guid());
+ scoped_refptr<BackgroundFetchRequestInfo> request_info) {
+ // It's possible for the |active_controller_| to have been aborted while the
+ // request was being started. Bail out in that case.
+ if (!active_controller_)
+ return;
request_provider_->MarkRequestAsComplete(
- controller->registration_id(), request.get(),
+ active_controller_->registration_id(), std::move(request_info),
base::BindOnce(&BackgroundFetchScheduler::DidMarkRequestAsComplete,
- base::Unretained(this), controller));
+ weak_ptr_factory_.GetWeakPtr()));
}
-void BackgroundFetchScheduler::DidMarkRequestAsComplete(
- BackgroundFetchScheduler::Controller* controller) {
- if (controller->HasMoreRequests())
- controller_queue_.push_back(controller);
- else
- controller->Finish(BackgroundFetchReasonToAbort::NONE);
-
- ScheduleDownload();
-}
+void BackgroundFetchScheduler::DidMarkRequestAsComplete() {
+ // It's possible for the |active_controller_| to have been aborted while the
+ // request was being marked as completed. Bail out in that case.
+ if (!active_controller_)
+ return;
-void BackgroundFetchScheduler::OnJobAborted(
- const BackgroundFetchRegistrationId& registration_id,
- std::vector<std::string> aborted_guids) {
- // For every active download that was aborted, remove it and schedule a new
- // download.
- for (const auto& guid : aborted_guids) {
- download_controller_map_.erase(guid);
- ScheduleDownload();
+ // Continue with the |active_controller_| while there are files pending.
+ if (active_controller_->HasMoreRequests()) {
+ request_provider_->PopNextRequest(
+ active_controller_->registration_id(),
+ base::BindOnce(&BackgroundFetchScheduler::DidPopNextRequest,
+ weak_ptr_factory_.GetWeakPtr()));
+ return;
}
+
+ active_controller_->Finish(BackgroundFetchReasonToAbort::NONE);
}
} // namespace content
diff --git a/chromium/content/browser/background_fetch/background_fetch_scheduler.h b/chromium/content/browser/background_fetch/background_fetch_scheduler.h
index 243bb95e705..449ea6699f8 100644
--- a/chromium/content/browser/background_fetch/background_fetch_scheduler.h
+++ b/chromium/content/browser/background_fetch/background_fetch_scheduler.h
@@ -13,8 +13,8 @@
#include "base/callback.h"
#include "base/containers/circular_deque.h"
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
#include "content/browser/background_fetch/background_fetch_registration_id.h"
-#include "content/browser/background_fetch/background_fetch_request_manager.h"
#include "content/common/content_export.h"
namespace content {
@@ -25,25 +25,26 @@ enum class BackgroundFetchReasonToAbort;
// Maintains a list of Controllers and chooses which ones should launch new
// downloads.
-class CONTENT_EXPORT BackgroundFetchScheduler
- : public BackgroundFetchRequestManager {
+class CONTENT_EXPORT BackgroundFetchScheduler {
public:
using FinishedCallback =
base::OnceCallback<void(const BackgroundFetchRegistrationId&,
BackgroundFetchReasonToAbort)>;
- using MarkedCompleteCallback = base::OnceCallback<void()>;
// Interface for download job controllers.
class CONTENT_EXPORT Controller {
public:
+ using RequestFinishedCallback =
+ base::OnceCallback<void(scoped_refptr<BackgroundFetchRequestInfo>)>;
+
virtual ~Controller();
// Returns whether the Controller has any pending download requests.
virtual bool HasMoreRequests() = 0;
// Requests the download manager to start fetching |request|.
- virtual void StartRequest(
- scoped_refptr<BackgroundFetchRequestInfo> request) = 0;
+ virtual void StartRequest(scoped_refptr<BackgroundFetchRequestInfo> request,
+ RequestFinishedCallback callback) = 0;
void Finish(BackgroundFetchReasonToAbort reason_to_abort);
@@ -52,10 +53,15 @@ class CONTENT_EXPORT BackgroundFetchScheduler
}
protected:
- Controller(const BackgroundFetchRegistrationId& registration_id,
+ Controller(BackgroundFetchScheduler* scheduler,
+ const BackgroundFetchRegistrationId& registration_id,
FinishedCallback finished_callback);
private:
+ // The |scheduler_| is guaranteed to outlive the controllers due to their
+ // declaration order in the BackgroundFetchContext.
+ BackgroundFetchScheduler* scheduler_;
+
BackgroundFetchRegistrationId registration_id_;
FinishedCallback finished_callback_;
};
@@ -73,57 +79,42 @@ class CONTENT_EXPORT BackgroundFetchScheduler
const BackgroundFetchRegistrationId& registration_id,
NextRequestCallback callback) = 0;
- // Marks |request| as complete and calls |callback| when done.
+ // Marks |request_info| as complete and calls |callback| when done.
virtual void MarkRequestAsComplete(
const BackgroundFetchRegistrationId& registration_id,
- BackgroundFetchRequestInfo* request,
- MarkedCompleteCallback callback) = 0;
+ scoped_refptr<BackgroundFetchRequestInfo> request_info,
+ base::OnceClosure closure) = 0;
};
explicit BackgroundFetchScheduler(RequestProvider* request_provider);
-
- ~BackgroundFetchScheduler() override;
+ ~BackgroundFetchScheduler();
// Adds a new job controller to the scheduler. May immediately start to
// schedule jobs for |controller|.
void AddJobController(Controller* controller);
- // Removes a job controller from the scheduler. Abort ongoing fetches on the
- // controller before calling this.
- // TODO(crbug.com/850075): Move management of active fetches to
- // BackgroundFetchScheduler.
- void RemoveJobController(
- const BackgroundFetchRegistrationId& registration_id);
-
- void set_max_concurrent_downloads(size_t new_max) {
- max_concurrent_downloads_ = new_max;
- }
-
- // BackgroundFetchRequestManager implementation:
- void MarkRequestAsComplete(
- const BackgroundFetchRegistrationId& registration_id,
- scoped_refptr<BackgroundFetchRequestInfo> request) override;
- void OnJobAborted(const BackgroundFetchRegistrationId& registration_id,
- std::vector<std::string> aborted_guids) override;
+ // Removes the |controller| from the scheduler. Pending updates will be
+ // ignored and it won't be considered for further requests.
+ void RemoveJobController(Controller* controller);
private:
void ScheduleDownload();
- void DidPopNextRequest(BackgroundFetchScheduler::Controller* controller,
- scoped_refptr<BackgroundFetchRequestInfo>);
+ void DidPopNextRequest(
+ scoped_refptr<BackgroundFetchRequestInfo> request_info);
- void DidMarkRequestAsComplete(
- BackgroundFetchScheduler::Controller* controller);
+ void MarkRequestAsComplete(
+ scoped_refptr<BackgroundFetchRequestInfo> request_info);
+ void DidMarkRequestAsComplete();
RequestProvider* request_provider_;
// The scheduler owns all the job controllers, holding them either in the
// controller queue or the guid to controller map.
base::circular_deque<Controller*> controller_queue_;
- std::map<std::string, Controller*> download_controller_map_;
+ Controller* active_controller_ = nullptr;
- bool lock_scheduler_ = false;
- size_t max_concurrent_downloads_ = 1;
+ base::WeakPtrFactory<BackgroundFetchScheduler> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(BackgroundFetchScheduler);
};
diff --git a/chromium/content/browser/background_fetch/background_fetch_scheduler_unittest.cc b/chromium/content/browser/background_fetch/background_fetch_scheduler_unittest.cc
index fdee316f59d..156d262cdaf 100644
--- a/chromium/content/browser/background_fetch/background_fetch_scheduler_unittest.cc
+++ b/chromium/content/browser/background_fetch/background_fetch_scheduler_unittest.cc
@@ -31,10 +31,9 @@ class FakeController : public BackgroundFetchScheduler::Controller {
const std::string& name,
std::vector<std::string>* controller_sequence_list,
int total_jobs)
- : BackgroundFetchScheduler::Controller(
- registration_id,
- base::BindOnce(&FakeController::OnJobFinished)),
- scheduler_(scheduler),
+ : BackgroundFetchScheduler::Controller(scheduler,
+ registration_id,
+ base::DoNothing()),
controller_sequence_list_(controller_sequence_list),
name_(name),
total_jobs_(total_jobs) {}
@@ -43,28 +42,20 @@ class FakeController : public BackgroundFetchScheduler::Controller {
// BackgroundFetchScheduler::Controller implementation:
bool HasMoreRequests() override { return jobs_started_ < total_jobs_; }
- void StartRequest(
- scoped_refptr<BackgroundFetchRequestInfo> request) override {
+ void StartRequest(scoped_refptr<BackgroundFetchRequestInfo> request,
+ RequestFinishedCallback callback) override {
DCHECK_LT(jobs_started_, total_jobs_);
++jobs_started_;
controller_sequence_list_->push_back(name_ +
base::IntToString(jobs_started_));
+
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- base::BindOnce(&FakeController::OnDownloadCompleted,
- base::Unretained(this), std::move(request)));
+ base::BindOnce(std::move(callback), std::move(request)));
}
private:
- void OnDownloadCompleted(scoped_refptr<BackgroundFetchRequestInfo> request) {
- scheduler_->MarkRequestAsComplete(registration_id(), std::move(request));
- }
-
- static void OnJobFinished(const BackgroundFetchRegistrationId&,
- BackgroundFetchReasonToAbort reason_to_abort) {}
-
int jobs_started_ = 0;
- BackgroundFetchScheduler* scheduler_;
std::vector<std::string>* controller_sequence_list_;
std::string name_;
int total_jobs_;
@@ -108,9 +99,9 @@ class BackgroundFetchSchedulerTest
void MarkRequestAsComplete(
const BackgroundFetchRegistrationId& registration_id,
- BackgroundFetchRequestInfo* request,
- BackgroundFetchScheduler::MarkedCompleteCallback callback) override {
- std::move(callback).Run();
+ scoped_refptr<BackgroundFetchRequestInfo> request_info,
+ base::OnceClosure closure) override {
+ std::move(closure).Run();
}
protected:
@@ -156,46 +147,13 @@ TEST_F(BackgroundFetchSchedulerTest, TwoControllers) {
// Only one task is run at a time so after 3 barrier iterations, 3 tasks
// should have been have run.
- EXPECT_THAT(controller_sequence_list_, ElementsAre("A1", "B1", "A2"));
- }
-
- base::RunLoop().RunUntilIdle();
-
- EXPECT_THAT(controller_sequence_list_,
- ElementsAre("A1", "B1", "A2", "B2", "A3", "B3", "A4", "B4"));
-}
-
-TEST_F(BackgroundFetchSchedulerTest, TwoControllers_TwoConcurrent) {
- BackgroundFetchRegistrationId registration_id1(
- kExampleServiceWorkerRegistrationId, origin(), kExampleDeveloperId1,
- base::GenerateGUID());
- BackgroundFetchRegistrationId registration_id2(
- kExampleServiceWorkerRegistrationId, origin(), kExampleDeveloperId2,
- base::GenerateGUID());
- FakeController controller1(registration_id1, &scheduler_, "A",
- &controller_sequence_list_, 4);
- FakeController controller2(registration_id2, &scheduler_, "B",
- &controller_sequence_list_, 4);
-
- scheduler_.set_max_concurrent_downloads(2);
- scheduler_.AddJobController(&controller1);
- scheduler_.AddJobController(&controller2);
-
- {
- base::RunLoop run_loop;
- PostQuitAfterRepeatingBarriers(run_loop.QuitClosure(), 3);
- run_loop.Run();
-
- // Two tasks are run at a time so after 3 barrier iterations, 6 tasks should
- // have run.
- EXPECT_THAT(controller_sequence_list_,
- ElementsAre("A1", "B1", "A2", "B2", "A3", "B3"));
+ EXPECT_THAT(controller_sequence_list_, ElementsAre("A1", "A2", "A3"));
}
base::RunLoop().RunUntilIdle();
EXPECT_THAT(controller_sequence_list_,
- ElementsAre("A1", "B1", "A2", "B2", "A3", "B3", "A4", "B4"));
+ ElementsAre("A1", "A2", "A3", "A4", "B1", "B2", "B3", "B4"));
}
} // namespace content
diff --git a/chromium/content/browser/background_fetch/background_fetch_service_impl.cc b/chromium/content/browser/background_fetch/background_fetch_service_impl.cc
index 596cfaa0109..f116ff5aad3 100644
--- a/chromium/content/browser/background_fetch/background_fetch_service_impl.cc
+++ b/chromium/content/browser/background_fetch/background_fetch_service_impl.cc
@@ -7,9 +7,11 @@
#include <memory>
#include "base/guid.h"
+#include "base/optional.h"
#include "content/browser/background_fetch/background_fetch_context.h"
#include "content/browser/background_fetch/background_fetch_metrics.h"
#include "content/browser/background_fetch/background_fetch_registration_id.h"
+#include "content/browser/background_fetch/background_fetch_request_match_params.h"
#include "content/browser/bad_message.h"
#include "content/browser/storage_partition_impl.h"
#include "content/common/service_worker/service_worker_types.h"
@@ -30,11 +32,12 @@ constexpr size_t kMaxTitleLength = 1024 * 1024;
} // namespace
// static
-void BackgroundFetchServiceImpl::Create(
+void BackgroundFetchServiceImpl::CreateForWorker(
blink::mojom::BackgroundFetchServiceRequest request,
RenderProcessHost* render_process_host,
const url::Origin& origin) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::BindOnce(
@@ -42,26 +45,53 @@ void BackgroundFetchServiceImpl::Create(
WrapRefCounted(static_cast<StoragePartitionImpl*>(
render_process_host->GetStoragePartition())
->GetBackgroundFetchContext()),
- origin, std::move(request)));
+ origin, nullptr /* render_frame_host */, std::move(request)));
+}
+
+// static
+void BackgroundFetchServiceImpl::CreateForFrame(
+ RenderProcessHost* render_process_host,
+ int render_frame_id,
+ blink::mojom::BackgroundFetchServiceRequest request) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ DCHECK(render_process_host);
+ auto* render_frame_host =
+ RenderFrameHost::FromID(render_process_host->GetID(), render_frame_id);
+ DCHECK(render_frame_host);
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(
+ BackgroundFetchServiceImpl::CreateOnIoThread,
+ WrapRefCounted(static_cast<StoragePartitionImpl*>(
+ render_process_host->GetStoragePartition())
+ ->GetBackgroundFetchContext()),
+ render_frame_host->GetLastCommittedOrigin(), render_frame_host,
+ std::move(request)));
}
// static
void BackgroundFetchServiceImpl::CreateOnIoThread(
scoped_refptr<BackgroundFetchContext> background_fetch_context,
url::Origin origin,
+ RenderFrameHost* render_frame_host,
blink::mojom::BackgroundFetchServiceRequest request) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- mojo::MakeStrongBinding(
- std::make_unique<BackgroundFetchServiceImpl>(
- std::move(background_fetch_context), std::move(origin)),
- std::move(request));
+
+ mojo::MakeStrongBinding(std::make_unique<BackgroundFetchServiceImpl>(
+ std::move(background_fetch_context),
+ std::move(origin), render_frame_host),
+ std::move(request));
}
BackgroundFetchServiceImpl::BackgroundFetchServiceImpl(
scoped_refptr<BackgroundFetchContext> background_fetch_context,
- url::Origin origin)
+ url::Origin origin,
+ RenderFrameHost* render_frame_host)
: background_fetch_context_(std::move(background_fetch_context)),
- origin_(std::move(origin)) {
+ origin_(std::move(origin)),
+ render_frame_host_(render_frame_host) {
DCHECK(background_fetch_context_);
}
@@ -93,7 +123,8 @@ void BackgroundFetchServiceImpl::Fetch(
base::GenerateGUID());
background_fetch_context_->StartFetch(registration_id, requests, options,
- icon, std::move(callback));
+ icon, render_frame_host_,
+ std::move(callback));
}
void BackgroundFetchServiceImpl::GetIconDisplaySize(
@@ -102,14 +133,37 @@ void BackgroundFetchServiceImpl::GetIconDisplaySize(
background_fetch_context_->GetIconDisplaySize(std::move(callback));
}
+void BackgroundFetchServiceImpl::MatchRequests(
+ int64_t service_worker_registration_id,
+ const std::string& developer_id,
+ const std::string& unique_id,
+ const base::Optional<ServiceWorkerFetchRequest>& request_to_match,
+ blink::mojom::QueryParamsPtr cache_query_params,
+ bool match_all,
+ MatchRequestsCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ BackgroundFetchRegistrationId registration_id(
+ service_worker_registration_id, origin_, developer_id, unique_id);
+
+ // Create BackgroundFetchMatchRequestParams.
+ auto match_params = std::make_unique<BackgroundFetchRequestMatchParams>(
+ request_to_match, std::move(cache_query_params), match_all);
+
+ background_fetch_context_->MatchRequests(
+ registration_id, std::move(match_params), std::move(callback));
+}
+
void BackgroundFetchServiceImpl::UpdateUI(
int64_t service_worker_registration_id,
const std::string& developer_id,
const std::string& unique_id,
- const std::string& title,
+ const base::Optional<std::string>& title,
+ const SkBitmap& icon,
UpdateUICallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!ValidateUniqueId(unique_id) || !ValidateTitle(title)) {
+
+ if (!ValidateUniqueId(unique_id) || (title && !ValidateTitle(*title))) {
std::move(callback).Run(
blink::mojom::BackgroundFetchError::INVALID_ARGUMENT);
return;
@@ -117,7 +171,12 @@ void BackgroundFetchServiceImpl::UpdateUI(
BackgroundFetchRegistrationId registration_id(
service_worker_registration_id, origin_, developer_id, unique_id);
- background_fetch_context_->UpdateUI(registration_id, title,
+
+ // Wrap the icon in an optional for clarity.
+ auto optional_icon =
+ icon.isNull() ? base::nullopt : base::Optional<SkBitmap>(icon);
+
+ background_fetch_context_->UpdateUI(registration_id, title, optional_icon,
std::move(callback));
}
diff --git a/chromium/content/browser/background_fetch/background_fetch_service_impl.h b/chromium/content/browser/background_fetch/background_fetch_service_impl.h
index c61095e1a3c..5abcc9b3b18 100644
--- a/chromium/content/browser/background_fetch/background_fetch_service_impl.h
+++ b/chromium/content/browser/background_fetch/background_fetch_service_impl.h
@@ -20,6 +20,7 @@
namespace content {
class BackgroundFetchContext;
+class RenderFrameHost;
class RenderProcessHost;
struct BackgroundFetchOptions;
struct ServiceWorkerFetchRequest;
@@ -29,12 +30,19 @@ class CONTENT_EXPORT BackgroundFetchServiceImpl
public:
BackgroundFetchServiceImpl(
scoped_refptr<BackgroundFetchContext> background_fetch_context,
- url::Origin origin);
+ url::Origin origin,
+ RenderFrameHost* render_frame_host);
~BackgroundFetchServiceImpl() override;
- static void Create(blink::mojom::BackgroundFetchServiceRequest request,
- RenderProcessHost* render_process_host,
- const url::Origin& origin);
+ static void CreateForWorker(
+ blink::mojom::BackgroundFetchServiceRequest request,
+ RenderProcessHost* render_process_host,
+ const url::Origin& origin);
+
+ static void CreateForFrame(
+ RenderProcessHost* render_process_host,
+ int render_frame_id,
+ blink::mojom::BackgroundFetchServiceRequest request);
// blink::mojom::BackgroundFetchService implementation.
void Fetch(int64_t service_worker_registration_id,
@@ -44,10 +52,19 @@ class CONTENT_EXPORT BackgroundFetchServiceImpl
const SkBitmap& icon,
FetchCallback callback) override;
void GetIconDisplaySize(GetIconDisplaySizeCallback callback) override;
+ void MatchRequests(
+ int64_t service_worker_registration_id,
+ const std::string& developer_id,
+ const std::string& unique_id,
+ const base::Optional<ServiceWorkerFetchRequest>& request_to_match,
+ blink::mojom::QueryParamsPtr cache_query_params,
+ bool match_all,
+ MatchRequestsCallback callback) override;
void UpdateUI(int64_t service_worker_registration_id,
const std::string& developer_id,
const std::string& unique_id,
- const std::string& title,
+ const base::Optional<std::string>& title,
+ const SkBitmap& icon,
UpdateUICallback callback) override;
void Abort(int64_t service_worker_registration_id,
const std::string& developer_id,
@@ -66,6 +83,7 @@ class CONTENT_EXPORT BackgroundFetchServiceImpl
static void CreateOnIoThread(
scoped_refptr<BackgroundFetchContext> background_fetch_context,
url::Origin origin,
+ RenderFrameHost* render_frame_host,
blink::mojom::BackgroundFetchServiceRequest request);
// Validates and returns whether the |developer_id|, |unique_id|, |requests|
@@ -82,6 +100,8 @@ class CONTENT_EXPORT BackgroundFetchServiceImpl
const url::Origin origin_;
+ RenderFrameHost* render_frame_host_;
+
DISALLOW_COPY_AND_ASSIGN(BackgroundFetchServiceImpl);
};
diff --git a/chromium/content/browser/background_fetch/background_fetch_service_unittest.cc b/chromium/content/browser/background_fetch/background_fetch_service_unittest.cc
index 6e2a9c67992..7ae027d417c 100644
--- a/chromium/content/browser/background_fetch/background_fetch_service_unittest.cc
+++ b/chromium/content/browser/background_fetch/background_fetch_service_unittest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <algorithm>
#include <map>
#include <memory>
#include <utility>
@@ -9,6 +10,7 @@
#include "base/auto_reset.h"
#include "base/macros.h"
#include "base/run_loop.h"
+#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/time/time.h"
@@ -47,6 +49,16 @@ blink::Manifest::ImageResource CreateIcon(const std::string& src,
return icon;
}
+bool ContainsHeader(const base::flat_map<std::string, std::string>& headers,
+ const std::string& target) {
+ return headers.cend() !=
+ std::find_if(headers.cbegin(), headers.cend(),
+ [target](const auto& pair) -> bool {
+ return base::EqualsCaseInsensitiveASCII(pair.first,
+ target);
+ });
+}
+
class BadMessageObserver {
public:
BadMessageObserver()
@@ -83,10 +95,11 @@ class BackgroundFetchServiceTest : public BackgroundFetchTestBase {
public:
ScopedCustomBackgroundFetchService(BackgroundFetchServiceTest* test,
const url::Origin& origin)
- : scoped_service_(
- &test->service_,
- std::make_unique<BackgroundFetchServiceImpl>(test->context_,
- origin)) {}
+ : scoped_service_(&test->service_,
+ std::make_unique<BackgroundFetchServiceImpl>(
+ test->context_,
+ origin,
+ nullptr /* render_frame_host */)) {}
private:
base::AutoReset<std::unique_ptr<BackgroundFetchServiceImpl>>
@@ -173,6 +186,24 @@ class BackgroundFetchServiceTest : public BackgroundFetchTestBase {
run_loop.Run();
}
+ // Calls BackgroundFetchServiceImpl::MatchRequests() to retrieve all settled
+ // fetches.
+ void MatchAllRequests(int64_t service_worker_registration_id,
+ const std::string& developer_id,
+ const std::string& unique_id,
+ std::vector<BackgroundFetchSettledFetch>* out_fetches) {
+ DCHECK(out_fetches);
+ base::RunLoop run_loop;
+ service_->MatchRequests(
+ service_worker_registration_id, developer_id, unique_id,
+ base::nullopt /* request_to_match*/, nullptr /* cache_query_params*/,
+ true /* match_all */,
+ base::BindOnce(&BackgroundFetchServiceTest::DidMatchAllRequests,
+ base::Unretained(this), run_loop.QuitClosure(),
+ out_fetches));
+ run_loop.Run();
+ }
+
// Synchronous wrapper for BackgroundFetchServiceImpl::UpdateUI().
void UpdateUI(int64_t service_worker_registration_id,
const std::string& developer_id,
@@ -183,7 +214,7 @@ class BackgroundFetchServiceTest : public BackgroundFetchTestBase {
base::RunLoop run_loop;
service_->UpdateUI(service_worker_registration_id, unique_id, developer_id,
- title,
+ title, SkBitmap(),
base::BindOnce(&BackgroundFetchServiceTest::DidGetError,
base::Unretained(this),
run_loop.QuitClosure(), out_error));
@@ -266,17 +297,18 @@ class BackgroundFetchServiceTest : public BackgroundFetchTestBase {
void SetUp() override {
BackgroundFetchTestBase::SetUp();
- context_ = new BackgroundFetchContext(
+ context_ = base::MakeRefCounted<BackgroundFetchContext>(
browser_context(),
base::WrapRefCounted(embedded_worker_test_helper()->context_wrapper()),
- nullptr /* cache_storage_context */);
+ nullptr /* cache_storage_context */, nullptr /* quota_manager_proxy */);
context_->SetDataManagerForTesting(
std::make_unique<BackgroundFetchTestDataManager>(
browser_context(), storage_partition(),
embedded_worker_test_helper()->context_wrapper()));
context_->InitializeOnIOThread();
- service_ = std::make_unique<BackgroundFetchServiceImpl>(context_, origin());
+ service_ = std::make_unique<BackgroundFetchServiceImpl>(
+ context_, origin(), nullptr /* render_frame_host */);
}
void TearDown() override {
@@ -290,9 +322,12 @@ class BackgroundFetchServiceTest : public BackgroundFetchTestBase {
base::RunLoop().RunUntilIdle();
}
+ protected:
+ scoped_refptr<BackgroundFetchContext> context_;
+
private:
void DidGetRegistration(
- base::Closure quit_closure,
+ base::OnceClosure quit_closure,
blink::mojom::BackgroundFetchError* out_error,
BackgroundFetchRegistration* out_registration,
blink::mojom::BackgroundFetchError error,
@@ -305,15 +340,14 @@ class BackgroundFetchServiceTest : public BackgroundFetchTestBase {
std::move(quit_closure).Run();
}
- void DidStartFetch(
- base::Closure quit_closure,
- blink::mojom::BackgroundFetchError error,
- std::unique_ptr<BackgroundFetchRegistration> registration) {
+ void DidStartFetch(base::OnceClosure quit_closure,
+ blink::mojom::BackgroundFetchError error,
+ const BackgroundFetchRegistration& registration) {
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
std::move(quit_closure).Run();
}
- void DidGetError(base::Closure quit_closure,
+ void DidGetError(base::OnceClosure quit_closure,
blink::mojom::BackgroundFetchError* out_error,
blink::mojom::BackgroundFetchError error) {
*out_error = error;
@@ -321,7 +355,7 @@ class BackgroundFetchServiceTest : public BackgroundFetchTestBase {
std::move(quit_closure).Run();
}
- void DidGetDeveloperIds(base::Closure quit_closure,
+ void DidGetDeveloperIds(base::OnceClosure quit_closure,
blink::mojom::BackgroundFetchError* out_error,
std::vector<std::string>* out_developer_ids,
blink::mojom::BackgroundFetchError error,
@@ -332,7 +366,14 @@ class BackgroundFetchServiceTest : public BackgroundFetchTestBase {
std::move(quit_closure).Run();
}
- scoped_refptr<BackgroundFetchContext> context_;
+ void DidMatchAllRequests(
+ base::OnceClosure quit_closure,
+ std::vector<BackgroundFetchSettledFetch>* out_fetches,
+ const std::vector<BackgroundFetchSettledFetch>& fetches) {
+ *out_fetches = fetches;
+ std::move(quit_closure).Run();
+ }
+
std::unique_ptr<BackgroundFetchServiceImpl> service_;
DISALLOW_COPY_AND_ASSIGN(BackgroundFetchServiceTest);
@@ -455,7 +496,8 @@ TEST_F(BackgroundFetchServiceTest, FetchDuplicatedRegistrationFailure) {
TEST_F(BackgroundFetchServiceTest, FetchSuccessEventDispatch) {
// This test starts a new Background Fetch, completes the registration, then
// fetches all files to complete the job, and then verifies that the
- // `backgroundfetched` event will be dispatched with the expected contents.
+ // `backgroundfetchsuccess` event will be dispatched with the expected
+ // contents.
int64_t service_worker_registration_id = RegisterServiceWorker();
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId,
@@ -499,11 +541,10 @@ TEST_F(BackgroundFetchServiceTest, FetchSuccessEventDispatch) {
.Build()));
// Create the registration with the given |requests|.
+ BackgroundFetchRegistration registration;
{
BackgroundFetchOptions options;
-
blink::mojom::BackgroundFetchError error;
- BackgroundFetchRegistration registration;
// Create the first registration. This must succeed.
Fetch(service_worker_registration_id, kExampleDeveloperId, requests,
@@ -514,55 +555,58 @@ TEST_F(BackgroundFetchServiceTest, FetchSuccessEventDispatch) {
// Spin the |event_dispatched_loop| to wait for the dispatched event.
event_dispatched_loop.Run();
- ASSERT_TRUE(embedded_worker_test_helper()->last_developer_id().has_value());
- EXPECT_EQ(kExampleDeveloperId,
- embedded_worker_test_helper()->last_developer_id().value());
-
- ASSERT_TRUE(embedded_worker_test_helper()->last_fetches().has_value());
+ ASSERT_TRUE(embedded_worker_test_helper()->last_registration().has_value());
+ EXPECT_EQ(kExampleDeveloperId, registration.developer_id);
- std::vector<BackgroundFetchSettledFetch> fetches =
- embedded_worker_test_helper()->last_fetches().value();
+ // Get all the settled fetches and test properties.
+ std::vector<BackgroundFetchSettledFetch> fetches;
+ MatchAllRequests(service_worker_registration_id, registration.developer_id,
+ registration.unique_id, &fetches);
ASSERT_EQ(fetches.size(), requests.size());
for (size_t i = 0; i < fetches.size(); ++i) {
ASSERT_EQ(fetches[i].request.url, requests[i].url);
EXPECT_EQ(fetches[i].request.method, requests[i].method);
- EXPECT_EQ(fetches[i].response.url_list[0], fetches[i].request.url);
- EXPECT_EQ(fetches[i].response.response_type,
+ EXPECT_EQ(fetches[i].response->url_list[0], fetches[i].request.url);
+ EXPECT_EQ(fetches[i].response->response_type,
network::mojom::FetchResponseType::kDefault);
switch (i) {
case 0:
- EXPECT_EQ(fetches[i].response.status_code, kFirstResponseCode);
- EXPECT_EQ(fetches[i].response.headers.count("Content-Type"), 1u);
- EXPECT_EQ(fetches[i].response.headers.count("X-Cat"), 1u);
+ EXPECT_EQ(fetches[i].response->status_code, kFirstResponseCode);
+ EXPECT_TRUE(
+ ContainsHeader(fetches[i].response->headers, "Content-Type"));
+ EXPECT_TRUE(ContainsHeader(fetches[i].response->headers, "X-Cat"));
break;
case 1:
- EXPECT_EQ(fetches[i].response.status_code, kSecondResponseCode);
- EXPECT_EQ(fetches[i].response.headers.count("Content-Type"), 1u);
- EXPECT_EQ(fetches[i].response.headers.count("X-Cat"), 0u);
+ EXPECT_EQ(fetches[i].response->status_code, kSecondResponseCode);
+ EXPECT_TRUE(
+ ContainsHeader(fetches[i].response->headers, "Content-Type"));
+ EXPECT_FALSE(ContainsHeader(fetches[i].response->headers, "X-Cat"));
break;
case 2:
- EXPECT_EQ(fetches[i].response.status_code, kThirdResponseCode);
- EXPECT_EQ(fetches[i].response.headers.count("Content-Type"), 1u);
- EXPECT_EQ(fetches[i].response.headers.count("X-Cat"), 0u);
+ EXPECT_EQ(fetches[i].response->status_code, kThirdResponseCode);
+ EXPECT_TRUE(
+ ContainsHeader(fetches[i].response->headers, "Content-Type"));
+ EXPECT_FALSE(ContainsHeader(fetches[i].response->headers, "X-Cat"));
break;
default:
NOTREACHED();
}
// TODO(peter): change-detector tests for unsupported properties.
- EXPECT_EQ(fetches[i].response.error,
+ EXPECT_EQ(fetches[i].response->error,
blink::mojom::ServiceWorkerResponseError::kUnknown);
// Verify that all properties have a sensible value.
- EXPECT_FALSE(fetches[i].response.response_time.is_null());
+ EXPECT_FALSE(fetches[i].response->response_time.is_null());
// Verify that the response blobs have been populated. We cannot consume
// their data here since the handles have already been released.
- ASSERT_FALSE(fetches[i].response.blob_uuid.empty());
- ASSERT_GT(fetches[i].response.blob_size, 0u);
+ ASSERT_TRUE(fetches[i].response->blob);
+ ASSERT_FALSE(fetches[i].response->blob->uuid.empty());
+ ASSERT_GT(fetches[i].response->blob->size, 0u);
}
}
@@ -598,11 +642,12 @@ TEST_F(BackgroundFetchServiceTest, FetchFailEventDispatch) {
.Build()));
// Create the registration with the given |requests|.
+ BackgroundFetchRegistration registration;
+
{
BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error;
- BackgroundFetchRegistration registration;
// Create the first registration. This must succeed.
Fetch(service_worker_registration_id, kExampleDeveloperId, requests,
@@ -613,44 +658,42 @@ TEST_F(BackgroundFetchServiceTest, FetchFailEventDispatch) {
// Spin the |event_dispatched_loop| to wait for the dispatched event.
event_dispatched_loop.Run();
- ASSERT_TRUE(embedded_worker_test_helper()->last_developer_id().has_value());
- EXPECT_EQ(kExampleDeveloperId,
- embedded_worker_test_helper()->last_developer_id().value());
-
- ASSERT_TRUE(embedded_worker_test_helper()->last_fetches().has_value());
+ ASSERT_TRUE(embedded_worker_test_helper()->last_registration().has_value());
+ EXPECT_EQ(kExampleDeveloperId, registration.developer_id);
- std::vector<BackgroundFetchSettledFetch> fetches =
- embedded_worker_test_helper()->last_fetches().value();
+ // Get all the settled fetches and test properties.
+ std::vector<BackgroundFetchSettledFetch> fetches;
+ MatchAllRequests(service_worker_registration_id, registration.developer_id,
+ registration.unique_id, &fetches);
ASSERT_EQ(fetches.size(), requests.size());
for (size_t i = 0; i < fetches.size(); ++i) {
ASSERT_EQ(fetches[i].request.url, requests[i].url);
EXPECT_EQ(fetches[i].request.method, requests[i].method);
- EXPECT_EQ(fetches[i].response.url_list[0], fetches[i].request.url);
- EXPECT_EQ(fetches[i].response.response_type,
+ EXPECT_EQ(fetches[i].response->url_list[0], fetches[i].request.url);
+ EXPECT_EQ(fetches[i].response->response_type,
network::mojom::FetchResponseType::kDefault);
switch (i) {
case 0:
- EXPECT_EQ(fetches[i].response.status_code, 404);
+ EXPECT_EQ(fetches[i].response->status_code, 404);
break;
case 1:
- EXPECT_EQ(fetches[i].response.status_code, 0);
+ EXPECT_EQ(fetches[i].response->status_code, 0);
break;
default:
NOTREACHED();
}
- EXPECT_TRUE(fetches[i].response.headers.empty());
- EXPECT_TRUE(fetches[i].response.blob_uuid.empty());
- EXPECT_EQ(fetches[i].response.blob_size, 0u);
- EXPECT_FALSE(fetches[i].response.response_time.is_null());
+ EXPECT_TRUE(fetches[i].response->headers.empty());
+ EXPECT_FALSE(fetches[i].response->blob);
+ EXPECT_FALSE(fetches[i].response->response_time.is_null());
// TODO(peter): change-detector tests for unsupported properties.
- EXPECT_EQ(fetches[i].response.error,
+ EXPECT_EQ(fetches[i].response->error,
blink::mojom::ServiceWorkerResponseError::kUnknown);
- EXPECT_TRUE(fetches[i].response.cors_exposed_header_names.empty());
+ EXPECT_TRUE(fetches[i].response->cors_exposed_header_names.empty());
}
}
@@ -823,9 +866,9 @@ TEST_F(BackgroundFetchServiceTest, AbortEventDispatch) {
event_dispatched_loop.Run();
- ASSERT_TRUE(embedded_worker_test_helper()->last_developer_id().has_value());
+ ASSERT_TRUE(embedded_worker_test_helper()->last_registration().has_value());
EXPECT_EQ(kExampleDeveloperId,
- embedded_worker_test_helper()->last_developer_id().value());
+ embedded_worker_test_helper()->last_registration()->developer_id);
}
TEST_F(BackgroundFetchServiceTest, UniqueId) {
@@ -893,7 +936,7 @@ TEST_F(BackgroundFetchServiceTest, UniqueId) {
// Calling UpdateUI for the aborted registration should fail (unlike, say,
// calling UpdateUI before resolving the waitUntil promise of a
- // backgroundfetched or backgroundfetchfail event, both of which should
+ // backgroundfetchsuccess or backgroundfetchfail event, both of which should
// work even though that registration is no longer active).
UpdateUI(aborted_registration_id.service_worker_registration_id(),
aborted_registration_id.unique_id(),
@@ -1095,9 +1138,15 @@ TEST_F(BackgroundFetchServiceTest, JobsInitializedOnBrowserRestart) {
.Build()));
BackgroundFetchOptions options;
- // Only register the Fetch.
- StartFetch(service_worker_registration_id, kExampleDeveloperId, requests,
- options, SkBitmap());
+ // Only register the Fetch. In order to appropriately simulate a browser
+ // restart, we do not want the fetch to start yet.
+ {
+ base::AutoReset<bool> hang_registration_creation_for_testing(
+ &context_->hang_registration_creation_for_testing_, true);
+
+ StartFetch(service_worker_registration_id, kExampleDeveloperId, requests,
+ options, SkBitmap());
+ }
// Simulate browser restart by re-creating |context_| and |service_|.
SetUp();
diff --git a/chromium/content/browser/background_fetch/background_fetch_test_base.cc b/chromium/content/browser/background_fetch/background_fetch_test_base.cc
index fc5366e5abd..ef6f354e99c 100644
--- a/chromium/content/browser/background_fetch/background_fetch_test_base.cc
+++ b/chromium/content/browser/background_fetch/background_fetch_test_base.cc
@@ -163,4 +163,16 @@ BackgroundFetchTestBase::CreateRequestWithProvidedResponse(
Referrer(), false /* is_reload */);
}
+std::unique_ptr<BackgroundFetchRegistration>
+BackgroundFetchTestBase::CreateBackgroundFetchRegistration(
+ const std::string& developer_id,
+ const std::string& unique_id,
+ blink::mojom::BackgroundFetchState state,
+ blink::mojom::BackgroundFetchFailureReason failure_reason) {
+ auto registration = std::make_unique<BackgroundFetchRegistration>(
+ developer_id, unique_id, 0 /* upload_total */, 0 /* uploaded */,
+ 0 /* download_total */, 0 /* downloaded */, state, failure_reason);
+ return registration;
+}
+
} // namespace content
diff --git a/chromium/content/browser/background_fetch/background_fetch_test_base.h b/chromium/content/browser/background_fetch/background_fetch_test_base.h
index a2bcc7365bd..9bb6f0b09c9 100644
--- a/chromium/content/browser/background_fetch/background_fetch_test_base.h
+++ b/chromium/content/browser/background_fetch/background_fetch_test_base.h
@@ -56,6 +56,14 @@ class BackgroundFetchTestBase : public ::testing::Test {
const GURL& url,
std::unique_ptr<TestResponse> response);
+ // Creates a BackgroundFetchRegistration object.
+ std::unique_ptr<BackgroundFetchRegistration>
+ CreateBackgroundFetchRegistration(
+ const std::string& developer_id,
+ const std::string& unique_id,
+ blink::mojom::BackgroundFetchState state,
+ blink::mojom::BackgroundFetchFailureReason failure_reason);
+
// Returns the embedded worker test helper instance, which can be used to
// influence the behavior of the Service Worker events.
BackgroundFetchEmbeddedWorkerTestHelper* embedded_worker_test_helper() {
diff --git a/chromium/content/browser/background_fetch/background_fetch_test_data_manager.cc b/chromium/content/browser/background_fetch/background_fetch_test_data_manager.cc
index b081be6b97c..2f4ebbb5bdf 100644
--- a/chromium/content/browser/background_fetch/background_fetch_test_data_manager.cc
+++ b/chromium/content/browser/background_fetch/background_fetch_test_data_manager.cc
@@ -29,6 +29,15 @@ class MockBGFQuotaManagerProxy : public MockQuotaManagerProxy {
delete client; // Directly delete, to avoid memory leak.
}
+ void GetUsageAndQuota(base::SequencedTaskRunner* original_task_runner,
+ const url::Origin& origin,
+ blink::mojom::StorageType type,
+ UsageAndQuotaCallback callback) override {
+ DCHECK(original_task_runner);
+ std::move(callback).Run(blink::mojom::QuotaStatusCode::kOk, 0 /* usage */,
+ kBackgroundFetchMaxQuotaBytes);
+ }
+
protected:
~MockBGFQuotaManagerProxy() override = default;
};
@@ -42,7 +51,8 @@ BackgroundFetchTestDataManager::BackgroundFetchTestDataManager(
bool mock_fill_response)
: BackgroundFetchDataManager(browser_context,
service_worker_context,
- nullptr /* cache_storage_context */),
+ nullptr /* cache_storage_context */,
+ nullptr /* quota_manager_proxy */),
browser_context_(browser_context),
storage_partition_(storage_partition),
mock_fill_response_(mock_fill_response) {}
@@ -57,13 +67,13 @@ void BackgroundFetchTestDataManager::InitializeOnIOThread() {
storage_partition_->GetPath().empty(), storage_partition_->GetPath(),
base::ThreadTaskRunnerHandle::Get().get(),
base::MakeRefCounted<MockSpecialStoragePolicy>());
- mock_quota_manager_->SetQuota(GURL("https://example.com/"),
- StorageType::kTemporary, 1024 * 1024 * 100);
+
+ quota_manager_proxy_ =
+ base::MakeRefCounted<MockBGFQuotaManagerProxy>(mock_quota_manager_.get());
cache_manager_ = CacheStorageManager::Create(
storage_partition_->GetPath(), base::ThreadTaskRunnerHandle::Get(),
- base::MakeRefCounted<MockBGFQuotaManagerProxy>(
- mock_quota_manager_.get()));
+ quota_manager_proxy_);
DCHECK(cache_manager_);
cache_manager_->SetBlobParametersForCache(
diff --git a/chromium/content/browser/background_fetch/background_fetch_test_data_manager.h b/chromium/content/browser/background_fetch/background_fetch_test_data_manager.h
index 9596d3f84d8..8cb5228b294 100644
--- a/chromium/content/browser/background_fetch/background_fetch_test_data_manager.h
+++ b/chromium/content/browser/background_fetch/background_fetch_test_data_manager.h
@@ -20,6 +20,9 @@ class MockQuotaManager;
class ServiceWorkerContextWrapper;
class StoragePartition;
+// Arbitrary quota that is large enough for test purposes.
+constexpr int64_t kBackgroundFetchMaxQuotaBytes = 42424242;
+
// Test DataManager that sets up a CacheStorageManager suited for test
// environments. Tests can also optionally override FillServiceWorkerResponse by
// setting |mock_fill_response| to true.
diff --git a/chromium/content/browser/background_fetch/mock_background_fetch_delegate.cc b/chromium/content/browser/background_fetch/mock_background_fetch_delegate.cc
index 72a098529cc..3655aae7eb8 100644
--- a/chromium/content/browser/background_fetch/mock_background_fetch_delegate.cc
+++ b/chromium/content/browser/background_fetch/mock_background_fetch_delegate.cc
@@ -6,6 +6,7 @@
#include <vector>
#include "base/files/file_util.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/browser/background_fetch/mock_background_fetch_delegate.h"
#include "content/public/browser/background_fetch_description.h"
@@ -56,6 +57,15 @@ MockBackgroundFetchDelegate::MockBackgroundFetchDelegate() {}
MockBackgroundFetchDelegate::~MockBackgroundFetchDelegate() {}
+void MockBackgroundFetchDelegate::GetPermissionForOrigin(
+ const url::Origin& origin,
+ const ResourceRequestInfo::WebContentsGetter& wc_getter,
+ GetPermissionForOriginCallback callback) {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(callback), true /* has_permission */));
+}
+
void MockBackgroundFetchDelegate::GetIconDisplaySize(
GetIconDisplaySizeCallback callback) {}
@@ -149,8 +159,10 @@ void MockBackgroundFetchDelegate::Abort(const std::string& job_unique_id) {
aborted_jobs_.insert(job_unique_id);
}
-void MockBackgroundFetchDelegate::UpdateUI(const std::string& job_unique_id,
- const std::string& title) {}
+void MockBackgroundFetchDelegate::UpdateUI(
+ const std::string& job_unique_id,
+ const base::Optional<std::string>& title,
+ const base::Optional<SkBitmap>& icon) {}
void MockBackgroundFetchDelegate::RegisterResponse(
const GURL& url,
diff --git a/chromium/content/browser/background_fetch/mock_background_fetch_delegate.h b/chromium/content/browser/background_fetch/mock_background_fetch_delegate.h
index 587f07116a5..fc64babe3cb 100644
--- a/chromium/content/browser/background_fetch/mock_background_fetch_delegate.h
+++ b/chromium/content/browser/background_fetch/mock_background_fetch_delegate.h
@@ -12,7 +12,9 @@
#include <vector>
#include "base/files/scoped_temp_dir.h"
+#include "base/optional.h"
#include "content/public/browser/background_fetch_delegate.h"
+#include "third_party/skia/include/core/SkBitmap.h"
#include "url/gurl.h"
namespace net {
@@ -63,6 +65,10 @@ class MockBackgroundFetchDelegate : public BackgroundFetchDelegate {
~MockBackgroundFetchDelegate() override;
// BackgroundFetchDelegate implementation:
+ void GetPermissionForOrigin(
+ const url::Origin& origin,
+ const ResourceRequestInfo::WebContentsGetter& wc_getter,
+ GetPermissionForOriginCallback callback) override;
void GetIconDisplaySize(
BackgroundFetchDelegate::GetIconDisplaySizeCallback callback) override;
void CreateDownloadJob(
@@ -75,7 +81,8 @@ class MockBackgroundFetchDelegate : public BackgroundFetchDelegate {
const net::HttpRequestHeaders& headers) override;
void Abort(const std::string& job_unique_id) override;
void UpdateUI(const std::string& job_unique_id,
- const std::string& title) override;
+ const base::Optional<std::string>& title,
+ const base::Optional<SkBitmap>& icon) override;
void RegisterResponse(const GURL& url,
std::unique_ptr<TestResponse> response);
diff --git a/chromium/content/browser/background_fetch/storage/README.md b/chromium/content/browser/background_fetch/storage/README.md
index a21b6bc1a03..ccaaa2e1a4e 100644
--- a/chromium/content/browser/background_fetch/storage/README.md
+++ b/chromium/content/browser/background_fetch/storage/README.md
@@ -26,8 +26,8 @@ value: "<serialized content::proto::BackgroundFetchMetadata>"
```
```
-key: "bgfetch_title_<unique_id>"
-value: "<ui_title>"
+key: "bgfetch_ui_options_<unique_id>"
+value: "<serialized content::proto::BackgroundFetchUIOptions>"
```
```
diff --git a/chromium/content/browser/background_fetch/storage/cleanup_task.cc b/chromium/content/browser/background_fetch/storage/cleanup_task.cc
index 8940c09d09d..96ac829f8ae 100644
--- a/chromium/content/browser/background_fetch/storage/cleanup_task.cc
+++ b/chromium/content/browser/background_fetch/storage/cleanup_task.cc
@@ -57,7 +57,8 @@ void CleanupTask::DidGetActiveUniqueIds(
case DatabaseStatus::kNotFound:
break;
case DatabaseStatus::kFailed:
- FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
+ SetStorageErrorAndFinish(
+ BackgroundFetchStorageError::kServiceWorkerStorageError);
return;
}
@@ -93,9 +94,14 @@ void CleanupTask::DidGetActiveUniqueIds(
}
void CleanupTask::FinishWithError(blink::mojom::BackgroundFetchError error) {
+ ReportStorageError();
Finished(); // Destroys |this|.
}
+std::string CleanupTask::HistogramName() const {
+ return "CleanupTask";
+}
+
} // namespace background_fetch
} // namespace content
diff --git a/chromium/content/browser/background_fetch/storage/cleanup_task.h b/chromium/content/browser/background_fetch/storage/cleanup_task.h
index e116f789a39..4bbfbe5ce35 100644
--- a/chromium/content/browser/background_fetch/storage/cleanup_task.h
+++ b/chromium/content/browser/background_fetch/storage/cleanup_task.h
@@ -38,6 +38,8 @@ class CleanupTask : public background_fetch::DatabaseTask {
void FinishWithError(blink::mojom::BackgroundFetchError error) override;
+ std::string HistogramName() const override;
+
base::WeakPtrFactory<CleanupTask> weak_factory_; // Keep as last.
DISALLOW_COPY_AND_ASSIGN(CleanupTask);
diff --git a/chromium/content/browser/background_fetch/storage/create_metadata_task.cc b/chromium/content/browser/background_fetch/storage/create_metadata_task.cc
index 07fdeb13d8a..17665e2b145 100644
--- a/chromium/content/browser/background_fetch/storage/create_metadata_task.cc
+++ b/chromium/content/browser/background_fetch/storage/create_metadata_task.cc
@@ -6,37 +6,19 @@
#include <utility>
-#include "base/sequenced_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/task_scheduler/post_task.h"
-#include "base/task_scheduler/task_traits.h"
+#include "content/browser/background_fetch/background_fetch_data_manager.h"
+#include "content/browser/background_fetch/background_fetch_data_manager_observer.h"
#include "content/browser/background_fetch/storage/database_helpers.h"
+#include "content/browser/background_fetch/storage/image_helpers.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
-#include "ui/gfx/image/image.h"
namespace content {
namespace background_fetch {
-namespace {
-
-std::string ConvertAndSerializeIcon(const SkBitmap& icon) {
- // Serialize the icon and copy the bytes over.
- std::string serialized_icon;
- auto icon_bytes = gfx::Image::CreateFrom1xBitmap(icon).As1xPNGBytes();
- serialized_icon.assign(icon_bytes->front_as<char>(),
- icon_bytes->front_as<char>() + icon_bytes->size());
- return serialized_icon;
-}
-
-} // namespace
-
-// The max icon resolution, this is used as a threshold to decide
-// whether the icon should be persisted.
-constexpr int kMaxIconResolution = 256 * 256;
-
CreateMetadataTask::CreateMetadataTask(
DatabaseTaskHost* host,
const BackgroundFetchRegistrationId& registration_id,
@@ -55,6 +37,25 @@ CreateMetadataTask::CreateMetadataTask(
CreateMetadataTask::~CreateMetadataTask() = default;
void CreateMetadataTask::Start() {
+ // Check if there is enough quota to download the data first.
+ if (options_.download_total > 0) {
+ IsQuotaAvailable(registration_id_.origin(), options_.download_total,
+ base::BindOnce(&CreateMetadataTask::DidGetIsQuotaAvailable,
+ weak_factory_.GetWeakPtr()));
+ } else {
+ // Proceed with the fetch.
+ GetRegistrationUniqueId();
+ }
+}
+
+void CreateMetadataTask::DidGetIsQuotaAvailable(bool is_available) {
+ if (!is_available)
+ FinishWithError(blink::mojom::BackgroundFetchError::QUOTA_EXCEEDED);
+ else
+ GetRegistrationUniqueId();
+}
+
+void CreateMetadataTask::GetRegistrationUniqueId() {
service_worker_context()->GetRegistrationUserData(
registration_id_.service_worker_registration_id(),
{ActiveRegistrationUniqueIdKey(registration_id_.developer_id())},
@@ -66,8 +67,7 @@ void CreateMetadataTask::DidGetUniqueId(const std::vector<std::string>& data,
blink::ServiceWorkerStatusCode status) {
switch (ToDatabaseStatus(status)) {
case DatabaseStatus::kNotFound:
- InitializeMetadataProto();
- return;
+ break;
case DatabaseStatus::kOk:
// Can't create a registration since there is already an active
// registration with the same |developer_id|. It must be deactivated
@@ -76,9 +76,21 @@ void CreateMetadataTask::DidGetUniqueId(const std::vector<std::string>& data,
blink::mojom::BackgroundFetchError::DUPLICATED_DEVELOPER_ID);
return;
case DatabaseStatus::kFailed:
- FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
+ SetStorageErrorAndFinish(
+ BackgroundFetchStorageError::kServiceWorkerStorageError);
return;
}
+
+ InitializeMetadataProto();
+
+ if (ShouldPersistIcon(icon_)) {
+ // Serialize the icon, then store all the metadata.
+ SerializeIcon(icon_, base::BindOnce(&CreateMetadataTask::DidSerializeIcon,
+ weak_factory_.GetWeakPtr()));
+ } else {
+ // Directly store the metadata.
+ StoreMetadata();
+ }
}
void CreateMetadataTask::InitializeMetadataProto() {
@@ -89,6 +101,10 @@ void CreateMetadataTask::InitializeMetadataProto() {
registration_proto->set_unique_id(registration_id_.unique_id());
registration_proto->set_developer_id(registration_id_.developer_id());
registration_proto->set_download_total(options_.download_total);
+ registration_proto->set_state(
+ proto::BackgroundFetchRegistration_BackgroundFetchState_PENDING);
+ registration_proto->set_failure_reason(
+ proto::BackgroundFetchRegistration_BackgroundFetchFailureReason_NONE);
// Set Options fields.
auto* options_proto = metadata_proto_->mutable_options();
@@ -126,40 +142,39 @@ void CreateMetadataTask::InitializeMetadataProto() {
metadata_proto_->set_creation_microseconds_since_unix_epoch(
(base::Time::Now() - base::Time::UnixEpoch()).InMicroseconds());
metadata_proto_->set_num_fetches(requests_.size());
-
- // Check if |icon_| should be persisted.
- if (icon_.height() * icon_.width() > kMaxIconResolution) {
- StoreMetadata();
- return;
- }
-
- // Do the initialization on a seperate thread to avoid blocking on
- // expensive operations (image conversions), then post back to IO thread
- // and continue normally.
- base::PostTaskWithTraitsAndReplyWithResult(
- FROM_HERE,
- {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
- base::TaskPriority::BACKGROUND},
- base::BindOnce(&ConvertAndSerializeIcon, icon_),
- base::BindOnce(&CreateMetadataTask::StoreIcon,
- weak_factory_.GetWeakPtr()));
}
-void CreateMetadataTask::StoreIcon(std::string serialized_icon) {
- DCHECK(metadata_proto_);
- metadata_proto_->set_icon(std::move(serialized_icon));
+void CreateMetadataTask::DidSerializeIcon(std::string serialized_icon) {
+ serialized_icon_ = std::move(serialized_icon);
StoreMetadata();
}
void CreateMetadataTask::StoreMetadata() {
DCHECK(metadata_proto_);
std::vector<std::pair<std::string, std::string>> entries;
- entries.reserve(requests_.size() * 2 + 1);
+ // - One BackgroundFetchPendingRequest per request
+ // - DeveloperId -> UniqueID
+ // - BackgroundFetchMetadata
+ // - BackgroundFetchUIOptions
+ entries.reserve(requests_.size() + 3);
std::string serialized_metadata_proto;
if (!metadata_proto_->SerializeToString(&serialized_metadata_proto)) {
- FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
+ SetStorageErrorAndFinish(
+ BackgroundFetchStorageError::kServiceWorkerStorageError);
+ return;
+ }
+
+ std::string serialized_ui_options_proto;
+ proto::BackgroundFetchUIOptions ui_options;
+ ui_options.set_title(options_.title);
+ if (!serialized_icon_.empty())
+ ui_options.set_icon(std::move(serialized_icon_));
+
+ if (!ui_options.SerializeToString(&serialized_ui_options_proto)) {
+ SetStorageErrorAndFinish(
+ BackgroundFetchStorageError::kServiceWorkerStorageError);
return;
}
@@ -168,7 +183,8 @@ void CreateMetadataTask::StoreMetadata() {
registration_id_.unique_id());
entries.emplace_back(RegistrationKey(registration_id_.unique_id()),
std::move(serialized_metadata_proto));
- entries.emplace_back(TitleKey(registration_id_.unique_id()), options_.title);
+ entries.emplace_back(UIOptionsKey(registration_id_.unique_id()),
+ serialized_ui_options_proto);
// Signed integers are used for request indexes to avoid unsigned gotchas.
for (int i = 0; i < base::checked_cast<int>(requests_.size()); i++) {
@@ -194,7 +210,8 @@ void CreateMetadataTask::DidStoreMetadata(
break;
case DatabaseStatus::kFailed:
case DatabaseStatus::kNotFound:
- FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
+ SetStorageErrorAndFinish(
+ BackgroundFetchStorageError::kServiceWorkerStorageError);
return;
}
@@ -203,12 +220,36 @@ void CreateMetadataTask::DidStoreMetadata(
void CreateMetadataTask::FinishWithError(
blink::mojom::BackgroundFetchError error) {
- if (error != blink::mojom::BackgroundFetchError::NONE)
- metadata_proto_.reset();
- std::move(callback_).Run(error, std::move(metadata_proto_));
+ BackgroundFetchRegistration registration;
+
+ if (error == blink::mojom::BackgroundFetchError::NONE) {
+ DCHECK(metadata_proto_);
+
+ bool converted =
+ ToBackgroundFetchRegistration(*metadata_proto_, &registration);
+ if (!converted) {
+ // Database corrupted.
+ SetStorageErrorAndFinish(
+ BackgroundFetchStorageError::kServiceWorkerStorageError);
+ return;
+ }
+
+ for (auto& observer : data_manager()->observers()) {
+ observer.OnRegistrationCreated(registration_id_, registration, options_,
+ icon_, requests_.size());
+ }
+ }
+
+ ReportStorageError();
+
+ std::move(callback_).Run(error, registration);
Finished(); // Destroys |this|.
}
+std::string CreateMetadataTask::HistogramName() const {
+ return "CreateMetadataTask";
+}
+
} // namespace background_fetch
} // namespace content
diff --git a/chromium/content/browser/background_fetch/storage/create_metadata_task.h b/chromium/content/browser/background_fetch/storage/create_metadata_task.h
index 48bc0d59541..33307624820 100644
--- a/chromium/content/browser/background_fetch/storage/create_metadata_task.h
+++ b/chromium/content/browser/background_fetch/storage/create_metadata_task.h
@@ -17,6 +17,8 @@
namespace content {
+struct BackgroundFetchRegistration;
+
namespace background_fetch {
// Creates Background Fetch metadata entries in the database.
@@ -24,7 +26,7 @@ class CreateMetadataTask : public DatabaseTask {
public:
using CreateMetadataCallback =
base::OnceCallback<void(blink::mojom::BackgroundFetchError,
- std::unique_ptr<proto::BackgroundFetchMetadata>)>;
+ const BackgroundFetchRegistration&)>;
CreateMetadataTask(DatabaseTaskHost* host,
const BackgroundFetchRegistrationId& registration_id,
@@ -38,10 +40,14 @@ class CreateMetadataTask : public DatabaseTask {
void Start() override;
private:
+ void DidGetIsQuotaAvailable(bool is_available);
+
+ void GetRegistrationUniqueId();
+
void DidGetUniqueId(const std::vector<std::string>& data,
blink::ServiceWorkerStatusCode status);
- void StoreIcon(std::string serialized_icon);
+ void DidSerializeIcon(std::string serialized_icon);
void StoreMetadata();
@@ -52,6 +58,8 @@ class CreateMetadataTask : public DatabaseTask {
void FinishWithError(blink::mojom::BackgroundFetchError error) override;
+ std::string HistogramName() const override;
+
BackgroundFetchRegistrationId registration_id_;
std::vector<ServiceWorkerFetchRequest> requests_;
BackgroundFetchOptions options_;
@@ -60,6 +68,8 @@ class CreateMetadataTask : public DatabaseTask {
std::unique_ptr<proto::BackgroundFetchMetadata> metadata_proto_;
+ std::string serialized_icon_;
+
base::WeakPtrFactory<CreateMetadataTask> weak_factory_; // Keep as last.
DISALLOW_COPY_AND_ASSIGN(CreateMetadataTask);
diff --git a/chromium/content/browser/background_fetch/storage/database_helpers.cc b/chromium/content/browser/background_fetch/storage/database_helpers.cc
index 4e4fadf265c..691e721e6ad 100644
--- a/chromium/content/browser/background_fetch/storage/database_helpers.cc
+++ b/chromium/content/browser/background_fetch/storage/database_helpers.cc
@@ -5,6 +5,7 @@
#include "content/browser/background_fetch/storage/database_helpers.h"
#include "base/strings/string_number_conversions.h"
+#include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom.h"
namespace content {
@@ -23,8 +24,8 @@ std::string RegistrationKey(const std::string& unique_id) {
return kRegistrationKeyPrefix + unique_id;
}
-std::string TitleKey(const std::string& unique_id) {
- return kTitleKeyPrefix + unique_id;
+std::string UIOptionsKey(const std::string& unique_id) {
+ return kUIOptionsKeyPrefix + unique_id;
}
std::string PendingRequestKeyPrefix(const std::string& unique_id) {
@@ -81,12 +82,85 @@ DatabaseStatus ToDatabaseStatus(blink::ServiceWorkerStatusCode status) {
case blink::ServiceWorkerStatusCode::kErrorDiskCache:
case blink::ServiceWorkerStatusCode::kErrorRedundant:
case blink::ServiceWorkerStatusCode::kErrorDisallowed:
+ case blink::ServiceWorkerStatusCode::kErrorInvalidArguments:
break;
}
NOTREACHED();
return DatabaseStatus::kFailed;
}
+bool ToBackgroundFetchRegistration(
+ const proto::BackgroundFetchMetadata& metadata_proto,
+ BackgroundFetchRegistration* registration) {
+ DCHECK(registration);
+ const auto& registration_proto = metadata_proto.registration();
+
+ registration->developer_id = registration_proto.developer_id();
+ registration->unique_id = registration_proto.unique_id();
+ registration->upload_total = registration_proto.upload_total();
+ registration->uploaded = registration_proto.uploaded();
+ registration->download_total = registration_proto.download_total();
+ registration->downloaded = registration_proto.downloaded();
+ switch (registration_proto.state()) {
+ case proto::BackgroundFetchRegistration_BackgroundFetchState_PENDING:
+ registration->state = blink::mojom::BackgroundFetchState::PENDING;
+ break;
+ case proto::BackgroundFetchRegistration_BackgroundFetchState_FAILURE:
+ registration->state = blink::mojom::BackgroundFetchState::FAILURE;
+ break;
+ case proto::BackgroundFetchRegistration_BackgroundFetchState_SUCCESS:
+ registration->state = blink::mojom::BackgroundFetchState::SUCCESS;
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ bool did_convert = MojoFailureReasonFromRegistrationProto(
+ registration_proto.failure_reason(), &registration->failure_reason);
+ return did_convert;
+}
+
+bool MojoFailureReasonFromRegistrationProto(
+ proto::BackgroundFetchRegistration::BackgroundFetchFailureReason
+ proto_failure_reason,
+ blink::mojom::BackgroundFetchFailureReason* failure_reason) {
+ DCHECK(failure_reason);
+ switch (proto_failure_reason) {
+ case proto::BackgroundFetchRegistration::NONE:
+ *failure_reason = blink::mojom::BackgroundFetchFailureReason::NONE;
+ return true;
+ case proto::BackgroundFetchRegistration::CANCELLED_FROM_UI:
+ *failure_reason =
+ blink::mojom::BackgroundFetchFailureReason::CANCELLED_FROM_UI;
+ return true;
+ case proto::BackgroundFetchRegistration::CANCELLED_BY_DEVELOPER:
+ *failure_reason =
+ blink::mojom::BackgroundFetchFailureReason::CANCELLED_BY_DEVELOPER;
+ return true;
+ case proto::BackgroundFetchRegistration::SERVICE_WORKER_UNAVAILABLE:
+ *failure_reason = blink::mojom::BackgroundFetchFailureReason::
+ SERVICE_WORKER_UNAVAILABLE;
+ return true;
+ case proto::BackgroundFetchRegistration::QUOTA_EXCEEDED:
+ *failure_reason =
+ blink::mojom::BackgroundFetchFailureReason::QUOTA_EXCEEDED;
+ return true;
+ case proto::BackgroundFetchRegistration::TOTAL_DOWNLOAD_SIZE_EXCEEDED:
+ *failure_reason = blink::mojom::BackgroundFetchFailureReason::
+ TOTAL_DOWNLOAD_SIZE_EXCEEDED;
+ return true;
+ case proto::BackgroundFetchRegistration::FETCH_ERROR:
+ *failure_reason = blink::mojom::BackgroundFetchFailureReason::FETCH_ERROR;
+ return true;
+ case proto::BackgroundFetchRegistration::BAD_STATUS:
+ *failure_reason = blink::mojom::BackgroundFetchFailureReason::BAD_STATUS;
+ return true;
+ }
+ LOG(ERROR) << "BackgroundFetchFailureReason from the metadata proto doesn't"
+ << " match any enum value. Possible database corruption.";
+ return false;
+}
+
} // namespace background_fetch
} // namespace content
diff --git a/chromium/content/browser/background_fetch/storage/database_helpers.h b/chromium/content/browser/background_fetch/storage/database_helpers.h
index a9741fe283c..bca77cdc83d 100644
--- a/chromium/content/browser/background_fetch/storage/database_helpers.h
+++ b/chromium/content/browser/background_fetch/storage/database_helpers.h
@@ -7,7 +7,11 @@
#include <string>
+#include "content/browser/background_fetch/background_fetch.pb.h"
+#include "content/common/background_fetch/background_fetch_types.h"
+#include "content/common/content_export.h"
#include "content/common/service_worker/service_worker_types.h"
+#include "content/public/browser/background_fetch_delegate.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
namespace content {
@@ -24,16 +28,17 @@ const char kSeparator[] = "_";
const char kActiveRegistrationUniqueIdKeyPrefix[] =
"bgfetch_active_registration_unique_id_";
const char kRegistrationKeyPrefix[] = "bgfetch_registration_";
-const char kTitleKeyPrefix[] = "bgfetch_title_";
+const char kUIOptionsKeyPrefix[] = "bgfetch_ui_options_";
const char kPendingRequestKeyPrefix[] = "bgfetch_pending_request_";
const char kActiveRequestKeyPrefix[] = "bgfetch_active_request_";
const char kCompletedRequestKeyPrefix[] = "bgfetch_completed_request_";
+// Database Keys.
std::string ActiveRegistrationUniqueIdKey(const std::string& developer_id);
-std::string RegistrationKey(const std::string& unique_id);
+CONTENT_EXPORT std::string RegistrationKey(const std::string& unique_id);
-std::string TitleKey(const std::string& unique_id);
+std::string UIOptionsKey(const std::string& unique_id);
std::string PendingRequestKeyPrefix(const std::string& unique_id);
@@ -48,10 +53,21 @@ std::string CompletedRequestKeyPrefix(const std::string& unique_id);
std::string CompletedRequestKey(const std::string& unique_id,
int request_index);
+// Database status.
enum class DatabaseStatus { kOk, kFailed, kNotFound };
DatabaseStatus ToDatabaseStatus(blink::ServiceWorkerStatusCode status);
+// Converts the |metadata_proto| to a BackgroundFetchRegistration object.
+bool ToBackgroundFetchRegistration(
+ const proto::BackgroundFetchMetadata& metadata_proto,
+ BackgroundFetchRegistration* registration);
+
+bool MojoFailureReasonFromRegistrationProto(
+ proto::BackgroundFetchRegistration_BackgroundFetchFailureReason
+ proto_failure_reason,
+ blink::mojom::BackgroundFetchFailureReason* failure_reason);
+
} // namespace background_fetch
} // namespace content
diff --git a/chromium/content/browser/background_fetch/storage/database_task.cc b/chromium/content/browser/background_fetch/storage/database_task.cc
index 62a5a758c1e..0029afb1318 100644
--- a/chromium/content/browser/background_fetch/storage/database_task.cc
+++ b/chromium/content/browser/background_fetch/storage/database_task.cc
@@ -6,15 +6,33 @@
#include <utility>
+#include "base/metrics/histogram_functions.h"
#include "content/browser/background_fetch/background_fetch_data_manager.h"
#include "content/browser/background_fetch/background_fetch_data_manager_observer.h"
#include "content/browser/background_fetch/storage/database_helpers.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/public/browser/browser_thread.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
namespace content {
namespace background_fetch {
+namespace {
+
+void DidGetUsageAndQuota(DatabaseTask::IsQuotaAvailableCallback callback,
+ int64_t size,
+ blink::mojom::QuotaStatusCode status,
+ int64_t usage,
+ int64_t quota) {
+ bool is_available =
+ status == blink::mojom::QuotaStatusCode::kOk && (usage + size) <= quota;
+
+ std::move(callback).Run(is_available);
+}
+
+} // namespace
+
DatabaseTaskHost::DatabaseTaskHost() : weak_factory_(this) {}
DatabaseTaskHost::~DatabaseTaskHost() = default;
@@ -61,6 +79,57 @@ void DatabaseTask::AbandonFetches(int64_t service_worker_registration_id) {
observer.OnServiceWorkerDatabaseCorrupted(service_worker_registration_id);
}
+void DatabaseTask::IsQuotaAvailable(const url::Origin& origin,
+ int64_t size,
+ IsQuotaAvailableCallback callback) {
+ DCHECK(quota_manager_proxy());
+ DCHECK_GT(size, 0);
+ quota_manager_proxy()->GetUsageAndQuota(
+ base::ThreadTaskRunnerHandle::Get().get(), origin,
+ blink::mojom::StorageType::kTemporary,
+ base::BindOnce(&DidGetUsageAndQuota, std::move(callback), size));
+}
+
+void DatabaseTask::SetStorageError(BackgroundFetchStorageError error) {
+ DCHECK_NE(BackgroundFetchStorageError::kNone, error);
+ switch (storage_error_) {
+ case BackgroundFetchStorageError::kNone:
+ storage_error_ = error;
+ break;
+ case BackgroundFetchStorageError::kServiceWorkerStorageError:
+ case BackgroundFetchStorageError::kCacheStorageError:
+ DCHECK(error == BackgroundFetchStorageError::kServiceWorkerStorageError ||
+ error == BackgroundFetchStorageError::kCacheStorageError);
+ if (storage_error_ != error)
+ storage_error_ = BackgroundFetchStorageError::kStorageError;
+ break;
+ case BackgroundFetchStorageError::kStorageError:
+ break;
+ }
+}
+
+void DatabaseTask::SetStorageErrorAndFinish(BackgroundFetchStorageError error) {
+ SetStorageError(error);
+ FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
+}
+
+void DatabaseTask::ReportStorageError() {
+ if (host_ != data_manager())
+ return; // This is a SubTask.
+
+ base::UmaHistogramEnumeration("BackgroundFetch.Storage." + HistogramName(),
+ storage_error_);
+}
+
+bool DatabaseTask::HasStorageError() {
+ return storage_error_ != BackgroundFetchStorageError::kNone;
+}
+
+std::string DatabaseTask::HistogramName() const {
+ NOTREACHED() << "HistogramName needs to be provided.";
+ return "GeneralDatabaseTask";
+}
+
ServiceWorkerContextWrapper* DatabaseTask::service_worker_context() {
DCHECK(data_manager()->service_worker_context());
return data_manager()->service_worker_context();
@@ -83,6 +152,10 @@ BackgroundFetchDataManager* DatabaseTask::data_manager() {
return host_->data_manager();
}
+storage::QuotaManagerProxy* DatabaseTask::quota_manager_proxy() {
+ return data_manager()->quota_manager_proxy();
+}
+
} // namespace background_fetch
} // namespace content
diff --git a/chromium/content/browser/background_fetch/storage/database_task.h b/chromium/content/browser/background_fetch/storage/database_task.h
index 3d5742cfa6e..471d9ca7656 100644
--- a/chromium/content/browser/background_fetch/storage/database_task.h
+++ b/chromium/content/browser/background_fetch/storage/database_task.h
@@ -16,6 +16,14 @@
#include "content/browser/cache_storage/cache_storage_manager.h"
#include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom.h"
+namespace storage {
+class QuotaManagerProxy;
+} // namespace storage
+
+namespace url {
+class Origin;
+} // namespace url
+
namespace content {
class BackgroundFetchDataManager;
@@ -62,11 +70,23 @@ class DatabaseTaskHost {
// as they are added, and cannot outlive the parent DatabaseTask.
class DatabaseTask : public DatabaseTaskHost {
public:
+ using IsQuotaAvailableCallback =
+ base::OnceCallback<void(bool /* is_available */)>;
+
~DatabaseTask() override;
virtual void Start() = 0;
protected:
+ // This enum is append-only since it is used by UMA.
+ enum class BackgroundFetchStorageError {
+ kNone,
+ kServiceWorkerStorageError,
+ kCacheStorageError,
+ kStorageError,
+ kMaxValue = kStorageError
+ };
+
explicit DatabaseTask(DatabaseTaskHost* host);
// Each task MUST call this once finished, even if exceptions occur, to
@@ -80,25 +100,38 @@ class DatabaseTask : public DatabaseTaskHost {
// Abandon all fetches for a given service worker.
void AbandonFetches(int64_t service_worker_registration_id);
+ // Getters.
ServiceWorkerContextWrapper* service_worker_context();
-
CacheStorageManager* cache_manager();
-
std::set<std::string>& ref_counted_unique_ids();
-
ChromeBlobStorageContext* blob_storage_context();
+ storage::QuotaManagerProxy* quota_manager_proxy();
// DatabaseTaskHost implementation.
void OnTaskFinished(DatabaseTask* finished_subtask) override;
BackgroundFetchDataManager* data_manager() override;
+ // UMA reporting.
+ void SetStorageError(BackgroundFetchStorageError error);
+ void SetStorageErrorAndFinish(BackgroundFetchStorageError error);
+ void ReportStorageError();
+ bool HasStorageError();
+
+ // Quota.
+ void IsQuotaAvailable(const url::Origin& origin,
+ int64_t size,
+ IsQuotaAvailableCallback callback);
+
private:
// Each task must override this function and perform the following steps:
- // 1) Report error (UMA) if applicable.
+ // 1) Report storage error (UMA) if applicable.
// 2) Run the provided callback.
// 3) Call Finished().
virtual void FinishWithError(blink::mojom::BackgroundFetchError error) = 0;
+ // The Histogram name to report with the Error.
+ virtual std::string HistogramName() const;
+
DatabaseTaskHost* host_;
// Owns a reference to the CacheStorageManager in case Shutdown was
@@ -108,6 +141,10 @@ class DatabaseTask : public DatabaseTaskHost {
// Map the raw pointer to its unique_ptr, to make lookups easier.
std::map<DatabaseTask*, std::unique_ptr<DatabaseTask>> active_subtasks_;
+ // The storage error to report.
+ BackgroundFetchStorageError storage_error_ =
+ BackgroundFetchStorageError::kNone;
+
DISALLOW_COPY_AND_ASSIGN(DatabaseTask);
};
diff --git a/chromium/content/browser/background_fetch/storage/delete_registration_task.cc b/chromium/content/browser/background_fetch/storage/delete_registration_task.cc
index 5734680a96d..ade9a789b6f 100644
--- a/chromium/content/browser/background_fetch/storage/delete_registration_task.cc
+++ b/chromium/content/browser/background_fetch/storage/delete_registration_task.cc
@@ -57,12 +57,9 @@ DeleteRegistrationTask::~DeleteRegistrationTask() = default;
void DeleteRegistrationTask::Start() {
base::RepeatingClosure barrier_closure = base::BarrierClosure(
- 2u, base::BindOnce(
- [](base::WeakPtr<DeleteRegistrationTask> task) {
- if (task)
- task->FinishWithError(task->error_);
- },
- weak_factory_.GetWeakPtr()));
+ 2u, base::BindOnce(&DeleteRegistrationTask::FinishWithError,
+ weak_factory_.GetWeakPtr(),
+ blink::mojom::BackgroundFetchError::NONE));
#if DCHECK_IS_ON()
// Get the registration |developer_id| to check it was deactivated.
@@ -97,7 +94,7 @@ void DeleteRegistrationTask::DidGetRegistration(
base::BindOnce(&DCheckRegistrationNotActive, unique_id_));
} else {
// Service worker database has been corrupted. Abandon all fetches.
- error_ = blink::mojom::BackgroundFetchError::STORAGE_ERROR;
+ SetStorageError(BackgroundFetchStorageError::kServiceWorkerStorageError);
AbandonFetches(service_worker_registration_id_);
std::move(done_closure).Run();
}
@@ -107,7 +104,7 @@ void DeleteRegistrationTask::DidGetRegistration(
#endif // DCHECK_IS_ON()
std::vector<std::string> deletion_key_prefixes{
- RegistrationKey(unique_id_), TitleKey(unique_id_),
+ RegistrationKey(unique_id_), UIOptionsKey(unique_id_),
PendingRequestKeyPrefix(unique_id_), ActiveRequestKeyPrefix(unique_id_),
CompletedRequestKeyPrefix(unique_id_)};
@@ -125,7 +122,7 @@ void DeleteRegistrationTask::DidDeleteRegistration(
case DatabaseStatus::kNotFound:
break;
case DatabaseStatus::kFailed:
- error_ = blink::mojom::BackgroundFetchError::STORAGE_ERROR;
+ SetStorageError(BackgroundFetchStorageError::kServiceWorkerStorageError);
break;
}
std::move(done_closure).Run();
@@ -136,17 +133,24 @@ void DeleteRegistrationTask::DidDeleteCache(
blink::mojom::CacheStorageError error) {
if (error != blink::mojom::CacheStorageError::kSuccess &&
error != blink::mojom::CacheStorageError::kErrorNotFound) {
- error_ = blink::mojom::BackgroundFetchError::STORAGE_ERROR;
+ SetStorageError(BackgroundFetchStorageError::kCacheStorageError);
}
std::move(done_closure).Run();
}
void DeleteRegistrationTask::FinishWithError(
blink::mojom::BackgroundFetchError error) {
+ if (HasStorageError())
+ error = blink::mojom::BackgroundFetchError::STORAGE_ERROR;
+ ReportStorageError();
std::move(callback_).Run(error);
Finished(); // Destroys |this|.
}
+std::string DeleteRegistrationTask::HistogramName() const {
+ return "DeleteRegistrationTask";
+}
+
} // namespace background_fetch
} // namespace content
diff --git a/chromium/content/browser/background_fetch/storage/delete_registration_task.h b/chromium/content/browser/background_fetch/storage/delete_registration_task.h
index b25a7d19955..89195b80eff 100644
--- a/chromium/content/browser/background_fetch/storage/delete_registration_task.h
+++ b/chromium/content/browser/background_fetch/storage/delete_registration_task.h
@@ -43,15 +43,13 @@ class DeleteRegistrationTask : public background_fetch::DatabaseTask {
void FinishWithError(blink::mojom::BackgroundFetchError error) override;
+ std::string HistogramName() const override;
+
int64_t service_worker_registration_id_;
url::Origin origin_;
std::string unique_id_;
HandleBackgroundFetchErrorCallback callback_;
- // The error to report once all async work is completed.
- blink::mojom::BackgroundFetchError error_ =
- blink::mojom::BackgroundFetchError::NONE;
-
base::WeakPtrFactory<DeleteRegistrationTask> weak_factory_; // Keep as last.
DISALLOW_COPY_AND_ASSIGN(DeleteRegistrationTask);
diff --git a/chromium/content/browser/background_fetch/storage/get_developer_ids_task.cc b/chromium/content/browser/background_fetch/storage/get_developer_ids_task.cc
index 1f170218d83..78186816d01 100644
--- a/chromium/content/browser/background_fetch/storage/get_developer_ids_task.cc
+++ b/chromium/content/browser/background_fetch/storage/get_developer_ids_task.cc
@@ -48,17 +48,23 @@ void GetDeveloperIdsTask::DidGetUniqueIds(
break;
}
case DatabaseStatus::kFailed:
- FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
+ SetStorageErrorAndFinish(
+ BackgroundFetchStorageError::kServiceWorkerStorageError);
break;
}
}
void GetDeveloperIdsTask::FinishWithError(
blink::mojom::BackgroundFetchError error) {
+ ReportStorageError();
std::move(callback_).Run(error, std::move(developer_ids_));
Finished(); // Destroys |this|.
}
+std::string GetDeveloperIdsTask::HistogramName() const {
+ return "GetDeveloperIdsTask";
+}
+
} // namespace background_fetch
} // namespace content
diff --git a/chromium/content/browser/background_fetch/storage/get_developer_ids_task.h b/chromium/content/browser/background_fetch/storage/get_developer_ids_task.h
index e9db0880fcc..0d79dead061 100644
--- a/chromium/content/browser/background_fetch/storage/get_developer_ids_task.h
+++ b/chromium/content/browser/background_fetch/storage/get_developer_ids_task.h
@@ -40,6 +40,8 @@ class GetDeveloperIdsTask : public DatabaseTask {
void FinishWithError(blink::mojom::BackgroundFetchError error) override;
+ std::string HistogramName() const override;
+
int64_t service_worker_registration_id_;
url::Origin origin_;
diff --git a/chromium/content/browser/background_fetch/storage/get_initialization_data_task.cc b/chromium/content/browser/background_fetch/storage/get_initialization_data_task.cc
index 10db38fcd96..a5c1e3b5b5a 100644
--- a/chromium/content/browser/background_fetch/storage/get_initialization_data_task.cc
+++ b/chromium/content/browser/background_fetch/storage/get_initialization_data_task.cc
@@ -6,11 +6,13 @@
#include "base/barrier_closure.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/task_scheduler/post_task.h"
-#include "base/task_scheduler/task_traits.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
#include "content/browser/background_fetch/background_fetch.pb.h"
#include "content/browser/background_fetch/background_fetch_data_manager.h"
+#include "content/browser/background_fetch/background_fetch_request_info.h"
#include "content/browser/background_fetch/storage/database_helpers.h"
+#include "content/browser/background_fetch/storage/image_helpers.h"
#include "content/browser/background_fetch/storage/mark_registration_for_deletion_task.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "third_party/blink/public/common/manifest/manifest.h"
@@ -69,26 +71,27 @@ class InitializationSubTask : public DatabaseTask {
};
// Fills the BackgroundFetchInitializationData with the most recent UI title.
-class GetTitleTask : public InitializationSubTask {
+class GetUIOptionsTask : public InitializationSubTask {
public:
- GetTitleTask(DatabaseTaskHost* host,
- const SubTaskInit& sub_task_init,
- base::OnceClosure done_closure)
+ GetUIOptionsTask(DatabaseTaskHost* host,
+ const SubTaskInit& sub_task_init,
+ base::OnceClosure done_closure)
: InitializationSubTask(host, sub_task_init, std::move(done_closure)),
weak_factory_(this) {}
- ~GetTitleTask() override = default;
+ ~GetUIOptionsTask() override = default;
void Start() override {
service_worker_context()->GetRegistrationUserData(
sub_task_init().service_worker_registration_id,
- {TitleKey(sub_task_init().unique_id)},
- base::BindOnce(&GetTitleTask::DidGetTitle, weak_factory_.GetWeakPtr()));
+ {UIOptionsKey(sub_task_init().unique_id)},
+ base::BindOnce(&GetUIOptionsTask::DidGetUIOptions,
+ weak_factory_.GetWeakPtr()));
}
private:
- void DidGetTitle(const std::vector<std::string>& data,
- blink::ServiceWorkerStatusCode status) {
+ void DidGetUIOptions(const std::vector<std::string>& data,
+ blink::ServiceWorkerStatusCode status) {
switch (ToDatabaseStatus(status)) {
case DatabaseStatus::kFailed:
FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
@@ -98,12 +101,36 @@ class GetTitleTask : public InitializationSubTask {
break;
}
- if (!data.empty())
- sub_task_init().initialization_data->ui_title = data.front();
+ if (data.size() != 1u) {
+ FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
+ return;
+ }
+
+ proto::BackgroundFetchUIOptions ui_options;
+ if (!ui_options.ParseFromString(data[0])) {
+ FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
+ return;
+ }
+
+ if (!ui_options.title().empty())
+ sub_task_init().initialization_data->ui_title = ui_options.title();
+
+ if (!ui_options.icon().empty()) {
+ // Start an icon deserialization SubTask on another thread, then finish.
+ DeserializeIcon(std::unique_ptr<std::string>(ui_options.release_icon()),
+ base::BindOnce(&GetUIOptionsTask::DidDeserializeIcon,
+ weak_factory_.GetWeakPtr()));
+ } else {
+ FinishWithError(blink::mojom::BackgroundFetchError::NONE);
+ }
+ }
+
+ void DidDeserializeIcon(SkBitmap icon) {
+ sub_task_init().initialization_data->icon = std::move(icon);
FinishWithError(blink::mojom::BackgroundFetchError::NONE);
}
- base::WeakPtrFactory<GetTitleTask> weak_factory_; // Keep as last.
+ base::WeakPtrFactory<GetUIOptionsTask> weak_factory_; // Keep as last.
};
// Gets the number of completed fetches, the number of active fetches,
@@ -207,8 +234,16 @@ class GetRequestsTask : public InitializationSubTask {
return;
}
DCHECK_EQ(sub_task_init().unique_id, active_request.unique_id());
- sub_task_init().initialization_data->active_fetch_guids.push_back(
- active_request.download_guid());
+
+ auto request_info = base::MakeRefCounted<BackgroundFetchRequestInfo>(
+ active_request.request_index(),
+ ServiceWorkerFetchRequest::ParseFromString(
+ active_request.serialized_request()));
+ request_info->SetDownloadGuid(active_request.download_guid());
+
+ sub_task_init().initialization_data->active_fetch_requests.push_back(
+ std::move(request_info));
+
pending_requests_to_delete.push_back(PendingRequestKey(
active_request.unique_id(), active_request.request_index()));
}
@@ -243,48 +278,6 @@ class GetRequestsTask : public InitializationSubTask {
DISALLOW_COPY_AND_ASSIGN(GetRequestsTask);
};
-// Deserializes the icon and creates an SkBitmap from it.
-class DeserializeIconTask : public InitializationSubTask {
- public:
- DeserializeIconTask(DatabaseTaskHost* host,
- const SubTaskInit& sub_task_init,
- base::OnceClosure done_closure,
- std::string* serialized_icon)
- : InitializationSubTask(host, sub_task_init, std::move(done_closure)),
- serialized_icon_(serialized_icon),
- weak_factory_(this) {}
-
- ~DeserializeIconTask() override = default;
-
- void Start() override {
- base::PostTaskWithTraitsAndReplyWithResult(
- FROM_HERE,
- {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
- base::TaskPriority::BACKGROUND},
- base::BindOnce(&DeserializeIcon, std::move(serialized_icon_)),
- base::BindOnce(&DeserializeIconTask::StoreIcon,
- weak_factory_.GetWeakPtr()));
- }
-
- private:
- static SkBitmap DeserializeIcon(
- std::unique_ptr<std::string> serialized_icon) {
- return gfx::Image::CreateFrom1xPNGBytes(
- reinterpret_cast<const unsigned char*>(serialized_icon->c_str()),
- serialized_icon->size())
- .AsBitmap();
- }
-
- void StoreIcon(SkBitmap icon) {
- sub_task_init().initialization_data->icon = std::move(icon);
- FinishWithError(blink::mojom::BackgroundFetchError::NONE);
- }
-
- std::unique_ptr<std::string> serialized_icon_;
-
- base::WeakPtrFactory<DeserializeIconTask> weak_factory_; // Keep as last.
-};
-
// Fills the BackgroundFetchInitializationData with all the relevant information
// stored in the BackgroundFetchMetadata proto.
class FillFromMetadataTask : public InitializationSubTask {
@@ -382,18 +375,7 @@ class FillFromMetadataTask : public InitializationSubTask {
}
}
- if (!metadata.icon().empty()) {
- // Start an icon deserialization SubTask on another thread, then finish.
- AddSubTask(std::make_unique<DeserializeIconTask>(
- this, sub_task_init(),
- base::BindOnce(&FillFromMetadataTask::FinishWithError,
- weak_factory_.GetWeakPtr(),
- blink::mojom::BackgroundFetchError::NONE),
- metadata.release_icon()));
- } else {
- // Immediately finish.
- FinishWithError(blink::mojom::BackgroundFetchError::NONE);
- }
+ FinishWithError(blink::mojom::BackgroundFetchError::NONE);
}
base::WeakPtrFactory<FillFromMetadataTask> weak_factory_; // Keep as last.
@@ -416,9 +398,9 @@ class FillBackgroundFetchInitializationDataTask : public InitializationSubTask {
void Start() override {
// We need 3 queries to get the initialization data. These are wrapped
// in a BarrierClosure to avoid querying them serially.
- // 1. Metadata (+ icon deserialization)
+ // 1. Metadata
// 2. Request statuses and state sanitization
- // 3. UI Title
+ // 3. UI Options (+ icon deserialization)
base::RepeatingClosure barrier_closure = base::BarrierClosure(
3u,
base::BindOnce(
@@ -432,8 +414,8 @@ class FillBackgroundFetchInitializationDataTask : public InitializationSubTask {
barrier_closure));
AddSubTask(std::make_unique<GetRequestsTask>(this, sub_task_init(),
barrier_closure));
- AddSubTask(
- std::make_unique<GetTitleTask>(this, sub_task_init(), barrier_closure));
+ AddSubTask(std::make_unique<GetUIOptionsTask>(this, sub_task_init(),
+ barrier_closure));
}
private:
@@ -525,12 +507,25 @@ void GetInitializationDataTask::FinishWithError(
AddDatabaseTask(std::make_unique<MarkRegistrationForDeletionTask>(
data_manager(), data.second.registration_id, base::DoNothing()));
}
+
+ if (data.second.error ==
+ blink::mojom::BackgroundFetchError::STORAGE_ERROR) {
+ // The subtasks only access the Service Worker storage, so if there is
+ // a storage error, that would be the cause.
+ SetStorageError(BackgroundFetchStorageError::kServiceWorkerStorageError);
+ }
}
+ ReportStorageError();
+
std::move(callback_).Run(error, std::move(results));
Finished(); // Destroys |this|.
}
+std::string GetInitializationDataTask::HistogramName() const {
+ return "GetInitializationDataTask";
+}
+
} // namespace background_fetch
} // namespace content
diff --git a/chromium/content/browser/background_fetch/storage/get_initialization_data_task.h b/chromium/content/browser/background_fetch/storage/get_initialization_data_task.h
index 7946ba0a1f6..bae5662ccb6 100644
--- a/chromium/content/browser/background_fetch/storage/get_initialization_data_task.h
+++ b/chromium/content/browser/background_fetch/storage/get_initialization_data_task.h
@@ -10,6 +10,7 @@
#include <vector>
#include "base/callback.h"
+#include "base/memory/scoped_refptr.h"
#include "content/browser/background_fetch/background_fetch_registration_id.h"
#include "content/browser/background_fetch/storage/database_task.h"
#include "content/browser/service_worker/service_worker_info.h"
@@ -21,6 +22,8 @@
namespace content {
+class BackgroundFetchRequestInfo;
+
namespace background_fetch {
// All the information needed to create a JobController and resume the fetch
@@ -36,7 +39,7 @@ struct CONTENT_EXPORT BackgroundFetchInitializationData {
BackgroundFetchRegistration registration;
size_t num_requests;
size_t num_completed_requests;
- std::vector<std::string> active_fetch_guids;
+ std::vector<scoped_refptr<BackgroundFetchRequestInfo>> active_fetch_requests;
std::string ui_title;
// The error, if any, when getting the registration data.
@@ -82,6 +85,8 @@ class GetInitializationDataTask : public DatabaseTask {
void FinishWithError(blink::mojom::BackgroundFetchError error) override;
+ std::string HistogramName() const override;
+
GetInitializationDataCallback callback_;
// Map from the unique_id to the initialization data.
diff --git a/chromium/content/browser/background_fetch/storage/get_registration_task.cc b/chromium/content/browser/background_fetch/storage/get_registration_task.cc
new file mode 100644
index 00000000000..d5e9c45d2c3
--- /dev/null
+++ b/chromium/content/browser/background_fetch/storage/get_registration_task.cc
@@ -0,0 +1,74 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/background_fetch/storage/get_registration_task.h"
+
+#include "content/browser/background_fetch/background_fetch.pb.h"
+#include "content/browser/background_fetch/storage/database_helpers.h"
+#include "content/browser/background_fetch/storage/get_metadata_task.h"
+
+namespace content {
+
+namespace background_fetch {
+
+GetRegistrationTask::GetRegistrationTask(DatabaseTaskHost* host,
+ int64_t service_worker_registration_id,
+ const url::Origin& origin,
+ const std::string& developer_id,
+ GetRegistrationCallback callback)
+ : DatabaseTask(host),
+ service_worker_registration_id_(service_worker_registration_id),
+ origin_(origin),
+ developer_id_(developer_id),
+ callback_(std::move(callback)),
+ weak_factory_(this) {}
+
+GetRegistrationTask::~GetRegistrationTask() = default;
+
+void GetRegistrationTask::Start() {
+ AddSubTask(std::make_unique<GetMetadataTask>(
+ this, service_worker_registration_id_, origin_, developer_id_,
+ base::BindOnce(&GetRegistrationTask::DidGetMetadata,
+ weak_factory_.GetWeakPtr())));
+}
+
+void GetRegistrationTask::DidGetMetadata(
+ blink::mojom::BackgroundFetchError error,
+ std::unique_ptr<proto::BackgroundFetchMetadata> metadata_proto) {
+ metadata_proto_ = std::move(metadata_proto);
+ if (error == blink::mojom::BackgroundFetchError::STORAGE_ERROR)
+ SetStorageError(BackgroundFetchStorageError::kServiceWorkerStorageError);
+ FinishWithError(error);
+}
+
+void GetRegistrationTask::FinishWithError(
+ blink::mojom::BackgroundFetchError error) {
+ BackgroundFetchRegistration registration;
+
+ if (error == blink::mojom::BackgroundFetchError::NONE) {
+ DCHECK(metadata_proto_);
+
+ bool converted =
+ ToBackgroundFetchRegistration(*metadata_proto_, &registration);
+ if (!converted) {
+ // Database corrupted.
+ SetStorageErrorAndFinish(
+ BackgroundFetchStorageError::kServiceWorkerStorageError);
+ return;
+ }
+ }
+
+ ReportStorageError();
+
+ std::move(callback_).Run(error, registration);
+ Finished(); // Destroys |this|.
+}
+
+std::string GetRegistrationTask::HistogramName() const {
+ return "GetRegistrationTask";
+}
+
+} // namespace background_fetch
+
+} // namespace content
diff --git a/chromium/content/browser/background_fetch/storage/get_registration_task.h b/chromium/content/browser/background_fetch/storage/get_registration_task.h
new file mode 100644
index 00000000000..908b856807f
--- /dev/null
+++ b/chromium/content/browser/background_fetch/storage/get_registration_task.h
@@ -0,0 +1,68 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_GET_REGISTRATION_TASK_H_
+#define CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_GET_REGISTRATION_TASK_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "content/browser/background_fetch/storage/database_task.h"
+#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
+#include "url/origin.h"
+
+namespace content {
+
+namespace proto {
+class BackgroundFetchMetadata;
+}
+
+namespace background_fetch {
+
+// Gets an active Background Fetch metadata entry from the database.
+class GetRegistrationTask : public DatabaseTask {
+ public:
+ using GetRegistrationCallback =
+ base::OnceCallback<void(blink::mojom::BackgroundFetchError,
+ const BackgroundFetchRegistration&)>;
+
+ GetRegistrationTask(DatabaseTaskHost* host,
+ int64_t service_worker_registration_id,
+ const url::Origin& origin,
+ const std::string& developer_id,
+ GetRegistrationCallback callback);
+
+ ~GetRegistrationTask() override;
+
+ // DatabaseTask implementation:
+ void Start() override;
+
+ private:
+ void DidGetMetadata(
+ blink::mojom::BackgroundFetchError error,
+ std::unique_ptr<proto::BackgroundFetchMetadata> metadata_proto);
+
+ void FinishWithError(blink::mojom::BackgroundFetchError error) override;
+
+ std::string HistogramName() const override;
+
+ int64_t service_worker_registration_id_;
+ url::Origin origin_;
+ std::string developer_id_;
+
+ GetRegistrationCallback callback_;
+
+ std::unique_ptr<proto::BackgroundFetchMetadata> metadata_proto_;
+
+ base::WeakPtrFactory<GetRegistrationTask> weak_factory_; // Keep as last.
+
+ DISALLOW_COPY_AND_ASSIGN(GetRegistrationTask);
+};
+
+} // namespace background_fetch
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_GET_REGISTRATION_TASK_H_
diff --git a/chromium/content/browser/background_fetch/storage/get_settled_fetches_task.cc b/chromium/content/browser/background_fetch/storage/get_settled_fetches_task.cc
index d74d797949a..1d9a170a594 100644
--- a/chromium/content/browser/background_fetch/storage/get_settled_fetches_task.cc
+++ b/chromium/content/browser/background_fetch/storage/get_settled_fetches_task.cc
@@ -17,9 +17,11 @@ namespace background_fetch {
GetSettledFetchesTask::GetSettledFetchesTask(
DatabaseTaskHost* host,
BackgroundFetchRegistrationId registration_id,
+ std::unique_ptr<BackgroundFetchRequestMatchParams> match_params,
SettledFetchesCallback callback)
: DatabaseTask(host),
registration_id_(registration_id),
+ match_params_(std::move(match_params)),
settled_fetches_callback_(std::move(callback)),
weak_factory_(this) {}
@@ -48,8 +50,7 @@ void GetSettledFetchesTask::DidOpenCache(
CacheStorageCacheHandle handle,
blink::mojom::CacheStorageError error) {
if (error != blink::mojom::CacheStorageError::kSuccess) {
- // TODO(crbug.com/780025): Log failures to UMA.
- error_ = blink::mojom::BackgroundFetchError::STORAGE_ERROR;
+ SetStorageError(BackgroundFetchStorageError::kCacheStorageError);
} else {
DCHECK(handle.value());
handle_ = std::move(handle);
@@ -64,9 +65,8 @@ void GetSettledFetchesTask::DidGetCompletedRequests(
switch (ToDatabaseStatus(status)) {
case DatabaseStatus::kOk:
break;
- // TODO(crbug.com/780025): Log failures to UMA.
case DatabaseStatus::kFailed:
- error_ = blink::mojom::BackgroundFetchError::STORAGE_ERROR;
+ SetStorageError(BackgroundFetchStorageError::kServiceWorkerStorageError);
break;
case DatabaseStatus::kNotFound:
background_fetch_succeeded_ = false;
@@ -80,7 +80,7 @@ void GetSettledFetchesTask::DidGetCompletedRequests(
if (!completed_requests_.back().ParseFromString(
serialized_completed_request)) {
// Service worker database has been corrupted. Abandon fetches.
- error_ = blink::mojom::BackgroundFetchError::STORAGE_ERROR;
+ SetStorageError(BackgroundFetchStorageError::kServiceWorkerStorageError);
background_fetch_succeeded_ = false;
AbandonFetches(registration_id_.service_worker_registration_id());
break;
@@ -92,6 +92,11 @@ void GetSettledFetchesTask::DidGetCompletedRequests(
}
void GetSettledFetchesTask::GetResponses() {
+ // Handle potential errors.
+ if (HasStorageError()) {
+ FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
+ return;
+ }
if (error_ != blink::mojom::BackgroundFetchError::NONE) {
FinishWithError(error_);
return;
@@ -101,19 +106,42 @@ void GetSettledFetchesTask::GetResponses() {
return;
}
- base::RepeatingClosure barrier_closure = base::BarrierClosure(
- completed_requests_.size(),
- base::BindOnce(&GetSettledFetchesTask::FinishWithError,
- weak_factory_.GetWeakPtr(),
- blink::mojom::BackgroundFetchError::NONE));
+ if (!match_params_->FilterByRequest()) {
+ // No request to match against has been specified. Process all completed
+ // requests.
+ // TODO(crbug.com/863016): Process all requests here, not just the
+ // completed ones.
+ base::RepeatingClosure barrier_closure = base::BarrierClosure(
+ completed_requests_.size(),
+ base::BindOnce(&GetSettledFetchesTask::FinishWithError,
+ weak_factory_.GetWeakPtr(),
+ blink::mojom::BackgroundFetchError::NONE));
+ settled_fetches_.reserve(completed_requests_.size());
+ for (const auto& completed_request : completed_requests_) {
+ settled_fetches_.emplace_back();
+ settled_fetches_.back().request =
+ std::move(ServiceWorkerFetchRequest::ParseFromString(
+ completed_request.serialized_request()));
+ FillResponse(&settled_fetches_.back(), barrier_closure);
+ }
+ return;
+ }
- settled_fetches_.reserve(completed_requests_.size());
- for (const auto& completed_request : completed_requests_) {
- settled_fetches_.emplace_back();
- settled_fetches_.back().request =
- std::move(ServiceWorkerFetchRequest::ParseFromString(
- completed_request.serialized_request()));
- FillResponse(&settled_fetches_.back(), barrier_closure);
+ // Get response(s) only for the relevant fetch.
+ settled_fetches_.emplace_back();
+ settled_fetches_.back().request = match_params_->request_to_match();
+
+ if (match_params_->match_all()) {
+ FillResponses(base::BindOnce(&GetSettledFetchesTask::FinishWithError,
+ weak_factory_.GetWeakPtr(),
+ blink::mojom::BackgroundFetchError::NONE));
+ return;
+ } else {
+ FillResponse(&settled_fetches_.back(),
+ base::BindOnce(&GetSettledFetchesTask::FinishWithError,
+ weak_factory_.GetWeakPtr(),
+ blink::mojom::BackgroundFetchError::NONE));
+ return;
}
}
@@ -125,48 +153,115 @@ void GetSettledFetchesTask::FillResponse(
auto request =
std::make_unique<ServiceWorkerFetchRequest>(settled_fetch->request);
-
- handle_.value()->Match(std::move(request), nullptr /* match_params */,
+ handle_.value()->Match(std::move(request),
+ match_params_->cloned_cache_query_params(),
base::BindOnce(&GetSettledFetchesTask::DidMatchRequest,
weak_factory_.GetWeakPtr(),
settled_fetch, std::move(callback)));
}
+void GetSettledFetchesTask::FillResponses(base::OnceClosure callback) {
+ DCHECK(match_params_->match_all());
+ DCHECK(match_params_->FilterByRequest());
+ DCHECK(!settled_fetches_.empty());
+ DCHECK(handle_.value());
+
+ // Make a copy.
+ auto request = std::make_unique<ServiceWorkerFetchRequest>(
+ match_params_->request_to_match());
+
+ handle_.value()->MatchAll(
+ std::move(request), match_params_->cloned_cache_query_params(),
+ base::BindOnce(&GetSettledFetchesTask::DidMatchAllResponsesForRequest,
+ weak_factory_.GetWeakPtr(), std::move(callback)));
+}
+
void GetSettledFetchesTask::DidMatchRequest(
BackgroundFetchSettledFetch* settled_fetch,
base::OnceClosure callback,
blink::mojom::CacheStorageError error,
- std::unique_ptr<ServiceWorkerResponse> cache_response) {
- if (error != blink::mojom::CacheStorageError::kSuccess) {
- DCHECK(settled_fetch);
+ blink::mojom::FetchAPIResponsePtr cache_response) {
+ DCHECK(settled_fetch);
+
+ // Handle error cases.
+ if (error == blink::mojom::CacheStorageError::kErrorNotFound) {
+ // This is currently being called once a fetch finishes, or when match() is
+ // called.
+ // In the first case, not finding a response is an error state. In the
+ // second case, it just means the developer passed a non-matching request.
+ // The if condition below picks the first one.
+ // TODO(crbug.com/863016): Once we stop sending settled_fetches with
+ // BackgroundFetch events, this won't be a storage error.
+ if (!match_params_->FilterByRequest())
+ SetStorageError(BackgroundFetchStorageError::kCacheStorageError);
+ } else if (error != blink::mojom::CacheStorageError::kSuccess) {
+ SetStorageError(BackgroundFetchStorageError::kCacheStorageError);
+ }
+
+ if (!cache_response) {
FillUncachedResponse(settled_fetch, std::move(callback));
return;
}
- settled_fetch->response = std::move(*cache_response);
+ settled_fetch->response = std::move(cache_response);
+ std::move(callback).Run();
+}
+
+void GetSettledFetchesTask::DidMatchAllResponsesForRequest(
+ base::OnceClosure callback,
+ blink::mojom::CacheStorageError error,
+ std::vector<blink::mojom::FetchAPIResponsePtr> cache_responses) {
+ if (error != blink::mojom::CacheStorageError::kSuccess &&
+ error != blink::mojom::CacheStorageError::kErrorNotFound) {
+ SetStorageError(BackgroundFetchStorageError::kCacheStorageError);
+ }
+
+ if (error != blink::mojom::CacheStorageError::kSuccess) {
+ DCHECK(!settled_fetches_.empty());
+ FillUncachedResponse(&settled_fetches_.back(), std::move(callback));
+ return;
+ }
+
+ settled_fetches_.clear();
+ settled_fetches_.reserve(cache_responses.size());
+ for (size_t i = 0; i < cache_responses.size(); ++i) {
+ settled_fetches_.emplace_back();
+ settled_fetches_.back().request = match_params_->request_to_match();
+ settled_fetches_.back().response = std::move(cache_responses[i]);
+ }
std::move(callback).Run();
}
+// TODO(crbug.com/863016): Get rid of this method.
void GetSettledFetchesTask::FillUncachedResponse(
BackgroundFetchSettledFetch* settled_fetch,
base::OnceClosure callback) {
background_fetch_succeeded_ = false;
// TODO(rayankans): Fill unmatched response with error reports.
- settled_fetch->response.response_type =
+ DCHECK(!settled_fetch->response);
+ settled_fetch->response = blink::mojom::FetchAPIResponse::New();
+ settled_fetch->response->response_type =
network::mojom::FetchResponseType::kError;
- settled_fetch->response.url_list.push_back(settled_fetch->request.url);
+ settled_fetch->response->url_list.push_back(settled_fetch->request.url);
std::move(callback).Run();
}
void GetSettledFetchesTask::FinishWithError(
blink::mojom::BackgroundFetchError error) {
+ if (HasStorageError())
+ error = blink::mojom::BackgroundFetchError::STORAGE_ERROR;
+ ReportStorageError();
std::move(settled_fetches_callback_)
.Run(error, background_fetch_succeeded_, std::move(settled_fetches_),
{} /* blob_data_handles */);
Finished(); // Destroys |this|.
}
+std::string GetSettledFetchesTask::HistogramName() const {
+ return "GetSettledFetchesTask";
+};
+
} // namespace background_fetch
} // namespace content
diff --git a/chromium/content/browser/background_fetch/storage/get_settled_fetches_task.h b/chromium/content/browser/background_fetch/storage/get_settled_fetches_task.h
index 6830c21d924..2b5183a09b5 100644
--- a/chromium/content/browser/background_fetch/storage/get_settled_fetches_task.h
+++ b/chromium/content/browser/background_fetch/storage/get_settled_fetches_task.h
@@ -8,6 +8,7 @@
#include "base/callback_forward.h"
#include "base/memory/scoped_refptr.h"
#include "content/browser/background_fetch/background_fetch.pb.h"
+#include "content/browser/background_fetch/background_fetch_request_match_params.h"
#include "content/browser/background_fetch/storage/database_task.h"
#include "content/browser/cache_storage/cache_storage_cache_handle.h"
#include "storage/browser/blob/blob_data_handle.h"
@@ -15,19 +16,26 @@
namespace content {
+class BackgroundFetchRequestMatchParams;
+
namespace background_fetch {
class GetSettledFetchesTask : public DatabaseTask {
public:
+ // TODO(nator): Remove BlobDataHandle since we're not using them.
using SettledFetchesCallback = base::OnceCallback<void(
blink::mojom::BackgroundFetchError,
bool,
std::vector<BackgroundFetchSettledFetch>,
std::vector<std::unique_ptr<storage::BlobDataHandle>>)>;
- GetSettledFetchesTask(DatabaseTaskHost* host,
- BackgroundFetchRegistrationId registration_id,
- SettledFetchesCallback callback);
+ // Gets settled fetches from cache storage, filtered according to
+ // |match_params|.
+ GetSettledFetchesTask(
+ DatabaseTaskHost* host,
+ BackgroundFetchRegistrationId registration_id,
+ std::unique_ptr<BackgroundFetchRequestMatchParams> match_params,
+ SettledFetchesCallback callback);
~GetSettledFetchesTask() override;
@@ -51,14 +59,24 @@ class GetSettledFetchesTask : public DatabaseTask {
void FillResponse(BackgroundFetchSettledFetch* settled_fetch,
base::OnceClosure callback);
+ void FillResponses(base::OnceClosure callback);
+
void DidMatchRequest(BackgroundFetchSettledFetch* settled_fetch,
base::OnceClosure callback,
blink::mojom::CacheStorageError error,
- std::unique_ptr<ServiceWorkerResponse> cache_response);
+ blink::mojom::FetchAPIResponsePtr cache_response);
+
+ void DidMatchAllResponsesForRequest(
+ base::OnceClosure callback,
+ blink::mojom::CacheStorageError error,
+ std::vector<blink::mojom::FetchAPIResponsePtr> cache_responses);
void FinishWithError(blink::mojom::BackgroundFetchError error) override;
+ std::string HistogramName() const override;
+
BackgroundFetchRegistrationId registration_id_;
+ std::unique_ptr<BackgroundFetchRequestMatchParams> match_params_;
SettledFetchesCallback settled_fetches_callback_;
// SettledFetchesCallback params.
diff --git a/chromium/content/browser/background_fetch/storage/image_helpers.cc b/chromium/content/browser/background_fetch/storage/image_helpers.cc
new file mode 100644
index 00000000000..8dc2076b199
--- /dev/null
+++ b/chromium/content/browser/background_fetch/storage/image_helpers.cc
@@ -0,0 +1,72 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/background_fetch/storage/image_helpers.h"
+
+#include "base/sequenced_task_runner.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
+#include "ui/gfx/image/image.h"
+
+namespace content {
+
+namespace background_fetch {
+
+namespace {
+
+// The max icon resolution, this is used as a threshold to decide
+// whether the icon should be persisted.
+constexpr int kMaxIconResolution = 256 * 256;
+
+std::string ConvertAndSerializeIcon(const SkBitmap& icon) {
+ std::string serialized_icon;
+ auto icon_bytes = gfx::Image::CreateFrom1xBitmap(icon).As1xPNGBytes();
+ serialized_icon.assign(icon_bytes->front_as<char>(),
+ icon_bytes->front_as<char>() + icon_bytes->size());
+ return serialized_icon;
+}
+
+SkBitmap DeserializeAndConvertIcon(
+ std::unique_ptr<std::string> serialized_icon) {
+ return gfx::Image::CreateFrom1xPNGBytes(
+ reinterpret_cast<const unsigned char*>(serialized_icon->c_str()),
+ serialized_icon->size())
+ .AsBitmap();
+}
+
+} // namespace
+
+bool ShouldPersistIcon(const SkBitmap& icon) {
+ return !icon.isNull() && (icon.height() * icon.width() <= kMaxIconResolution);
+}
+
+void SerializeIcon(const SkBitmap& icon, SerializeIconCallback callback) {
+ DCHECK(!icon.isNull());
+ // Do the serialization on a seperate thread to avoid blocking on
+ // expensive operations (image conversions), then post back to current
+ // thread and continue normally.
+ base::PostTaskWithTraitsAndReplyWithResult(
+ FROM_HERE,
+ {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
+ base::TaskPriority::BEST_EFFORT},
+ base::BindOnce(&ConvertAndSerializeIcon, icon), std::move(callback));
+}
+
+void DeserializeIcon(std::unique_ptr<std::string> serialized_icon,
+ DeserializeIconCallback callback) {
+ DCHECK(serialized_icon);
+ // Do the deserialization on a seperate thread to avoid blocking on
+ // expensive operations (image conversions), then post back to current
+ // thread and continue normally.
+ base::PostTaskWithTraitsAndReplyWithResult(
+ FROM_HERE,
+ {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
+ base::TaskPriority::BEST_EFFORT},
+ base::BindOnce(&DeserializeAndConvertIcon, std::move(serialized_icon)),
+ base::BindOnce(std::move(callback)));
+}
+
+} // namespace background_fetch
+
+} // namespace content
diff --git a/chromium/content/browser/background_fetch/storage/image_helpers.h b/chromium/content/browser/background_fetch/storage/image_helpers.h
new file mode 100644
index 00000000000..b42073d4bc6
--- /dev/null
+++ b/chromium/content/browser/background_fetch/storage/image_helpers.h
@@ -0,0 +1,41 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_IMAGE_HELPERS_H_
+#define CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_IMAGE_HELPERS_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "content/common/content_export.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace content {
+
+namespace background_fetch {
+
+using SerializeIconCallback = base::OnceCallback<void(std::string)>;
+using DeserializeIconCallback = base::OnceCallback<void(SkBitmap)>;
+
+// Checks whether the icon should be stored on disk. This is only the case for
+// non-null |icon|s with a resolution of at most 256x256 pixels.
+CONTENT_EXPORT bool ShouldPersistIcon(const SkBitmap& icon);
+
+// Serializes the icon on a separate Task Runner. The |icon| will be serialized
+// as a 1x bitmap to raw PNG-encoded data
+CONTENT_EXPORT void SerializeIcon(const SkBitmap& icon,
+ SerializeIconCallback callback);
+
+// Deserializes the icon on a separate Task Runner. he |serialized_icon| must
+// contain raw PNG-encoded data, which will be decoded to a 1x bitmap.
+CONTENT_EXPORT void DeserializeIcon(
+ std::unique_ptr<std::string> serialized_icon,
+ DeserializeIconCallback callback);
+
+} // namespace background_fetch
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_IMAGE_HELPERS_H_
diff --git a/chromium/content/browser/background_fetch/storage/image_helpers_unittest.cc b/chromium/content/browser/background_fetch/storage/image_helpers_unittest.cc
new file mode 100644
index 00000000000..b0ecce7941d
--- /dev/null
+++ b/chromium/content/browser/background_fetch/storage/image_helpers_unittest.cc
@@ -0,0 +1,92 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/background_fetch/storage/image_helpers.h"
+
+#include <memory>
+#include <string>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace content {
+
+namespace background_fetch {
+
+namespace {
+
+void DidSerializeIcon(base::OnceClosure quit_closure,
+ std::string* out_icon,
+ std::string icon) {
+ DCHECK(out_icon);
+ *out_icon = std::move(icon);
+ std::move(quit_closure).Run();
+}
+
+void DidDeserializeIcon(base::OnceClosure quit_closure,
+ SkBitmap* out_icon,
+ SkBitmap icon) {
+ DCHECK(out_icon);
+ *out_icon = std::move(icon);
+ std::move(quit_closure).Run();
+}
+
+TEST(BackgroundFetchImageHelpers, ShouldPersistIcon) {
+ SkBitmap null_icon;
+ EXPECT_FALSE(ShouldPersistIcon(null_icon));
+
+ SkBitmap large_icon;
+ large_icon.allocN32Pixels(512, 512);
+ EXPECT_FALSE(ShouldPersistIcon(large_icon));
+
+ SkBitmap valid_icon;
+ valid_icon.allocN32Pixels(42, 42);
+ EXPECT_TRUE(ShouldPersistIcon(valid_icon));
+}
+
+TEST(BackgroundFetchImageHelpers, SerializeRoundTrip) {
+ base::test::ScopedTaskEnvironment scoped_task_environment;
+
+ SkBitmap icon;
+ icon.allocN32Pixels(42, 42);
+ icon.eraseColor(SK_ColorGREEN);
+
+ // Serialize.
+ std::string serialized_icon;
+ {
+ base::RunLoop run_loop;
+ SerializeIcon(icon,
+ base::BindOnce(&DidSerializeIcon, run_loop.QuitClosure(),
+ &serialized_icon));
+ run_loop.Run();
+ }
+
+ // Deserialize.
+ SkBitmap result_icon;
+ {
+ base::RunLoop run_loop;
+ DeserializeIcon(std::make_unique<std::string>(serialized_icon),
+ base::BindOnce(&DidDeserializeIcon, run_loop.QuitClosure(),
+ &result_icon));
+ run_loop.Run();
+ }
+
+ ASSERT_FALSE(result_icon.isNull());
+ EXPECT_EQ(icon.height(), result_icon.height());
+ EXPECT_EQ(icon.width(), result_icon.width());
+ for (int i = 0; i < result_icon.width(); i++) {
+ for (int j = 0; j < result_icon.height(); j++)
+ EXPECT_EQ(result_icon.getColor(i, j), SK_ColorGREEN);
+ }
+}
+
+} // namespace
+
+} // namespace background_fetch
+
+} // namespace content
diff --git a/chromium/content/browser/background_fetch/storage/mark_registration_for_deletion_task.cc b/chromium/content/browser/background_fetch/storage/mark_registration_for_deletion_task.cc
index 1f12e1a190d..6007fb6b929 100644
--- a/chromium/content/browser/background_fetch/storage/mark_registration_for_deletion_task.cc
+++ b/chromium/content/browser/background_fetch/storage/mark_registration_for_deletion_task.cc
@@ -47,7 +47,8 @@ void MarkRegistrationForDeletionTask::DidGetActiveUniqueId(
FinishWithError(blink::mojom::BackgroundFetchError::INVALID_ID);
return;
case DatabaseStatus::kFailed:
- FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
+ SetStorageErrorAndFinish(
+ BackgroundFetchStorageError::kServiceWorkerStorageError);
return;
}
@@ -75,7 +76,8 @@ void MarkRegistrationForDeletionTask::DidGetActiveUniqueId(
} else {
// Service worker database has been corrupted. Abandon fetches.
AbandonFetches(registration_id_.service_worker_registration_id());
- FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
+ SetStorageErrorAndFinish(
+ BackgroundFetchStorageError::kServiceWorkerStorageError);
return;
}
}
@@ -87,7 +89,8 @@ void MarkRegistrationForDeletionTask::DidDeactivate(
case DatabaseStatus::kNotFound:
break;
case DatabaseStatus::kFailed:
- FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
+ SetStorageErrorAndFinish(
+ BackgroundFetchStorageError::kServiceWorkerStorageError);
return;
}
@@ -100,10 +103,15 @@ void MarkRegistrationForDeletionTask::DidDeactivate(
void MarkRegistrationForDeletionTask::FinishWithError(
blink::mojom::BackgroundFetchError error) {
+ ReportStorageError();
std::move(callback_).Run(error);
Finished(); // Destroys |this|.
}
+std::string MarkRegistrationForDeletionTask::HistogramName() const {
+ return "MarkRegistrationForDeletionTask";
+}
+
} // namespace background_fetch
} // namespace content
diff --git a/chromium/content/browser/background_fetch/storage/mark_registration_for_deletion_task.h b/chromium/content/browser/background_fetch/storage/mark_registration_for_deletion_task.h
index 0c78c17f2b2..a4119559daa 100644
--- a/chromium/content/browser/background_fetch/storage/mark_registration_for_deletion_task.h
+++ b/chromium/content/browser/background_fetch/storage/mark_registration_for_deletion_task.h
@@ -37,6 +37,8 @@ class MarkRegistrationForDeletionTask : public background_fetch::DatabaseTask {
void FinishWithError(blink::mojom::BackgroundFetchError error) override;
+ std::string HistogramName() const override;
+
BackgroundFetchRegistrationId registration_id_;
HandleBackgroundFetchErrorCallback callback_;
diff --git a/chromium/content/browser/background_fetch/storage/mark_request_complete_task.cc b/chromium/content/browser/background_fetch/storage/mark_request_complete_task.cc
index f416b06e4a6..a6c9de6c61a 100644
--- a/chromium/content/browser/background_fetch/storage/mark_request_complete_task.cc
+++ b/chromium/content/browser/background_fetch/storage/mark_request_complete_task.cc
@@ -8,6 +8,7 @@
#include "base/guid.h"
#include "content/browser/background_fetch/background_fetch_cross_origin_filter.h"
#include "content/browser/background_fetch/background_fetch_data_manager.h"
+#include "content/browser/background_fetch/background_fetch_data_manager_observer.h"
#include "content/browser/background_fetch/storage/database_helpers.h"
#include "content/browser/background_fetch/storage/get_metadata_task.h"
#include "content/browser/blob_storage/chrome_blob_storage_context.h"
@@ -39,11 +40,11 @@ MarkRequestCompleteTask::MarkRequestCompleteTask(
DatabaseTaskHost* host,
BackgroundFetchRegistrationId registration_id,
scoped_refptr<BackgroundFetchRequestInfo> request_info,
- MarkedCompleteCallback callback)
+ base::OnceClosure closure)
: DatabaseTask(host),
registration_id_(registration_id),
request_info_(std::move(request_info)),
- callback_(std::move(callback)),
+ closure_(std::move(closure)),
weak_factory_(this) {}
MarkRequestCompleteTask::~MarkRequestCompleteTask() = default;
@@ -59,7 +60,7 @@ void MarkRequestCompleteTask::Start() {
}
void MarkRequestCompleteTask::StoreResponse(base::OnceClosure done_closure) {
- auto response = std::make_unique<ServiceWorkerResponse>();
+ auto response = blink::mojom::FetchAPIResponse::New();
response->url_list = request_info_->GetURLChain();
// TODO(crbug.com/838837): fill error and cors_exposed_header_names in
// response.
@@ -82,6 +83,42 @@ void MarkRequestCompleteTask::StoreResponse(base::OnceClosure done_closure) {
return;
}
+ int64_t response_size = 0;
+ if (service_worker_context()->is_incognito()) {
+ // The blob contains the size.
+ if (request_info_->GetBlobDataHandle())
+ response_size = request_info_->GetBlobDataHandle()->size();
+ } else {
+ // The file contains the size.
+ response_size = request_info_->GetFileSize();
+ }
+
+ // We need to check if there is enough quota before writing the response to
+ // the cache.
+ if (response_size > 0) {
+ IsQuotaAvailable(
+ registration_id_.origin(), response_size,
+ base::BindOnce(&MarkRequestCompleteTask::DidGetIsQuotaAvailable,
+ weak_factory_.GetWeakPtr(), std::move(response),
+ std::move(done_closure)));
+ } else {
+ // Assume there is enough quota.
+ DidGetIsQuotaAvailable(std::move(response), std::move(done_closure),
+ true /* is_available */);
+ }
+}
+
+void MarkRequestCompleteTask::DidGetIsQuotaAvailable(
+ blink::mojom::FetchAPIResponsePtr response,
+ base::OnceClosure done_closure,
+ bool is_available) {
+ if (!is_available) {
+ for (auto& observer : data_manager()->observers())
+ observer.OnQuotaExceeded(registration_id_);
+ FinishWithError(blink::mojom::BackgroundFetchError::QUOTA_EXCEEDED);
+ return;
+ }
+
cache_manager()->OpenCache(
registration_id_.origin(), CacheStorageOwner::kBackgroundFetch,
registration_id_.unique_id() /* cache_name */,
@@ -91,7 +128,7 @@ void MarkRequestCompleteTask::StoreResponse(base::OnceClosure done_closure) {
}
void MarkRequestCompleteTask::PopulateResponseBody(
- ServiceWorkerResponse* response) {
+ blink::mojom::FetchAPIResponse* response) {
// Include the status code, status text and the response's body as a blob
// when this is allowed by the CORS protocol.
response->status_code = request_info_->GetResponseCode();
@@ -126,27 +163,25 @@ void MarkRequestCompleteTask::PopulateResponseBody(
if (!blob_data_handle)
return;
- response->blob_uuid = blob_data_handle->uuid();
- response->blob_size = blob_data_handle->size();
- blink::mojom::BlobPtr blob_ptr;
+ response->blob = blink::mojom::SerializedBlob::New();
+ response->blob->uuid = blob_data_handle->uuid();
+ response->blob->size = blob_data_handle->size();
storage::BlobImpl::Create(
std::make_unique<storage::BlobDataHandle>(*blob_data_handle),
- MakeRequest(&blob_ptr));
-
- response->blob =
- base::MakeRefCounted<storage::BlobHandle>(std::move(blob_ptr));
+ MakeRequest(&response->blob->blob));
}
void MarkRequestCompleteTask::DidOpenCache(
- std::unique_ptr<ServiceWorkerResponse> response,
+ blink::mojom::FetchAPIResponsePtr response,
base::OnceClosure done_closure,
CacheStorageCacheHandle handle,
blink::mojom::CacheStorageError error) {
if (error != blink::mojom::CacheStorageError::kSuccess) {
- // TODO(crbug.com/780025): Log failures to UMA.
+ SetStorageError(BackgroundFetchStorageError::kCacheStorageError);
CreateAndStoreCompletedRequest(std::move(done_closure));
return;
}
+
DCHECK(handle.value());
auto request = std::make_unique<ServiceWorkerFetchRequest>(
@@ -165,7 +200,8 @@ void MarkRequestCompleteTask::DidWriteToCache(
CacheStorageCacheHandle handle,
base::OnceClosure done_closure,
blink::mojom::CacheStorageError error) {
- // TODO(crbug.com/780025): Log failures to UMA.
+ if (error != blink::mojom::CacheStorageError::kSuccess)
+ SetStorageError(BackgroundFetchStorageError::kCacheStorageError);
CreateAndStoreCompletedRequest(std::move(done_closure));
}
@@ -196,7 +232,7 @@ void MarkRequestCompleteTask::DidStoreCompletedRequest(
break;
case DatabaseStatus::kFailed:
case DatabaseStatus::kNotFound:
- // TODO(crbug.com/780025): Log failures to UMA.
+ SetStorageError(BackgroundFetchStorageError::kServiceWorkerStorageError);
std::move(done_closure).Run();
return;
}
@@ -213,7 +249,8 @@ void MarkRequestCompleteTask::DidStoreCompletedRequest(
void MarkRequestCompleteTask::DidDeleteActiveRequest(
base::OnceClosure done_closure,
blink::ServiceWorkerStatusCode status) {
- // TODO(crbug.com/780025): Log failures to UMA.
+ if (ToDatabaseStatus(status) != DatabaseStatus::kOk)
+ SetStorageError(BackgroundFetchStorageError::kServiceWorkerStorageError);
std::move(done_closure).Run();
}
@@ -235,7 +272,7 @@ void MarkRequestCompleteTask::DidGetMetadata(
blink::mojom::BackgroundFetchError error,
std::unique_ptr<proto::BackgroundFetchMetadata> metadata) {
if (!metadata || error != blink::mojom::BackgroundFetchError::NONE) {
- // TODO(crbug.com/780025): Log failures to UMA.
+ SetStorageError(BackgroundFetchStorageError::kServiceWorkerStorageError);
std::move(done_closure).Run();
return;
}
@@ -255,16 +292,22 @@ void MarkRequestCompleteTask::DidGetMetadata(
void MarkRequestCompleteTask::DidStoreMetadata(
base::OnceClosure done_closure,
blink::ServiceWorkerStatusCode status) {
- // TODO(crbug.com/780025): Log failures to UMA.
+ SetStorageError(BackgroundFetchStorageError::kServiceWorkerStorageError);
std::move(done_closure).Run();
}
void MarkRequestCompleteTask::FinishWithError(
blink::mojom::BackgroundFetchError error) {
- std::move(callback_).Run();
+ ReportStorageError();
+
+ std::move(closure_).Run();
Finished();
}
+std::string MarkRequestCompleteTask::HistogramName() const {
+ return "MarkRequestCompleteTask";
+}
+
} // namespace background_fetch
} // namespace content
diff --git a/chromium/content/browser/background_fetch/storage/mark_request_complete_task.h b/chromium/content/browser/background_fetch/storage/mark_request_complete_task.h
index 9e96d1db298..09e11561eb4 100644
--- a/chromium/content/browser/background_fetch/storage/mark_request_complete_task.h
+++ b/chromium/content/browser/background_fetch/storage/mark_request_complete_task.h
@@ -21,13 +21,11 @@ namespace background_fetch {
// download response in cache storage.
class MarkRequestCompleteTask : public DatabaseTask {
public:
- using MarkedCompleteCallback = base::OnceCallback<void()>;
-
MarkRequestCompleteTask(
DatabaseTaskHost* host,
BackgroundFetchRegistrationId registration_id,
scoped_refptr<BackgroundFetchRequestInfo> request_info,
- MarkedCompleteCallback callback);
+ base::OnceClosure closure);
~MarkRequestCompleteTask() override;
@@ -37,9 +35,13 @@ class MarkRequestCompleteTask : public DatabaseTask {
private:
void StoreResponse(base::OnceClosure done_closure);
- void PopulateResponseBody(ServiceWorkerResponse* response);
+ void PopulateResponseBody(blink::mojom::FetchAPIResponse* response);
+
+ void DidGetIsQuotaAvailable(blink::mojom::FetchAPIResponsePtr response,
+ base::OnceClosure done_closure,
+ bool is_available);
- void DidOpenCache(std::unique_ptr<ServiceWorkerResponse> response,
+ void DidOpenCache(blink::mojom::FetchAPIResponsePtr response,
base::OnceClosure done_closure,
CacheStorageCacheHandle handle,
blink::mojom::CacheStorageError error);
@@ -67,9 +69,11 @@ class MarkRequestCompleteTask : public DatabaseTask {
void FinishWithError(blink::mojom::BackgroundFetchError error) override;
+ std::string HistogramName() const override;
+
BackgroundFetchRegistrationId registration_id_;
scoped_refptr<BackgroundFetchRequestInfo> request_info_;
- MarkedCompleteCallback callback_;
+ base::OnceClosure closure_;
proto::BackgroundFetchCompletedRequest completed_request_;
bool is_response_successful_ = true;
@@ -83,4 +87,4 @@ class MarkRequestCompleteTask : public DatabaseTask {
} // namespace content
-#endif // CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_MARK_REQUEST_COMPLETE_TASK_H_ \ No newline at end of file
+#endif // CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_MARK_REQUEST_COMPLETE_TASK_H_
diff --git a/chromium/content/browser/background_fetch/storage/start_next_pending_request_task.cc b/chromium/content/browser/background_fetch/storage/start_next_pending_request_task.cc
index 1cc5c796f32..acccbe39878 100644
--- a/chromium/content/browser/background_fetch/storage/start_next_pending_request_task.cc
+++ b/chromium/content/browser/background_fetch/storage/start_next_pending_request_task.cc
@@ -15,15 +15,15 @@ namespace background_fetch {
StartNextPendingRequestTask::StartNextPendingRequestTask(
DatabaseTaskHost* host,
- int64_t service_worker_registration_id,
- std::unique_ptr<proto::BackgroundFetchMetadata> metadata,
+ const BackgroundFetchRegistrationId& registration_id,
+ const BackgroundFetchRegistration& registration,
NextRequestCallback callback)
: DatabaseTask(host),
- service_worker_registration_id_(service_worker_registration_id),
- metadata_(std::move(metadata)),
+ registration_id_(registration_id),
+ registration_(registration),
callback_(std::move(callback)),
weak_factory_(this) {
- DCHECK(metadata_);
+ DCHECK(!registration_id_.is_null());
}
StartNextPendingRequestTask::~StartNextPendingRequestTask() = default;
@@ -34,8 +34,8 @@ void StartNextPendingRequestTask::Start() {
void StartNextPendingRequestTask::GetPendingRequests() {
service_worker_context()->GetRegistrationUserDataByKeyPrefix(
- service_worker_registration_id_,
- PendingRequestKeyPrefix(metadata_->registration().unique_id()),
+ registration_id_.service_worker_registration_id(),
+ PendingRequestKeyPrefix(registration_.unique_id),
base::BindOnce(&StartNextPendingRequestTask::DidGetPendingRequests,
weak_factory_.GetWeakPtr()));
}
@@ -46,8 +46,8 @@ void StartNextPendingRequestTask::DidGetPendingRequests(
switch (ToDatabaseStatus(status)) {
case DatabaseStatus::kNotFound:
case DatabaseStatus::kFailed:
- // TODO(crbug.com/780025): Log failures to UMA.
- FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
+ SetStorageErrorAndFinish(
+ BackgroundFetchStorageError::kServiceWorkerStorageError);
return;
case DatabaseStatus::kOk:
if (data.empty()) {
@@ -59,15 +59,16 @@ void StartNextPendingRequestTask::DidGetPendingRequests(
if (!pending_request_.ParseFromString(data.front())) {
// Service Worker database has been corrupted. Abandon fetches.
- AbandonFetches(service_worker_registration_id_);
- FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
+ AbandonFetches(registration_id_.service_worker_registration_id());
+ SetStorageErrorAndFinish(
+ BackgroundFetchStorageError::kServiceWorkerStorageError);
return;
}
// Make sure there isn't already an Active Request.
// This might happen if the browser is killed in-between writes.
service_worker_context()->GetRegistrationUserData(
- service_worker_registration_id_,
+ registration_id_.service_worker_registration_id(),
{ActiveRequestKey(pending_request_.unique_id(),
pending_request_.request_index())},
base::BindOnce(&StartNextPendingRequestTask::DidFindActiveRequest,
@@ -79,7 +80,8 @@ void StartNextPendingRequestTask::DidFindActiveRequest(
blink::ServiceWorkerStatusCode status) {
switch (ToDatabaseStatus(status)) {
case DatabaseStatus::kFailed:
- FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
+ SetStorageErrorAndFinish(
+ BackgroundFetchStorageError::kServiceWorkerStorageError);
return;
case DatabaseStatus::kNotFound:
CreateAndStoreActiveRequest();
@@ -88,8 +90,9 @@ void StartNextPendingRequestTask::DidFindActiveRequest(
// We already stored the active request.
if (!active_request_.ParseFromString(data.front())) {
// Service worker database has been corrupted. Abandon fetches.
- AbandonFetches(service_worker_registration_id_);
- FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
+ AbandonFetches(registration_id_.service_worker_registration_id());
+ SetStorageErrorAndFinish(
+ BackgroundFetchStorageError::kServiceWorkerStorageError);
return;
}
StartDownload();
@@ -109,7 +112,8 @@ void StartNextPendingRequestTask::CreateAndStoreActiveRequest() {
pending_request_.release_serialized_request());
service_worker_context()->StoreRegistrationUserData(
- service_worker_registration_id_, GURL(metadata_->origin()),
+ registration_id_.service_worker_registration_id(),
+ registration_id_.origin().GetURL(),
{{ActiveRequestKey(active_request_.unique_id(),
active_request_.request_index()),
active_request_.SerializeAsString()}},
@@ -124,7 +128,8 @@ void StartNextPendingRequestTask::DidStoreActiveRequest(
break;
case DatabaseStatus::kFailed:
case DatabaseStatus::kNotFound:
- FinishWithError(blink::mojom::BackgroundFetchError::NONE);
+ SetStorageErrorAndFinish(
+ BackgroundFetchStorageError::kServiceWorkerStorageError);
return;
}
StartDownload();
@@ -143,7 +148,7 @@ void StartNextPendingRequestTask::StartDownload() {
// Delete the pending request.
service_worker_context()->ClearRegistrationUserData(
- service_worker_registration_id_,
+ registration_id_.service_worker_registration_id(),
{PendingRequestKey(pending_request_.unique_id(),
pending_request_.request_index())},
base::BindOnce(&StartNextPendingRequestTask::DidDeletePendingRequest,
@@ -152,17 +157,28 @@ void StartNextPendingRequestTask::StartDownload() {
void StartNextPendingRequestTask::DidDeletePendingRequest(
blink::ServiceWorkerStatusCode status) {
- // TODO(crbug.com/780025): Log failures to UMA.
- FinishWithError(blink::mojom::BackgroundFetchError::NONE);
+ if (ToDatabaseStatus(status) != DatabaseStatus::kOk) {
+ SetStorageErrorAndFinish(
+ BackgroundFetchStorageError::kServiceWorkerStorageError);
+ } else {
+ FinishWithError(blink::mojom::BackgroundFetchError::NONE);
+ }
}
void StartNextPendingRequestTask::FinishWithError(
blink::mojom::BackgroundFetchError error) {
+ ReportStorageError();
+
if (callback_)
std::move(callback_).Run(nullptr /* request */);
+
Finished(); // Destroys |this|.
}
+std::string StartNextPendingRequestTask::HistogramName() const {
+ return "StartNextPendingRequestTask";
+}
+
} // namespace background_fetch
} // namespace content
diff --git a/chromium/content/browser/background_fetch/storage/start_next_pending_request_task.h b/chromium/content/browser/background_fetch/storage/start_next_pending_request_task.h
index 89ae0fb1bdf..5faaeb00e5f 100644
--- a/chromium/content/browser/background_fetch/storage/start_next_pending_request_task.h
+++ b/chromium/content/browser/background_fetch/storage/start_next_pending_request_task.h
@@ -9,6 +9,7 @@
#include "content/browser/background_fetch/background_fetch.pb.h"
#include "content/browser/background_fetch/background_fetch_request_info.h"
#include "content/browser/background_fetch/storage/database_task.h"
+#include "content/common/background_fetch/background_fetch_types.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
namespace content {
@@ -24,8 +25,8 @@ class StartNextPendingRequestTask : public DatabaseTask {
StartNextPendingRequestTask(
DatabaseTaskHost* host,
- int64_t service_worker_registration_id,
- std::unique_ptr<proto::BackgroundFetchMetadata> metadata,
+ const BackgroundFetchRegistrationId& registration_id,
+ const BackgroundFetchRegistration& registration,
NextRequestCallback callback);
~StartNextPendingRequestTask() override;
@@ -52,8 +53,10 @@ class StartNextPendingRequestTask : public DatabaseTask {
void FinishWithError(blink::mojom::BackgroundFetchError error) override;
- int64_t service_worker_registration_id_;
- std::unique_ptr<proto::BackgroundFetchMetadata> metadata_;
+ std::string HistogramName() const override;
+
+ BackgroundFetchRegistrationId registration_id_;
+ BackgroundFetchRegistration registration_;
NextRequestCallback callback_;
// protos don't support move semantics, so these class members will be used
diff --git a/chromium/content/browser/background_fetch/storage/update_registration_ui_task.cc b/chromium/content/browser/background_fetch/storage/update_registration_ui_task.cc
index 38ad299080f..e86b2d2e0f9 100644
--- a/chromium/content/browser/background_fetch/storage/update_registration_ui_task.cc
+++ b/chromium/content/browser/background_fetch/storage/update_registration_ui_task.cc
@@ -7,6 +7,7 @@
#include "content/browser/background_fetch/background_fetch_data_manager.h"
#include "content/browser/background_fetch/background_fetch_data_manager_observer.h"
#include "content/browser/background_fetch/storage/database_helpers.h"
+#include "content/browser/background_fetch/storage/image_helpers.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom.h"
@@ -17,48 +18,113 @@ namespace background_fetch {
UpdateRegistrationUITask::UpdateRegistrationUITask(
DatabaseTaskHost* host,
const BackgroundFetchRegistrationId& registration_id,
- const std::string& updated_title,
+ const base::Optional<std::string>& title,
+ const base::Optional<SkBitmap>& icon,
UpdateRegistrationUICallback callback)
: DatabaseTask(host),
registration_id_(registration_id),
- updated_title_(updated_title),
+ title_(title),
+ icon_(icon),
callback_(std::move(callback)),
- weak_factory_(this) {}
+ weak_factory_(this) {
+ DCHECK(title_ || icon_);
+}
UpdateRegistrationUITask::~UpdateRegistrationUITask() = default;
void UpdateRegistrationUITask::Start() {
+ if (title_ && icon_ && ShouldPersistIcon(*icon_)) {
+ // Directly overwrite whatever's stored in the SWDB.
+ SerializeIcon(*icon_,
+ base::BindOnce(&UpdateRegistrationUITask::DidSerializeIcon,
+ weak_factory_.GetWeakPtr()));
+ return;
+ }
+
+ service_worker_context()->GetRegistrationUserData(
+ registration_id_.service_worker_registration_id(),
+ {UIOptionsKey(registration_id_.unique_id())},
+ base::BindOnce(&UpdateRegistrationUITask::DidGetUIOptions,
+ weak_factory_.GetWeakPtr()));
+}
+
+void UpdateRegistrationUITask::DidGetUIOptions(
+ const std::vector<std::string>& data,
+ blink::ServiceWorkerStatusCode status) {
+ switch (ToDatabaseStatus(status)) {
+ case DatabaseStatus::kFailed:
+ SetStorageErrorAndFinish(
+ BackgroundFetchStorageError::kServiceWorkerStorageError);
+ return;
+ case DatabaseStatus::kNotFound:
+ case DatabaseStatus::kOk:
+ break;
+ }
+
+ if (data.empty() || !ui_options_.ParseFromString(data[0])) {
+ SetStorageErrorAndFinish(
+ BackgroundFetchStorageError::kServiceWorkerStorageError);
+ return;
+ }
+
+ if (icon_ && ShouldPersistIcon(*icon_)) {
+ ui_options_.clear_icon();
+ SerializeIcon(*icon_,
+ base::BindOnce(&UpdateRegistrationUITask::DidSerializeIcon,
+ weak_factory_.GetWeakPtr()));
+ } else {
+ StoreUIOptions();
+ }
+}
+
+void UpdateRegistrationUITask::DidSerializeIcon(std::string serialized_icon) {
+ ui_options_.set_icon(std::move(serialized_icon));
+ StoreUIOptions();
+}
+
+void UpdateRegistrationUITask::StoreUIOptions() {
+ if (title_)
+ ui_options_.set_title(*title_);
+
service_worker_context()->StoreRegistrationUserData(
registration_id_.service_worker_registration_id(),
registration_id_.origin().GetURL(),
- {{TitleKey(registration_id_.unique_id()), updated_title_}},
- base::BindOnce(&UpdateRegistrationUITask::DidUpdateTitle,
+ {{UIOptionsKey(registration_id_.unique_id()),
+ ui_options_.SerializeAsString()}},
+ base::BindOnce(&UpdateRegistrationUITask::DidUpdateUIOptions,
weak_factory_.GetWeakPtr()));
}
-void UpdateRegistrationUITask::DidUpdateTitle(
+void UpdateRegistrationUITask::DidUpdateUIOptions(
blink::ServiceWorkerStatusCode status) {
switch (ToDatabaseStatus(status)) {
case DatabaseStatus::kOk:
break;
case DatabaseStatus::kFailed:
case DatabaseStatus::kNotFound:
- FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
+ SetStorageErrorAndFinish(
+ BackgroundFetchStorageError::kServiceWorkerStorageError);
return;
}
- for (auto& observer : data_manager()->observers())
- observer.OnUpdatedUI(registration_id_, updated_title_);
-
FinishWithError(blink::mojom::BackgroundFetchError::NONE);
}
void UpdateRegistrationUITask::FinishWithError(
blink::mojom::BackgroundFetchError error) {
+ for (auto& observer : data_manager()->observers())
+ observer.OnUpdatedUI(registration_id_, title_, icon_);
+
+ ReportStorageError();
+
std::move(callback_).Run(error);
Finished(); // Destroys |this|.
}
+std::string UpdateRegistrationUITask::HistogramName() const {
+ return "UpdateRegistrationUITask";
+}
+
} // namespace background_fetch
} // namespace content
diff --git a/chromium/content/browser/background_fetch/storage/update_registration_ui_task.h b/chromium/content/browser/background_fetch/storage/update_registration_ui_task.h
index 45a0a0fe8c5..1958f7ce24a 100644
--- a/chromium/content/browser/background_fetch/storage/update_registration_ui_task.h
+++ b/chromium/content/browser/background_fetch/storage/update_registration_ui_task.h
@@ -9,6 +9,7 @@
#include <string>
#include <vector>
+#include "base/optional.h"
#include "content/browser/background_fetch/background_fetch.pb.h"
#include "content/browser/background_fetch/storage/database_task.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
@@ -25,7 +26,8 @@ class UpdateRegistrationUITask : public DatabaseTask {
UpdateRegistrationUITask(DatabaseTaskHost* host,
const BackgroundFetchRegistrationId& registration_id,
- const std::string& updated_title,
+ const base::Optional<std::string>& title,
+ const base::Optional<SkBitmap>& icon,
UpdateRegistrationUICallback callback);
~UpdateRegistrationUITask() override;
@@ -33,12 +35,24 @@ class UpdateRegistrationUITask : public DatabaseTask {
void Start() override;
private:
- void DidUpdateTitle(blink::ServiceWorkerStatusCode status);
+ void DidGetUIOptions(const std::vector<std::string>& data,
+ blink::ServiceWorkerStatusCode status);
+
+ void DidSerializeIcon(std::string serialized_icon);
+
+ void StoreUIOptions();
+
+ void DidUpdateUIOptions(blink::ServiceWorkerStatusCode status);
void FinishWithError(blink::mojom::BackgroundFetchError error) override;
+ std::string HistogramName() const override;
+
BackgroundFetchRegistrationId registration_id_;
- std::string updated_title_;
+ base::Optional<std::string> title_;
+ base::Optional<SkBitmap> icon_;
+
+ proto::BackgroundFetchUIOptions ui_options_;
UpdateRegistrationUICallback callback_;
diff --git a/chromium/content/browser/bad_message.h b/chromium/content/browser/bad_message.h
index f5e39320ca6..aff08e3c28b 100644
--- a/chromium/content/browser/bad_message.h
+++ b/chromium/content/browser/bad_message.h
@@ -230,6 +230,8 @@ enum BadMessageReason {
PERMISSION_SERVICE_BAD_PERMISSION_DESCRIPTOR = 202,
RFH_BLOB_URL_TOKEN_FOR_NON_BLOB_URL = 203,
RFPH_BLOB_URL_TOKEN_FOR_NON_BLOB_URL = 204,
+ RFH_ERROR_PROCESS_NON_ERROR_COMMIT = 205,
+ RFH_ERROR_PROCESS_NON_UNIQUE_ORIGIN_COMMIT = 206,
// Please add new elements here. The naming convention is abbreviated class
// name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
diff --git a/chromium/content/browser/blob_storage/OWNERS b/chromium/content/browser/blob_storage/OWNERS
index 49592325cf3..6869c793a27 100644
--- a/chromium/content/browser/blob_storage/OWNERS
+++ b/chromium/content/browser/blob_storage/OWNERS
@@ -1,5 +1,9 @@
+# Primary
dmurph@chromium.org
mek@chromium.org
+# Secondary
+pwnall@chromium.org
+
# TEAM: storage-dev@chromium.org
# COMPONENT: Blink>Storage>FileAPI
diff --git a/chromium/content/browser/blob_storage/chrome_blob_storage_context.cc b/chromium/content/browser/blob_storage/chrome_blob_storage_context.cc
index 0900dbb6898..203e9c7e94a 100644
--- a/chromium/content/browser/blob_storage/chrome_blob_storage_context.cc
+++ b/chromium/content/browser/blob_storage/chrome_blob_storage_context.cc
@@ -16,8 +16,8 @@
#include "base/metrics/histogram_macros.h"
#include "base/single_thread_task_runner.h"
#include "base/supports_user_data.h"
+#include "base/task/post_task.h"
#include "base/task_runner.h"
-#include "base/task_scheduler/post_task.h"
#include "content/browser/resource_context_impl.h"
#include "content/public/browser/blob_handle.h"
#include "content/public/browser/browser_context.h"
@@ -117,7 +117,7 @@ ChromeBlobStorageContext* ChromeBlobStorageContext::GetFor(
// disk on the storage context.
if (!context->IsOffTheRecord() && io_thread_valid) {
file_task_runner = base::CreateTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::BACKGROUND,
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
// Removes our old blob directories if they exist.
BrowserThread::PostAfterStartupTask(
diff --git a/chromium/content/browser/bluetooth/bluetooth_metrics.cc b/chromium/content/browser/bluetooth/bluetooth_metrics.cc
index d6368e6548d..8b68152053c 100644
--- a/chromium/content/browser/bluetooth/bluetooth_metrics.cc
+++ b/chromium/content/browser/bluetooth/bluetooth_metrics.cc
@@ -33,8 +33,7 @@ int HashUUID(const std::string& canonical_uuid) {
// should be migrated to a dedicated histogram macro for hashed strings.
uint32_t data = base::PersistentHash(canonical_uuid);
- // Strip off the sign bit because UMA doesn't support negative values,
- // but takes a signed int as input.
+ // Strip off the sign bit to make the hash look nicer.
return static_cast<int>(data & 0x7fffffff);
}
diff --git a/chromium/content/browser/browser_child_process_host_impl.cc b/chromium/content/browser/browser_child_process_host_impl.cc
index 3fc3aa2f44c..993ba401697 100644
--- a/chromium/content/browser/browser_child_process_host_impl.cc
+++ b/chromium/content/browser/browser_child_process_host_impl.cc
@@ -61,7 +61,7 @@ static base::LazyInstance<
BrowserChildProcessHostImpl::BrowserChildProcessList>::DestructorAtExit
g_child_process_list = LAZY_INSTANCE_INITIALIZER;
-base::LazyInstance<base::ObserverList<BrowserChildProcessObserver>>::
+base::LazyInstance<base::ObserverList<BrowserChildProcessObserver>::Unchecked>::
DestructorAtExit g_browser_child_process_observers =
LAZY_INSTANCE_INITIALIZER;
@@ -186,7 +186,7 @@ BrowserChildProcessHostImpl::~BrowserChildProcessHostImpl() {
if (notify_child_disconnected_) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- base::BindOnce(&NotifyProcessHostDisconnected, data_));
+ base::BindOnce(&NotifyProcessHostDisconnected, data_.Duplicate()));
}
}
@@ -277,6 +277,7 @@ void BrowserChildProcessHostImpl::Launch(
weak_factory_.GetWeakPtr(),
base::ThreadTaskRunnerHandle::Get()),
terminate_on_shutdown));
+ ShareMetricsAllocatorToProcess();
}
const ChildProcessData& BrowserChildProcessHostImpl::GetData() const {
@@ -316,7 +317,7 @@ void BrowserChildProcessHostImpl::SetMetricsName(
void BrowserChildProcessHostImpl::SetHandle(base::ProcessHandle handle) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- data_.handle = handle;
+ data_.SetHandle(handle);
}
service_manager::mojom::ServiceRequest
@@ -358,7 +359,8 @@ ChildProcessTerminationInfo BrowserChildProcessHostImpl::GetTerminationInfo(
if (!child_process_) {
// If the delegate doesn't use Launch() helper.
ChildProcessTerminationInfo info;
- info.status = base::GetTerminationStatus(data_.handle, &info.exit_code);
+ info.status =
+ base::GetTerminationStatus(data_.GetHandle(), &info.exit_code);
return info;
}
return child_process_->GetChildTerminationInfo(known_dead);
@@ -381,16 +383,16 @@ void BrowserChildProcessHostImpl::OnChannelConnected(int32_t peer_pid) {
early_exit_watcher_.StopWatching();
#endif
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::BindOnce(&NotifyProcessHostConnected, data_));
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&NotifyProcessHostConnected, data_.Duplicate()));
delegate_->OnChannelConnected(peer_pid);
if (IsProcessLaunched()) {
- ShareMetricsAllocatorToProcess();
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- base::BindOnce(&NotifyProcessLaunchedAndConnected, data_));
+ base::BindOnce(&NotifyProcessLaunchedAndConnected, data_.Duplicate()));
}
}
@@ -435,13 +437,14 @@ void BrowserChildProcessHostImpl::OnChildDisconnected() {
// early exit watcher so GetTerminationStatus can close the process handle.
early_exit_watcher_.StopWatching();
#endif
- if (child_process_.get() || data_.handle) {
+ if (child_process_.get() || data_.GetHandle()) {
ChildProcessTerminationInfo info =
GetTerminationInfo(true /* known_dead */);
#if defined(OS_ANDROID)
delegate_->OnProcessCrashed(info.exit_code);
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::BindOnce(&NotifyProcessKilled, data_, info));
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&NotifyProcessKilled, data_.Duplicate(), info));
#else // OS_ANDROID
switch (info.status) {
case base::TERMINATION_STATUS_PROCESS_CRASHED:
@@ -449,7 +452,7 @@ void BrowserChildProcessHostImpl::OnChildDisconnected() {
delegate_->OnProcessCrashed(info.exit_code);
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- base::BindOnce(&NotifyProcessCrashed, data_, info));
+ base::BindOnce(&NotifyProcessCrashed, data_.Duplicate(), info));
UMA_HISTOGRAM_ENUMERATION("ChildProcess.Crashed2",
static_cast<ProcessType>(data_.process_type),
PROCESS_TYPE_MAX);
@@ -462,7 +465,7 @@ void BrowserChildProcessHostImpl::OnChildDisconnected() {
delegate_->OnProcessCrashed(info.exit_code);
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- base::BindOnce(&NotifyProcessKilled, data_, info));
+ base::BindOnce(&NotifyProcessKilled, data_.Duplicate(), info));
// Report that this child process was killed.
UMA_HISTOGRAM_ENUMERATION("ChildProcess.Killed2",
static_cast<ProcessType>(data_.process_type),
@@ -526,7 +529,8 @@ void BrowserChildProcessHostImpl::CreateMetricsAllocator() {
break;
case PROCESS_TYPE_GPU:
- memory_size = 64 << 10; // 64 KiB
+ // This needs to be larger for the display-compositor in the gpu process.
+ memory_size = 256 << 10; // 256 KiB
metrics_name = "GpuMetrics";
break;
@@ -600,15 +604,13 @@ void BrowserChildProcessHostImpl::OnProcessLaunched() {
early_exit_watcher_.StartWatchingOnce(process.Handle(), this);
#endif
- // TODO(rvargas) crbug.com/417532: Don't store a handle.
- data_.handle = process.Handle();
+ data_.SetHandle(process.Handle());
delegate_->OnProcessLaunched();
if (is_channel_connected_) {
- ShareMetricsAllocatorToProcess();
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- base::BindOnce(&NotifyProcessLaunchedAndConnected, data_));
+ base::BindOnce(&NotifyProcessLaunchedAndConnected, data_.Duplicate()));
}
}
diff --git a/chromium/content/browser/browser_context.cc b/chromium/content/browser/browser_context.cc
index 199a676de55..840cafc185f 100644
--- a/chromium/content/browser/browser_context.cc
+++ b/chromium/content/browser/browser_context.cc
@@ -22,7 +22,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/rand_util.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/unguessable_token.h"
@@ -43,7 +43,6 @@
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/site_instance.h"
-#include "content/public/browser/webrtc_event_logger.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/service_manager_connection.h"
#include "content/public/common/service_names.mojom.h"
@@ -396,12 +395,12 @@ void BrowserContext::DeliverPushMessage(
BrowserContext* browser_context,
const GURL& origin,
int64_t service_worker_registration_id,
- const PushEventPayload& payload,
+ base::Optional<std::string> payload,
const base::Callback<void(mojom::PushDeliveryStatus)>& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
PushMessagingRouter::DeliverMessage(browser_context, origin,
- service_worker_registration_id, payload,
- callback);
+ service_worker_registration_id,
+ std::move(payload), callback);
}
// static
@@ -588,13 +587,6 @@ void BrowserContext::Initialize(
RegisterCommonBrowserInterfaces(connection);
connection->Start();
}
-
- if (!browser_context->IsOffTheRecord()) {
- WebRtcEventLogger* const logger = WebRtcEventLogger::Get();
- if (logger) {
- logger->EnableForBrowserContext(browser_context, base::OnceClosure());
- }
- }
}
// static
@@ -647,11 +639,6 @@ BrowserContext::~BrowserContext() {
DCHECK(was_notify_will_be_destroyed_called_);
- WebRtcEventLogger* const logger = WebRtcEventLogger::Get();
- if (logger) {
- logger->DisableForBrowserContext(this, base::OnceClosure());
- }
-
RemoveBrowserContextFromUserIdMap(this);
if (GetUserData(kDownloadManagerKeyName))
@@ -694,4 +681,9 @@ media::VideoDecodePerfHistory* BrowserContext::GetVideoDecodePerfHistory() {
return decode_history;
}
+download::InProgressDownloadManager*
+BrowserContext::RetriveInProgressDownloadManager() {
+ return nullptr;
+}
+
} // namespace content
diff --git a/chromium/content/browser/browser_main_loop.cc b/chromium/content/browser/browser_main_loop.cc
index eb942391306..5cea69cfba0 100644
--- a/chromium/content/browser/browser_main_loop.cc
+++ b/chromium/content/browser/browser_main_loop.cc
@@ -38,7 +38,7 @@
#include "base/strings/string_split.h"
#include "base/synchronization/waitable_event.h"
#include "base/system_monitor/system_monitor.h"
-#include "base/task_scheduler/initialization_util.h"
+#include "base/task/task_scheduler/initialization_util.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -54,6 +54,7 @@
#include "components/tracing/common/tracing_switches.h"
#include "components/viz/common/features.h"
#include "components/viz/common/switches.h"
+#include "components/viz/host/gpu_host_impl.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "components/viz/service/display_embedder/compositing_mode_reporter_impl.h"
#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
@@ -68,7 +69,7 @@
#include "content/browser/download/download_resource_handler.h"
#include "content/browser/download/save_file_manager.h"
#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
-#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
+#include "content/browser/gpu/browser_gpu_client_delegate.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/gpu/gpu_process_host.h"
@@ -83,6 +84,7 @@
#include "content/browser/net/browser_online_state_observer.h"
#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/browser/scheduler/responsiveness/watcher.h"
#include "content/browser/service_manager/service_manager_context.h"
#include "content/browser/speech/speech_recognition_manager_impl.h"
#include "content/browser/startup_data_impl.h"
@@ -128,6 +130,8 @@
#include "ppapi/buildflags/buildflags.h"
#include "services/audio/public/cpp/audio_system_factory.h"
#include "services/audio/public/mojom/constants.mojom.h"
+#include "services/content/public/cpp/navigable_contents_view.h"
+#include "services/network/transitional_url_loader_factory_owner.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h"
#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
#include "services/resource_coordinator/public/mojom/service_constants.mojom.h"
@@ -153,6 +157,7 @@
#if defined(OS_ANDROID)
#include "base/android/jni_android.h"
+#include "base/trace_event/cpufreq_monitor_android.h"
#include "components/tracing/common/graphics_memory_dump_provider_android.h"
#include "content/browser/android/browser_startup_controller.h"
#include "content/browser/android/launcher_thread.h"
@@ -295,12 +300,8 @@ void OnStoppedStartupTracing(const base::FilePath& trace_file) {
VLOG(0) << "Completed startup tracing to " << trace_file.value();
}
-// Disable optimizations for this block of functions so the compiler doesn't
-// merge them all together. This makes it possible to tell what thread was
-// unresponsive by inspecting the callstack.
-MSVC_DISABLE_OPTIMIZE()
-MSVC_PUSH_DISABLE_WARNING(4748)
-
+// Tell compiler not to inline this function so it's possible to tell what
+// thread was unresponsive by inspecting the callstack.
NOINLINE void ResetThread_IO(
std::unique_ptr<BrowserProcessSubThread> io_thread) {
const int line_number = __LINE__;
@@ -308,9 +309,6 @@ NOINLINE void ResetThread_IO(
base::debug::Alias(&line_number);
}
-MSVC_POP_WARNING()
-MSVC_ENABLE_OPTIMIZE();
-
#if defined(OS_WIN)
// Creates a memory pressure monitor using automatic thresholds, or those
// specified on the command-line. Ownership is passed to the caller.
@@ -436,6 +434,9 @@ void SetFileUrlPathAliasForIpcFuzzer() {
}
#endif
+const base::Feature kBrowserResponsivenessCalculator{
+ "BrowserResponsivenessCalculator", base::FEATURE_DISABLED_BY_DEFAULT};
+
} // namespace
#if defined(USE_X11)
@@ -501,8 +502,9 @@ class HDRProxy {
auto* gpu_process_host =
GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, false);
if (gpu_process_host) {
- gpu_process_host->RequestHDRStatus(
- base::BindRepeating(&HDRProxy::GotResultOnIOThread));
+ auto* gpu_service = gpu_process_host->gpu_host()->gpu_service();
+ gpu_service->RequestHDRStatus(
+ base::BindOnce(&HDRProxy::GotResultOnIOThread));
} else {
bool hdr_enabled = false;
GotResultOnIOThread(hdr_enabled);
@@ -642,8 +644,7 @@ int BrowserMainLoop::EarlyInitialization() {
// Up the priority of the UI thread unless it was already high (since recent
// versions of Android (O+) do this automatically).
if (base::PlatformThread::GetCurrentThreadPriority() <
- base::ThreadPriority::DISPLAY ||
- base::FeatureList::IsEnabled(features::kOverrideUIThreadPriority)) {
+ base::ThreadPriority::DISPLAY) {
base::PlatformThread::SetCurrentThreadPriority(
base::ThreadPriority::DISPLAY);
}
@@ -757,7 +758,7 @@ void BrowserMainLoop::PostMainMessageLoopStart() {
BrowserThread::GetTaskRunnerForThread(BrowserThread::UI));
}
- if (features::IsAshInBrowserProcess()) {
+ if (!features::IsMultiProcessMash()) {
discardable_shared_memory_manager_ =
std::make_unique<discardable_memory::DiscardableSharedMemoryManager>();
// TODO(boliu): kSingleProcess check is a temporary workaround for
@@ -788,6 +789,9 @@ void BrowserMainLoop::PostMainMessageLoopStart() {
screen_orientation_delegate_.reset(
new ScreenOrientationDelegateAndroid());
}
+
+ base::trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(
+ base::trace_event::CPUFreqMonitor::GetInstance());
#endif
if (parsed_command_line_.HasSwitch(
@@ -811,6 +815,7 @@ void BrowserMainLoop::PostMainMessageLoopStart() {
skia::SkiaMemoryDumpProvider::GetInstance(), "Skia", nullptr);
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
sql::SqlMemoryDumpProvider::GetInstance(), "Sql", nullptr);
+ network::TransitionalURLLoaderFactoryOwner::DisallowUsageInProcess();
}
int BrowserMainLoop::PreCreateThreads() {
@@ -1118,9 +1123,8 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
device_monitor_mac_.reset();
#endif
- if (BrowserGpuChannelHostFactory::instance()) {
+ if (BrowserGpuChannelHostFactory::instance())
BrowserGpuChannelHostFactory::instance()->CloseChannel();
- }
// Shutdown the Service Manager and IPC.
service_manager_context_.reset();
@@ -1207,7 +1211,7 @@ void BrowserMainLoop::GetCompositingModeReporter(
// CompositingModeReporter.
return;
#else
- if (!features::IsAshInBrowserProcess()) {
+ if (features::IsUsingWindowService()) {
// Mash == ChromeOS, which doesn't support software compositing, so no need
// to report compositing mode.
return;
@@ -1242,7 +1246,7 @@ int BrowserMainLoop::BrowserThreadsStarted() {
InitializeMojo();
#if BUILDFLAG(ENABLE_MUS)
- if (!features::IsAshInBrowserProcess()) {
+ if (features::IsUsingWindowService()) {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableSurfaceSynchronization);
}
@@ -1273,11 +1277,11 @@ int BrowserMainLoop::BrowserThreadsStarted() {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::BindOnce(
- &GpuProcessHost::InitFontRenderParamsOnIO,
+ &viz::GpuHostImpl::InitFontRenderParams,
gfx::GetFontRenderParams(gfx::FontRenderParamsQuery(), nullptr)));
- // If mus is not hosting viz, then the browser must.
- bool browser_is_viz_host = features::IsAshInBrowserProcess();
+ // If ash/ws is not hosting viz, then the browser must.
+ bool browser_is_viz_host = !features::IsMultiProcessMash();
bool always_uses_gpu = true;
bool established_gpu_channel = false;
@@ -1326,7 +1330,9 @@ int BrowserMainLoop::BrowserThreadsStarted() {
}
#if defined(USE_AURA)
- if (browser_is_viz_host) {
+ // In single process mash mode the aura::Env created here uses the
+ // WindowService, and needs to use the context-factory from aura.
+ if (browser_is_viz_host && !features::IsSingleProcessMash()) {
env_->set_context_factory(GetContextFactory());
env_->set_context_factory_private(GetContextFactoryPrivate());
}
@@ -1471,6 +1477,11 @@ int BrowserMainLoop::BrowserThreadsStarted() {
SystemHotkeyHelperMac::GetInstance()->DeferredLoadSystemHotkeys();
#endif // defined(OS_MACOSX)
+ if (base::FeatureList::IsEnabled(kBrowserResponsivenessCalculator)) {
+ responsiveness_watcher_ = new responsiveness::Watcher;
+ responsiveness_watcher_->SetUp();
+ }
+
#if defined(OS_ANDROID)
media::SetMediaDrmBridgeClient(GetContentClient()->GetMediaDrmBridgeClient());
#endif
@@ -1548,9 +1559,9 @@ bool BrowserMainLoop::InitializeToolkit() {
// Env creates the compositor. Aura widgets need the compositor to be created
// before they can be initialized by the browser.
- env_ = aura::Env::CreateInstance(features::IsAshInBrowserProcess()
- ? aura::Env::Mode::LOCAL
- : aura::Env::Mode::MUS);
+ env_ = aura::Env::CreateInstance(features::IsUsingWindowService()
+ ? aura::Env::Mode::MUS
+ : aura::Env::Mode::LOCAL);
#endif // defined(USE_AURA)
if (parts_)
@@ -1597,6 +1608,10 @@ void BrowserMainLoop::InitializeMojo() {
GetContentClient()->OnServiceManagerConnected(
ServiceManagerConnection::GetForProcess());
+ // Ensure that any NavigableContentsViews constructed in the browser process
+ // know they're running in the same process as the service.
+ content::NavigableContentsView::SetClientRunningInServiceProcess();
+
tracing_controller_ = std::make_unique<content::TracingControllerImpl>();
content::BackgroundTracingManagerImpl::GetInstance()
->AddMetadataGeneratorFunction();
diff --git a/chromium/content/browser/browser_main_loop.h b/chromium/content/browser/browser_main_loop.h
index 040f1b63136..feebf19dc5f 100644
--- a/chromium/content/browser/browser_main_loop.h
+++ b/chromium/content/browser/browser_main_loop.h
@@ -102,6 +102,10 @@ class SwapMetricsDriver;
class TracingControllerImpl;
struct MainFunctionParams;
+namespace responsiveness {
+class Watcher;
+} // namespace responsiveness
+
#if defined(OS_ANDROID)
class ScreenOrientationDelegate;
#endif
@@ -370,6 +374,7 @@ class CONTENT_EXPORT BrowserMainLoop {
discardable_shared_memory_manager_;
scoped_refptr<SaveFileManager> save_file_manager_;
std::unique_ptr<content::TracingControllerImpl> tracing_controller_;
+ scoped_refptr<responsiveness::Watcher> responsiveness_watcher_;
#if !defined(OS_ANDROID)
// A SharedBitmapManager used to sharing and mapping IDs to shared memory
// between processes for software compositing. When the display compositor is
diff --git a/chromium/content/browser/browser_main_loop_unittest.cc b/chromium/content/browser/browser_main_loop_unittest.cc
index 46955a01c56..a4bebc6547d 100644
--- a/chromium/content/browser/browser_main_loop_unittest.cc
+++ b/chromium/content/browser/browser_main_loop_unittest.cc
@@ -7,7 +7,7 @@
#include "base/command_line.h"
#include "base/message_loop/message_loop.h"
#include "base/sys_info.h"
-#include "base/task_scheduler/task_scheduler.h"
+#include "base/task/task_scheduler/task_scheduler.h"
#include "base/test/scoped_command_line.h"
#include "content/browser/browser_thread_impl.h"
#include "content/public/browser/browser_thread.h"
diff --git a/chromium/content/browser/browser_main_runner_impl.cc b/chromium/content/browser/browser_main_runner_impl.cc
index e0c7136869b..94dc07ff40b 100644
--- a/chromium/content/browser/browser_main_runner_impl.cc
+++ b/chromium/content/browser/browser_main_runner_impl.cc
@@ -75,10 +75,9 @@ int BrowserMainRunnerImpl::Initialize(const MainFunctionParams& parameters) {
const base::TimeTicks start_time_step1 = base::TimeTicks::Now();
- base::SamplingHeapProfiler::InitTLSSlot();
+ base::SamplingHeapProfiler::Init();
if (parameters.command_line.HasSwitch(switches::kSamplingHeapProfiler)) {
- base::SamplingHeapProfiler* profiler =
- base::SamplingHeapProfiler::GetInstance();
+ base::SamplingHeapProfiler* profiler = base::SamplingHeapProfiler::Get();
unsigned sampling_interval = 0;
bool parsed =
base::StringToUint(parameters.command_line.GetSwitchValueASCII(
@@ -183,7 +182,7 @@ void BrowserMainRunnerImpl::Shutdown() {
// startup tracing becomes a version of shutdown tracing).
// There are two cases:
// 1. Startup duration is not reached.
- // 2. Or startup duration is not specified for --trace-config-file flag.
+ // 2. Or if the trace should be saved to file for --trace-config-file flag.
std::unique_ptr<BrowserShutdownProfileDumper> startup_profiler;
if (tracing::TraceStartupConfig::GetInstance()
->IsTracingStartupForDuration()) {
@@ -193,7 +192,8 @@ void BrowserMainRunnerImpl::Shutdown() {
startup_profiler.reset(
new BrowserShutdownProfileDumper(main_loop_->startup_trace_file()));
}
- } else if (tracing::TraceStartupConfig::GetInstance()->IsEnabled()) {
+ } else if (tracing::TraceStartupConfig::GetInstance()
+ ->ShouldTraceToResultFile()) {
base::FilePath result_file = main_loop_->GetStartupTraceFileName();
startup_profiler.reset(new BrowserShutdownProfileDumper(result_file));
}
diff --git a/chromium/content/browser/browser_plugin/browser_plugin_guest.cc b/chromium/content/browser/browser_plugin/browser_plugin_guest.cc
index f56ce93c3d5..e5f885ab4bc 100644
--- a/chromium/content/browser/browser_plugin/browser_plugin_guest.cc
+++ b/chromium/content/browser/browser_plugin/browser_plugin_guest.cc
@@ -16,6 +16,7 @@
#include "base/pickle.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "components/viz/common/features.h"
#include "components/viz/common/surfaces/surface_info.h"
#include "components/viz/service/surfaces/surface.h"
#include "content/browser/browser_plugin/browser_plugin_embedder.h"
@@ -408,7 +409,8 @@ void BrowserPluginGuest::PointerLockPermissionResponse(bool allow) {
void BrowserPluginGuest::FirstSurfaceActivation(
const viz::SurfaceInfo& surface_info) {
- if (features::IsAshInBrowserProcess()) {
+ if (!features::IsUsingWindowService() &&
+ !features::IsSurfaceSynchronizationEnabled()) {
SendMessageToEmbedder(
std::make_unique<BrowserPluginMsg_FirstSurfaceActivation>(
browser_plugin_instance_id(), surface_info));
@@ -436,6 +438,10 @@ void BrowserPluginGuest::ResendEventToEmbedder(
ui::LatencyInfo latency_info =
ui::WebInputEventTraits::CreateLatencyInfoForWebGestureEvent(
resent_gesture_event);
+ // The touch action may not be set for the embedder because the
+ // GestureScrollBegin is sent to the guest view. In this case, set the touch
+ // action of the embedder to Auto to prevent crash.
+ GetOwnerRenderWidgetHost()->input_router()->ForceSetTouchActionAuto();
view->ProcessGestureEvent(resent_gesture_event, latency_info);
} else if (event.GetType() == blink::WebInputEvent::kMouseWheel) {
blink::WebMouseWheelEvent resent_wheel_event;
@@ -661,7 +667,7 @@ void BrowserPluginGuest::RenderViewReady() {
// In case we've created a new guest render process after a crash, let the
// associated BrowserPlugin know. We only need to send this if we're attached,
// as guest_crashed_ is cleared automatically on attach anyways.
- if (attached() && features::IsAshInBrowserProcess()) {
+ if (attached() && !features::IsUsingWindowService()) {
RenderWidgetHostViewGuest* rwhv = static_cast<RenderWidgetHostViewGuest*>(
web_contents()->GetRenderWidgetHostView());
if (rwhv) {
@@ -764,11 +770,12 @@ void BrowserPluginGuest::Attach(
// change embedders before attach completes. If the embedder goes away,
// so does the guest and so we will never call WillAttachComplete because
// we have a weak ptr.
- delegate_->WillAttach(embedder_web_contents, browser_plugin_instance_id,
- params.is_full_page_plugin,
- base::Bind(&BrowserPluginGuest::OnWillAttachComplete,
- weak_ptr_factory_.GetWeakPtr(),
- embedder_web_contents, params));
+ delegate_->WillAttach(
+ embedder_web_contents, browser_plugin_instance_id,
+ params.is_full_page_plugin,
+ base::BindOnce(&BrowserPluginGuest::OnWillAttachComplete,
+ weak_ptr_factory_.GetWeakPtr(), embedder_web_contents,
+ params));
}
void BrowserPluginGuest::OnWillAttachComplete(
@@ -916,7 +923,7 @@ void BrowserPluginGuest::OnImeCommitText(
->GetWidget()
->GetWidgetInputHandler()
->ImeCommitText(text, ui_ime_text_spans, replacement_range,
- relative_cursor_pos);
+ relative_cursor_pos, base::OnceClosure());
}
void BrowserPluginGuest::OnImeFinishComposingText(
diff --git a/chromium/content/browser/browser_process_sub_thread.cc b/chromium/content/browser/browser_process_sub_thread.cc
index 876318dc799..9172012c111 100644
--- a/chromium/content/browser/browser_process_sub_thread.cc
+++ b/chromium/content/browser/browser_process_sub_thread.cc
@@ -11,7 +11,6 @@
#include "base/trace_event/memory_dump_manager.h"
#include "content/browser/browser_child_process_host_impl.h"
#include "content/browser/browser_thread_impl.h"
-#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
#include "content/browser/notification_service_impl.h"
#include "content/browser/utility_process_host.h"
#include "content/common/child_process_host_impl.h"
@@ -162,10 +161,8 @@ void BrowserProcessSubThread::CompleteInitializationOnBrowserThread() {
}
}
-// We disable optimizations for Run specifications so the compiler doesn't merge
-// them all together.
-MSVC_DISABLE_OPTIMIZE()
-MSVC_PUSH_DISABLE_WARNING(4748)
+// Mark following two functions as NOINLINE so the compiler doesn't merge
+// them together.
NOINLINE void BrowserProcessSubThread::UIThreadRun(base::RunLoop* run_loop) {
const int line_number = __LINE__;
@@ -179,9 +176,6 @@ NOINLINE void BrowserProcessSubThread::IOThreadRun(base::RunLoop* run_loop) {
base::debug::Alias(&line_number);
}
-MSVC_POP_WARNING()
-MSVC_ENABLE_OPTIMIZE();
-
void BrowserProcessSubThread::IOThreadCleanUp() {
DCHECK_CALLED_ON_VALID_THREAD(browser_thread_checker_);
@@ -222,10 +216,6 @@ void BrowserProcessSubThread::IOThreadCleanUp() {
// and delete the BrowserChildProcessHost instances to release whatever
// IO thread only resources they are referencing.
BrowserChildProcessHostImpl::TerminateAll();
-
- // Unregister GpuMemoryBuffer dump provider before IO thread is shut down.
- base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
- BrowserGpuMemoryBufferManager::current());
}
} // namespace content
diff --git a/chromium/content/browser/browser_side_navigation_browsertest.cc b/chromium/content/browser/browser_side_navigation_browsertest.cc
index b4cf78fea84..852370df647 100644
--- a/chromium/content/browser/browser_side_navigation_browsertest.cc
+++ b/chromium/content/browser/browser_side_navigation_browsertest.cc
@@ -422,7 +422,7 @@ IN_PROC_BROWSER_TEST_F(BrowserSideNavigationBrowserTest,
shell()->web_contents()->GetMainFrame());
// Prepare a file for the upload form.
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_temp_dir;
+ base::ScopedAllowBlockingForTesting allow_blocking;
base::ScopedTempDir temp_dir;
base::FilePath file_path;
std::string file_content("test-file-content");
diff --git a/chromium/content/browser/browser_thread_browsertest.cc b/chromium/content/browser/browser_thread_browsertest.cc
new file mode 100644
index 00000000000..25bf7fcd3a6
--- /dev/null
+++ b/chromium/content/browser/browser_thread_browsertest.cc
@@ -0,0 +1,51 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind_helpers.h"
+#include "base/task/post_task.h"
+#include "base/test/gtest_util.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/content_browser_test.h"
+
+namespace content {
+
+class BrowserThreadPostTaskBeforeInitBrowserTest : public ContentBrowserTest {
+ protected:
+ void SetUp() override {
+ // This should fail because the TaskScheduler + TaskExecutor weren't created
+ // yet.
+ EXPECT_DCHECK_DEATH(base::PostTaskWithTraits(FROM_HERE, {BrowserThread::IO},
+ base::DoNothing()));
+
+ // Obtaining a TaskRunner should also fail.
+ EXPECT_DCHECK_DEATH(base::CreateTaskRunnerWithTraits({BrowserThread::IO}));
+
+ ContentBrowserTest::SetUp();
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(BrowserThreadPostTaskBeforeInitBrowserTest,
+ ExpectFailures) {}
+
+class BrowserThreadPostTaskBeforeThreadCreationBrowserTest
+ : public ContentBrowserTest {
+ protected:
+ void CreatedBrowserMainParts(BrowserMainParts* browser_main_parts) override {
+ // This should fail because the IO thread hasn't been initialized yet.
+ EXPECT_DCHECK_DEATH(base::PostTaskWithTraits(FROM_HERE, {BrowserThread::IO},
+ base::DoNothing()));
+
+ // Obtaining a TaskRunner should work, because the TaskExecutor was
+ // registered already.
+ auto task_runner = base::CreateTaskRunnerWithTraits({BrowserThread::IO});
+ // But posting should still fail.
+ EXPECT_DCHECK_DEATH(task_runner->PostTask(FROM_HERE, base::DoNothing()));
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(BrowserThreadPostTaskBeforeThreadCreationBrowserTest,
+ ExpectFailures) {}
+
+} // namespace content
diff --git a/chromium/content/browser/browser_thread_impl.cc b/chromium/content/browser/browser_thread_impl.cc
index 4443c7bbc4c..d90d84982a4 100644
--- a/chromium/content/browser/browser_thread_impl.cc
+++ b/chromium/content/browser/browser_thread_impl.cc
@@ -15,9 +15,11 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/sequence_checker.h"
+#include "base/task/task_executor.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "build/build_config.h"
+#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/content_browser_client.h"
namespace content {
@@ -161,6 +163,68 @@ bool PostTaskHelper(BrowserThread::ID identifier,
}
}
+class BrowserThreadTaskExecutor : public base::TaskExecutor {
+ public:
+ BrowserThreadTaskExecutor() {}
+ ~BrowserThreadTaskExecutor() override {}
+
+ // base::TaskExecutor implementation.
+ bool PostDelayedTaskWithTraits(const base::Location& from_here,
+ const base::TaskTraits& traits,
+ base::OnceClosure task,
+ base::TimeDelta delay) override {
+ return PostTaskHelper(
+ GetBrowserThreadIdentifier(traits), from_here, std::move(task), delay,
+ traits.GetExtension<BrowserTaskTraitsExtension>().nestable());
+ }
+
+ scoped_refptr<base::TaskRunner> CreateTaskRunnerWithTraits(
+ const base::TaskTraits& traits) override {
+ return GetTaskRunnerForThread(GetBrowserThreadIdentifier(traits));
+ }
+
+ scoped_refptr<base::SequencedTaskRunner> CreateSequencedTaskRunnerWithTraits(
+ const base::TaskTraits& traits) override {
+ return GetTaskRunnerForThread(GetBrowserThreadIdentifier(traits));
+ }
+
+ scoped_refptr<base::SingleThreadTaskRunner>
+ CreateSingleThreadTaskRunnerWithTraits(
+ const base::TaskTraits& traits,
+ base::SingleThreadTaskRunnerThreadMode thread_mode) override {
+ // It's not possible to request DEDICATED access to a BrowserThread.
+ DCHECK_EQ(thread_mode, base::SingleThreadTaskRunnerThreadMode::SHARED);
+ return GetTaskRunnerForThread(GetBrowserThreadIdentifier(traits));
+ }
+
+#if defined(OS_WIN)
+ scoped_refptr<base::SingleThreadTaskRunner> CreateCOMSTATaskRunnerWithTraits(
+ const base::TaskTraits& traits,
+ base::SingleThreadTaskRunnerThreadMode thread_mode) override {
+ // Only the UI thread supports COM.
+ DCHECK_EQ(GetBrowserThreadIdentifier(traits), BrowserThread::UI);
+ return CreateSingleThreadTaskRunnerWithTraits(traits, thread_mode);
+ }
+#endif // defined(OS_WIN)
+
+ private:
+ BrowserThread::ID GetBrowserThreadIdentifier(const base::TaskTraits& traits) {
+ DCHECK_EQ(traits.extension_id(), BrowserTaskTraitsExtension::kExtensionId);
+ BrowserThread::ID id =
+ traits.GetExtension<BrowserTaskTraitsExtension>().browser_thread();
+ DCHECK_LT(id, BrowserThread::ID_COUNT);
+ return id;
+ }
+
+ scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunnerForThread(
+ BrowserThread::ID identifier) {
+ return g_task_runners.Get().proxies[identifier];
+ }
+};
+
+// |g_browser_thread_task_executor| is intentionally leaked on shutdown.
+BrowserThreadTaskExecutor* g_browser_thread_task_executor = nullptr;
+
} // namespace
BrowserThreadImpl::BrowserThreadImpl(
@@ -339,4 +403,21 @@ BrowserThread::GetTaskRunnerForThread(ID identifier) {
return g_task_runners.Get().proxies[identifier];
}
+// static
+void BrowserThreadImpl::CreateTaskExecutor() {
+ DCHECK(!g_browser_thread_task_executor);
+ g_browser_thread_task_executor = new BrowserThreadTaskExecutor();
+ base::RegisterTaskExecutor(BrowserTaskTraitsExtension::kExtensionId,
+ g_browser_thread_task_executor);
+}
+
+// static
+void BrowserThreadImpl::ResetTaskExecutorForTesting() {
+ DCHECK(g_browser_thread_task_executor);
+ base::UnregisterTaskExecutorForTesting(
+ BrowserTaskTraitsExtension::kExtensionId);
+ delete g_browser_thread_task_executor;
+ g_browser_thread_task_executor = nullptr;
+}
+
} // namespace content
diff --git a/chromium/content/browser/browser_thread_impl.h b/chromium/content/browser/browser_thread_impl.h
index cd0759c3f58..5789a29e1c5 100644
--- a/chromium/content/browser/browser_thread_impl.h
+++ b/chromium/content/browser/browser_thread_impl.h
@@ -39,6 +39,13 @@ class CONTENT_EXPORT BrowserThreadImpl : public BrowserThread {
// |identifier|.
static void ResetGlobalsForTesting(BrowserThread::ID identifier);
+ // Creates and registers a TaskExecutor that facilitates posting tasks to a
+ // BrowserThread via //base/task/post_task.h.
+ static void CreateTaskExecutor();
+
+ // Unregister and delete the TaskExecutor after a test.
+ static void ResetTaskExecutorForTesting();
+
private:
// Restrict instantiation to BrowserProcessSubThread as it performs important
// initialization that shouldn't be bypassed (except by BrowserMainLoop for
diff --git a/chromium/content/browser/browser_thread_unittest.cc b/chromium/content/browser/browser_thread_unittest.cc
index cf5b1635992..f27b5b97f7f 100644
--- a/chromium/content/browser/browser_thread_unittest.cc
+++ b/chromium/content/browser/browser_thread_unittest.cc
@@ -12,9 +12,13 @@
#include "base/run_loop.h"
#include "base/sequenced_task_runner_helpers.h"
#include "base/single_thread_task_runner.h"
+#include "base/task/post_task.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
#include "content/browser/browser_process_sub_thread.h"
#include "content/browser/browser_thread_impl.h"
+#include "content/public/browser/browser_task_traits.h"
#include "content/public/test/test_browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -33,6 +37,8 @@ class BrowserThreadTest : public testing::Test {
protected:
void SetUp() override {
+ BrowserThreadImpl::CreateTaskExecutor();
+
ui_thread_ = std::make_unique<BrowserProcessSubThread>(BrowserThread::UI);
ui_thread_->Start();
@@ -51,6 +57,7 @@ class BrowserThreadTest : public testing::Test {
BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::UI);
BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::IO);
+ BrowserThreadImpl::ResetTaskExecutorForTesting();
}
// Prepares this BrowserThreadTest for Release() to be invoked. |on_release|
@@ -59,8 +66,9 @@ class BrowserThreadTest : public testing::Test {
on_release_ = std::move(on_release);
}
- static void BasicFunction(base::OnceClosure continuation) {
- EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ static void BasicFunction(base::OnceClosure continuation,
+ BrowserThread::ID target) {
+ EXPECT_TRUE(BrowserThread::CurrentlyOn(target));
std::move(continuation).Run();
}
@@ -87,7 +95,7 @@ class BrowserThreadTest : public testing::Test {
std::unique_ptr<BrowserProcessSubThread> ui_thread_;
std::unique_ptr<BrowserProcessSubThread> io_thread_;
- base::MessageLoop loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
// Must be set before Release() to verify the deletion is intentional. Will be
// run from the next call to Release(). mutable so it can be consumed from
// Release().
@@ -136,7 +144,17 @@ TEST_F(BrowserThreadTest, PostTask) {
base::RunLoop run_loop;
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure()));
+ base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
+ BrowserThread::IO));
+ run_loop.Run();
+}
+
+TEST_F(BrowserThreadTest, PostTaskWithTraits) {
+ base::RunLoop run_loop;
+ EXPECT_TRUE(base::PostTaskWithTraits(
+ FROM_HERE, {BrowserThread::IO, NonNestable()},
+ base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
+ BrowserThread::IO)));
run_loop.Run();
}
@@ -161,11 +179,53 @@ TEST_F(BrowserThreadTest, PostTaskViaTaskRunner) {
BrowserThread::GetTaskRunnerForThread(BrowserThread::IO);
base::RunLoop run_loop;
task_runner->PostTask(
- FROM_HERE,
- base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure()));
+ FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
+ BrowserThread::IO));
+ run_loop.Run();
+}
+
+TEST_F(BrowserThreadTest, PostTaskViaTaskRunnerWithTraits) {
+ scoped_refptr<base::TaskRunner> task_runner =
+ base::CreateTaskRunnerWithTraits({BrowserThread::IO});
+ base::RunLoop run_loop;
+ EXPECT_TRUE(task_runner->PostTask(
+ FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
+ BrowserThread::IO)));
+ run_loop.Run();
+}
+
+TEST_F(BrowserThreadTest, PostTaskViaSequencedTaskRunnerWithTraits) {
+ scoped_refptr<base::SequencedTaskRunner> task_runner =
+ base::CreateSequencedTaskRunnerWithTraits({BrowserThread::IO});
+ base::RunLoop run_loop;
+ EXPECT_TRUE(task_runner->PostTask(
+ FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
+ BrowserThread::IO)));
+ run_loop.Run();
+}
+
+TEST_F(BrowserThreadTest, PostTaskViaSingleThreadTaskRunnerWithTraits) {
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO});
+ base::RunLoop run_loop;
+ EXPECT_TRUE(task_runner->PostTask(
+ FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
+ BrowserThread::IO)));
run_loop.Run();
}
+#if defined(OS_WIN)
+TEST_F(BrowserThreadTest, PostTaskViaCOMSTATaskRunnerWithTraits) {
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ base::CreateCOMSTATaskRunnerWithTraits({BrowserThread::UI});
+ base::RunLoop run_loop;
+ EXPECT_TRUE(task_runner->PostTask(
+ FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
+ BrowserThread::UI)));
+ run_loop.Run();
+}
+#endif // defined(OS_WIN)
+
TEST_F(BrowserThreadTest, ReleaseViaTaskRunner) {
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
BrowserThread::GetTaskRunnerForThread(BrowserThread::UI);
@@ -176,6 +236,15 @@ TEST_F(BrowserThreadTest, ReleaseViaTaskRunner) {
run_loop.Run();
}
+TEST_F(BrowserThreadTest, ReleaseViaTaskRunnerWithTraits) {
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::UI});
+ base::RunLoop run_loop;
+ ExpectRelease(run_loop.QuitWhenIdleClosure());
+ task_runner->ReleaseSoon(FROM_HERE, this);
+ run_loop.Run();
+}
+
TEST_F(BrowserThreadTest, PostTaskAndReply) {
// Most of the heavy testing for PostTaskAndReply() is done inside the
// task runner test. This just makes sure we get piped through at all.
@@ -186,6 +255,16 @@ TEST_F(BrowserThreadTest, PostTaskAndReply) {
run_loop.Run();
}
+TEST_F(BrowserThreadTest, PostTaskAndReplyWithTraits) {
+ // Most of the heavy testing for PostTaskAndReply() is done inside the
+ // task runner test. This just makes sure we get piped through at all.
+ base::RunLoop run_loop;
+ ASSERT_TRUE(base::PostTaskWithTraitsAndReply(FROM_HERE, {BrowserThread::IO},
+ base::DoNothing(),
+ run_loop.QuitWhenIdleClosure()));
+ run_loop.Run();
+}
+
TEST_F(BrowserThreadTest, RunsTasksInCurrentSequencedDuringShutdown) {
bool did_shutdown = false;
base::RunLoop loop;
diff --git a/chromium/content/browser/browsing_data/browsing_data_filter_builder_impl.cc b/chromium/content/browser/browsing_data/browsing_data_filter_builder_impl.cc
index cba9445e35b..e569410d369 100644
--- a/chromium/content/browser/browsing_data/browsing_data_filter_builder_impl.cc
+++ b/chromium/content/browser/browsing_data/browsing_data_filter_builder_impl.cc
@@ -128,6 +128,8 @@ BrowsingDataFilterBuilderImpl::BuildGeneralFilter() const {
network::mojom::ClearDataFilterPtr
BrowsingDataFilterBuilderImpl::BuildNetworkServiceFilter() const {
+ if (IsEmptyBlacklist())
+ return nullptr;
network::mojom::ClearDataFilterPtr filter =
network::mojom::ClearDataFilter::New();
filter->type = (mode_ == Mode::WHITELIST)
diff --git a/chromium/content/browser/browsing_data/browsing_data_remover_impl.cc b/chromium/content/browser/browsing_data/browsing_data_remover_impl.cc
index 3226847af60..5d0afd56593 100644
--- a/chromium/content/browser/browsing_data/browsing_data_remover_impl.cc
+++ b/chromium/content/browser/browsing_data/browsing_data_remover_impl.cc
@@ -227,7 +227,8 @@ void BrowsingDataRemoverImpl::RemoveInternal(
void BrowsingDataRemoverImpl::RunNextTask() {
DCHECK(!task_queue_.empty());
- const RemovalTask& removal_task = task_queue_.front();
+ RemovalTask& removal_task = task_queue_.front();
+ removal_task.task_started = base::Time::Now();
RemoveImpl(removal_task.delete_begin, removal_task.delete_end,
removal_task.remove_mask, *removal_task.filter_builder,
@@ -278,7 +279,7 @@ void BrowsingDataRemoverImpl::RemoveImpl(
//////////////////////////////////////////////////////////////////////////////
// INITIALIZATION
- base::Callback<bool(const GURL& url)> filter =
+ base::RepeatingCallback<bool(const GURL& url)> filter =
filter_builder.BuildGeneralFilter();
//////////////////////////////////////////////////////////////////////////////
@@ -303,7 +304,7 @@ void BrowsingDataRemoverImpl::RemoveImpl(
network::mojom::ClearDataFilterPtr service_filter =
filter_builder.BuildNetworkServiceFilter();
- DCHECK(service_filter->origins.empty())
+ DCHECK(!service_filter || service_filter->origins.empty())
<< "Origin-based deletion is not suitable for channel IDs.";
BrowserContext::GetDefaultStoragePartition(browser_context_)
@@ -418,23 +419,23 @@ void BrowsingDataRemoverImpl::RemoveImpl(
// TODO(msramek): Clear the cache of all renderers.
+ // TODO(crbug.com/813882): implement retry on network service.
if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
// The clearing of the HTTP cache happens in the network service process
- // when enabled.
+ // when enabled. Note that we've deprecated the concept of a media cache,
+ // and are now using a single cache for both purposes.
network_context->ClearHttpCache(
delete_begin, delete_end, filter_builder.BuildNetworkServiceFilter(),
CreatePendingTaskCompletionClosureForMojo());
+ } else {
+ storage_partition->ClearHttpAndMediaCaches(
+ delete_begin, delete_end,
+ filter_builder.IsEmptyBlacklist()
+ ? base::Callback<bool(const GURL&)>()
+ : filter,
+ CreatePendingTaskCompletionClosureForMojo());
}
- // In the network service case, the call below will only clear the media
- // cache.
- // TODO(crbug.com/813882): implement retry on network service.
- storage_partition->ClearHttpAndMediaCaches(
- delete_begin, delete_end,
- filter_builder.IsEmptyBlacklist() ? base::Callback<bool(const GURL&)>()
- : std::move(filter),
- CreatePendingTaskCompletionClosureForMojo());
-
// When clearing cache, wipe accumulated network related data
// (TransportSecurityState and HttpServerPropertiesManager data).
network_context->ClearNetworkingHistorySince(
@@ -550,9 +551,22 @@ void BrowsingDataRemoverImpl::Notify() {
// itself in the meantime.
DCHECK(!task_queue_.empty());
- if (task_queue_.front().observer != nullptr &&
- observer_list_.HasObserver(task_queue_.front().observer)) {
- task_queue_.front().observer->OnBrowsingDataRemoverDone();
+ const RemovalTask& task = task_queue_.front();
+ if (task.observer != nullptr && observer_list_.HasObserver(task.observer)) {
+ task.observer->OnBrowsingDataRemoverDone();
+ }
+ if (task.filter_builder->GetMode() == BrowsingDataFilterBuilder::BLACKLIST) {
+ base::TimeDelta delta = base::Time::Now() - task.task_started;
+ // Full and partial deletions are often implemented differently, so
+ // we track them in seperate metrics.
+ if (task.delete_begin.is_null() && task.delete_end.is_max() &&
+ task.filter_builder->IsEmptyBlacklist()) {
+ UMA_HISTOGRAM_MEDIUM_TIMES(
+ "History.ClearBrowsingData.Duration.FullDeletion", delta);
+ } else {
+ UMA_HISTOGRAM_MEDIUM_TIMES(
+ "History.ClearBrowsingData.Duration.PartialDeletion", delta);
+ }
}
task_queue_.pop();
diff --git a/chromium/content/browser/browsing_data/browsing_data_remover_impl.h b/chromium/content/browser/browsing_data/browsing_data_remover_impl.h
index 1b02d6fc28e..4d4f3c9d485 100644
--- a/chromium/content/browser/browsing_data/browsing_data_remover_impl.h
+++ b/chromium/content/browser/browsing_data/browsing_data_remover_impl.h
@@ -116,6 +116,7 @@ class CONTENT_EXPORT BrowsingDataRemoverImpl
int origin_type_mask;
std::unique_ptr<BrowsingDataFilterBuilder> filter_builder;
Observer* observer;
+ base::Time task_started;
};
// Setter for |is_removing_|; DCHECKs that we can only start removing if we're
@@ -194,7 +195,7 @@ class CONTENT_EXPORT BrowsingDataRemoverImpl
int num_pending_tasks_ = 0;
// Observers of the global state and individual tasks.
- base::ObserverList<Observer, true> observer_list_;
+ base::ObserverList<Observer, true>::Unchecked observer_list_;
// We do not own this.
StoragePartition* storage_partition_for_testing_;
diff --git a/chromium/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc b/chromium/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc
index 2f95096b273..a82100fd443 100644
--- a/chromium/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc
+++ b/chromium/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc
@@ -321,7 +321,7 @@ class RemoveChannelIDTester : public net::SSLConfigService::Observer {
}
void GetChannelIDList(net::ChannelIDStore::ChannelIDList* channel_ids) {
- GetChannelIDStore()->GetAllChannelIDs(base::Bind(
+ GetChannelIDStore()->GetAllChannelIDs(base::BindOnce(
&RemoveChannelIDTester::GetAllChannelIDsCallback, channel_ids));
}
diff --git a/chromium/content/browser/browsing_data/clear_site_data_handler.cc b/chromium/content/browser/browsing_data/clear_site_data_handler.cc
new file mode 100644
index 00000000000..fc99ea9a22b
--- /dev/null
+++ b/chromium/content/browser/browsing_data/clear_site_data_handler.cc
@@ -0,0 +1,449 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/browsing_data/clear_site_data_handler.h"
+
+#include "base/command_line.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/scoped_observer.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browsing_data_filter_builder.h"
+#include "content/public/browser/browsing_data_remover.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/origin_util.h"
+#include "net/base/load_flags.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "net/http/http_response_headers.h"
+
+namespace content {
+
+namespace {
+
+// Datatypes.
+const char kDatatypeWildcard[] = "\"*\"";
+const char kDatatypeCookies[] = "\"cookies\"";
+const char kDatatypeStorage[] = "\"storage\"";
+const char kDatatypeCache[] = "\"cache\"";
+
+// Pretty-printed log output.
+const char kConsoleMessageTemplate[] = "Clear-Site-Data header on '%s': %s";
+const char kConsoleMessageCleared[] = "Cleared data types: %s.";
+const char kConsoleMessageDatatypeSeparator[] = ", ";
+
+bool AreExperimentalFeaturesEnabled() {
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExperimentalWebPlatformFeatures);
+}
+
+// Represents the parameters as a single number to be recorded in a histogram.
+int ParametersMask(bool clear_cookies, bool clear_storage, bool clear_cache) {
+ return static_cast<int>(clear_cookies) * (1 << 0) +
+ static_cast<int>(clear_storage) * (1 << 1) +
+ static_cast<int>(clear_cache) * (1 << 2);
+}
+
+// Helper class to find the BrowserContext associated with the request and
+// requests the actual clearing of data for |origin|. The data types to be
+// deleted are determined by |clear_cookies|, |clear_storage|, and
+// |clear_cache|. |web_contents_getter| identifies the WebContents from which
+// the request originated.
+// TODO(crbug.com/876931): |SiteDataClearer| could be merged into
+// |ClearSiteDataHandler| to make things cleaner.
+class SiteDataClearer : public BrowsingDataRemover::Observer {
+ public:
+ static void Run(
+ const base::RepeatingCallback<WebContents*()>& web_contents_getter,
+ const url::Origin& origin,
+ bool clear_cookies,
+ bool clear_storage,
+ bool clear_cache,
+ base::OnceClosure callback) {
+ WebContents* web_contents = web_contents_getter.Run();
+ if (!web_contents)
+ return;
+
+ (new SiteDataClearer(web_contents, origin, clear_cookies, clear_storage,
+ clear_cache, std::move(callback)))
+ ->RunAndDestroySelfWhenDone();
+ }
+
+ private:
+ SiteDataClearer(const WebContents* web_contents,
+ const url::Origin& origin,
+ bool clear_cookies,
+ bool clear_storage,
+ bool clear_cache,
+ base::OnceClosure callback)
+ : origin_(origin),
+ clear_cookies_(clear_cookies),
+ clear_storage_(clear_storage),
+ clear_cache_(clear_cache),
+ callback_(std::move(callback)),
+ pending_task_count_(0),
+ remover_(nullptr),
+ scoped_observer_(this) {
+ remover_ = BrowserContext::GetBrowsingDataRemover(
+ web_contents->GetBrowserContext());
+ DCHECK(remover_);
+ scoped_observer_.Add(remover_);
+ }
+
+ ~SiteDataClearer() override {}
+
+ void RunAndDestroySelfWhenDone() {
+ // Cookies and channel IDs are scoped to
+ // a) eTLD+1 of |origin|'s host if |origin|'s host is a registrable domain
+ // or a subdomain thereof
+ // b) |origin|'s host exactly if it is an IP address or an internal hostname
+ // (e.g. "localhost" or "fileserver").
+ // TODO(msramek): What about plugin data?
+ if (clear_cookies_) {
+ std::string domain = GetDomainAndRegistry(
+ origin_.host(),
+ net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
+
+ if (domain.empty())
+ domain = origin_.host(); // IP address or internal hostname.
+
+ std::unique_ptr<BrowsingDataFilterBuilder> domain_filter_builder(
+ BrowsingDataFilterBuilder::Create(
+ BrowsingDataFilterBuilder::WHITELIST));
+ domain_filter_builder->AddRegisterableDomain(domain);
+
+ pending_task_count_++;
+ remover_->RemoveWithFilterAndReply(
+ base::Time(), base::Time::Max(),
+ BrowsingDataRemover::DATA_TYPE_COOKIES |
+ BrowsingDataRemover::DATA_TYPE_CHANNEL_IDS |
+ BrowsingDataRemover::DATA_TYPE_AVOID_CLOSING_CONNECTIONS,
+ BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB |
+ BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB,
+ std::move(domain_filter_builder), this);
+ }
+
+ // Delete origin-scoped data.
+ int remove_mask = 0;
+ if (clear_storage_)
+ remove_mask |= BrowsingDataRemover::DATA_TYPE_DOM_STORAGE;
+ if (clear_cache_)
+ remove_mask |= BrowsingDataRemover::DATA_TYPE_CACHE;
+
+ if (remove_mask) {
+ std::unique_ptr<BrowsingDataFilterBuilder> origin_filter_builder(
+ BrowsingDataFilterBuilder::Create(
+ BrowsingDataFilterBuilder::WHITELIST));
+ origin_filter_builder->AddOrigin(origin_);
+
+ pending_task_count_++;
+ remover_->RemoveWithFilterAndReply(
+ base::Time(), base::Time::Max(), remove_mask,
+ BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB |
+ BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB,
+ std::move(origin_filter_builder), this);
+ }
+
+ DCHECK_GT(pending_task_count_, 0);
+ }
+
+ // BrowsingDataRemover::Observer:
+ void OnBrowsingDataRemoverDone() override {
+ DCHECK(pending_task_count_);
+ if (--pending_task_count_)
+ return;
+
+ std::move(callback_).Run();
+ delete this;
+ }
+
+ url::Origin origin_;
+ bool clear_cookies_;
+ bool clear_storage_;
+ bool clear_cache_;
+ base::OnceClosure callback_;
+ int pending_task_count_;
+ BrowsingDataRemover* remover_;
+ ScopedObserver<BrowsingDataRemover, BrowsingDataRemover::Observer>
+ scoped_observer_;
+};
+
+// Outputs a single |formatted_message| on the UI thread.
+void OutputFormattedMessage(WebContents* web_contents,
+ ConsoleMessageLevel level,
+ const std::string& formatted_text) {
+ if (web_contents)
+ web_contents->GetMainFrame()->AddMessageToConsole(level, formatted_text);
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// ConsoleMessagesDelegate
+
+ClearSiteDataHandler::ConsoleMessagesDelegate::ConsoleMessagesDelegate()
+ : output_formatted_message_function_(
+ base::BindRepeating(&OutputFormattedMessage)) {}
+
+ClearSiteDataHandler::ConsoleMessagesDelegate::~ConsoleMessagesDelegate() {}
+
+void ClearSiteDataHandler::ConsoleMessagesDelegate::AddMessage(
+ const GURL& url,
+ const std::string& text,
+ ConsoleMessageLevel level) {
+ messages_.push_back({url, text, level});
+}
+
+void ClearSiteDataHandler::ConsoleMessagesDelegate::OutputMessages(
+ const base::RepeatingCallback<WebContents*()>& web_contents_getter) {
+ if (messages_.empty())
+ return;
+
+ WebContents* web_contents = web_contents_getter.Run();
+
+ for (const auto& message : messages_) {
+ // Prefix each message with |kConsoleMessageTemplate|.
+ output_formatted_message_function_.Run(
+ web_contents, message.level,
+ base::StringPrintf(kConsoleMessageTemplate, message.url.spec().c_str(),
+ message.text.c_str()));
+ }
+
+ messages_.clear();
+}
+
+void ClearSiteDataHandler::ConsoleMessagesDelegate::
+ SetOutputFormattedMessageFunctionForTesting(
+ const OutputFormattedMessageFunction& function) {
+ output_formatted_message_function_ = function;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ClearSiteDataHandler
+
+// static
+void ClearSiteDataHandler::HandleHeader(
+ base::RepeatingCallback<WebContents*()> web_contents_getter,
+ const GURL& url,
+ const std::string& header_value,
+ int load_flags,
+ base::OnceClosure callback) {
+ ClearSiteDataHandler handler(std::move(web_contents_getter), url,
+ header_value, load_flags, std::move(callback),
+ std::make_unique<ConsoleMessagesDelegate>());
+ handler.HandleHeaderAndOutputConsoleMessages();
+}
+
+// static
+bool ClearSiteDataHandler::ParseHeaderForTesting(
+ const std::string& header,
+ bool* clear_cookies,
+ bool* clear_storage,
+ bool* clear_cache,
+ ConsoleMessagesDelegate* delegate,
+ const GURL& current_url) {
+ return ClearSiteDataHandler::ParseHeader(header, clear_cookies, clear_storage,
+ clear_cache, delegate, current_url);
+}
+
+ClearSiteDataHandler::ClearSiteDataHandler(
+ base::RepeatingCallback<WebContents*()> web_contents_getter,
+ const GURL& url,
+ const std::string& header_value,
+ int load_flags,
+ base::OnceClosure callback,
+ std::unique_ptr<ConsoleMessagesDelegate> delegate)
+ : web_contents_getter_(std::move(web_contents_getter)),
+ url_(url),
+ header_value_(header_value),
+ load_flags_(load_flags),
+ callback_(std::move(callback)),
+ delegate_(std::move(delegate)) {
+ DCHECK(web_contents_getter_);
+ DCHECK(delegate_);
+}
+
+ClearSiteDataHandler::~ClearSiteDataHandler() = default;
+
+bool ClearSiteDataHandler::HandleHeaderAndOutputConsoleMessages() {
+ bool deferred = Run();
+
+ // If the redirect is deferred, wait until it is resumed.
+ // TODO(crbug.com/876931): Delay output until next frame for navigations.
+ if (!deferred) {
+ OutputConsoleMessages();
+ RunCallbackNotDeferred();
+ }
+
+ return deferred;
+}
+
+bool ClearSiteDataHandler::Run() {
+ // Only accept the header on secure non-unique origins.
+ if (!IsOriginSecure(url_)) {
+ delegate_->AddMessage(url_, "Not supported for insecure origins.",
+ CONSOLE_MESSAGE_LEVEL_ERROR);
+ return false;
+ }
+
+ url::Origin origin = url::Origin::Create(url_);
+ if (origin.unique()) {
+ delegate_->AddMessage(url_, "Not supported for unique origins.",
+ CONSOLE_MESSAGE_LEVEL_ERROR);
+ return false;
+ }
+
+ // The LOAD_DO_NOT_SAVE_COOKIES flag prohibits the request from doing any
+ // modification to cookies. Clear-Site-Data applies this restriction to other
+ // data types as well.
+ // TODO(msramek): Consider showing a blocked icon via
+ // TabSpecificContentSettings and reporting the action in the "Blocked"
+ // section of the cookies dialog in OIB.
+ if (load_flags_ & net::LOAD_DO_NOT_SAVE_COOKIES) {
+ delegate_->AddMessage(
+ url_,
+ "The request's credentials mode prohibits modifying cookies "
+ "and other local data.",
+ CONSOLE_MESSAGE_LEVEL_ERROR);
+ return false;
+ }
+
+ bool clear_cookies;
+ bool clear_storage;
+ bool clear_cache;
+
+ if (!ClearSiteDataHandler::ParseHeader(header_value_, &clear_cookies,
+ &clear_storage, &clear_cache,
+ delegate_.get(), url_)) {
+ return false;
+ }
+
+ // Record the call parameters.
+ UMA_HISTOGRAM_ENUMERATION(
+ "Navigation.ClearSiteData.Parameters",
+ ParametersMask(clear_cookies, clear_storage, clear_cache), (1 << 3));
+
+ ExecuteClearingTask(
+ origin, clear_cookies, clear_storage, clear_cache,
+ base::BindOnce(&ClearSiteDataHandler::TaskFinished,
+ base::TimeTicks::Now(), std::move(delegate_),
+ web_contents_getter_, std::move(callback_)));
+
+ return true;
+}
+
+// static
+bool ClearSiteDataHandler::ParseHeader(const std::string& header,
+ bool* clear_cookies,
+ bool* clear_storage,
+ bool* clear_cache,
+ ConsoleMessagesDelegate* delegate,
+ const GURL& current_url) {
+ if (!base::IsStringASCII(header)) {
+ delegate->AddMessage(current_url, "Must only contain ASCII characters.",
+ CONSOLE_MESSAGE_LEVEL_ERROR);
+ return false;
+ }
+
+ *clear_cookies = false;
+ *clear_storage = false;
+ *clear_cache = false;
+
+ std::vector<std::string> input_types = base::SplitString(
+ header, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ std::string output_types;
+
+ for (unsigned i = 0; i < input_types.size(); i++) {
+ bool* data_type = nullptr;
+
+ if (AreExperimentalFeaturesEnabled() &&
+ input_types[i] == kDatatypeWildcard) {
+ input_types.push_back(kDatatypeCookies);
+ input_types.push_back(kDatatypeStorage);
+ input_types.push_back(kDatatypeCache);
+ continue;
+ } else if (input_types[i] == kDatatypeCookies) {
+ data_type = clear_cookies;
+ } else if (input_types[i] == kDatatypeStorage) {
+ data_type = clear_storage;
+ } else if (input_types[i] == kDatatypeCache) {
+ data_type = clear_cache;
+ } else {
+ delegate->AddMessage(
+ current_url,
+ base::StringPrintf("Unrecognized type: %s.", input_types[i].c_str()),
+ CONSOLE_MESSAGE_LEVEL_ERROR);
+ continue;
+ }
+
+ DCHECK(data_type);
+
+ if (*data_type)
+ continue;
+
+ *data_type = true;
+ if (!output_types.empty())
+ output_types += kConsoleMessageDatatypeSeparator;
+ output_types += input_types[i];
+ }
+
+ if (!*clear_cookies && !*clear_storage && !*clear_cache) {
+ delegate->AddMessage(current_url, "No recognized types specified.",
+ CONSOLE_MESSAGE_LEVEL_ERROR);
+ return false;
+ }
+
+ // Pretty-print which types are to be cleared.
+ // TODO(crbug.com/798760): Remove the disclaimer about cookies.
+ std::string console_output =
+ base::StringPrintf(kConsoleMessageCleared, output_types.c_str());
+ if (*clear_cookies) {
+ console_output +=
+ " Clearing channel IDs and HTTP authentication cache is currently not"
+ " supported, as it breaks active network connections.";
+ }
+ delegate->AddMessage(current_url, console_output, CONSOLE_MESSAGE_LEVEL_INFO);
+
+ return true;
+}
+
+void ClearSiteDataHandler::ExecuteClearingTask(const url::Origin& origin,
+ bool clear_cookies,
+ bool clear_storage,
+ bool clear_cache,
+ base::OnceClosure callback) {
+ SiteDataClearer::Run(web_contents_getter_, origin, clear_cookies,
+ clear_storage, clear_cache, std::move(callback));
+}
+
+// static
+void ClearSiteDataHandler::TaskFinished(
+ base::TimeTicks clearing_started,
+ std::unique_ptr<ConsoleMessagesDelegate> delegate,
+ base::RepeatingCallback<WebContents*()> web_contents_getter,
+ base::OnceClosure callback) {
+ DCHECK(!clearing_started.is_null());
+
+ UMA_HISTOGRAM_CUSTOM_TIMES("Navigation.ClearSiteData.Duration",
+ base::TimeTicks::Now() - clearing_started,
+ base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromSeconds(1), 50);
+
+ // TODO(crbug.com/876931): Delay output until next frame for navigations.
+ delegate->OutputMessages(web_contents_getter);
+
+ std::move(callback).Run();
+}
+
+void ClearSiteDataHandler::OutputConsoleMessages() {
+ delegate_->OutputMessages(web_contents_getter_);
+}
+
+void ClearSiteDataHandler::RunCallbackNotDeferred() {
+ std::move(callback_).Run();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/browsing_data/clear_site_data_handler.h b/chromium/content/browser/browsing_data/clear_site_data_handler.h
new file mode 100644
index 00000000000..2a509de4d4c
--- /dev/null
+++ b/chromium/content/browser/browsing_data/clear_site_data_handler.h
@@ -0,0 +1,162 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_BROWSING_DATA_CLEAR_SITE_DATA_HANDLER_H_
+#define CONTENT_BROWSER_BROWSING_DATA_CLEAR_SITE_DATA_HANDLER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "content/common/content_export.h"
+#include "content/public/common/console_message_level.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace content {
+
+class WebContents;
+
+// This handler parses the Clear-Site-Data header and executes the clearing
+// of browsing data. The resource load is delayed until the header is parsed
+// and, if valid, until the browsing data are deleted. See the W3C working draft
+// at https://w3c.github.io/webappsec-clear-site-data/.
+class CONTENT_EXPORT ClearSiteDataHandler {
+ public:
+ // Stores and outputs console messages.
+ class CONTENT_EXPORT ConsoleMessagesDelegate {
+ public:
+ struct Message {
+ GURL url;
+ std::string text;
+ ConsoleMessageLevel level;
+ };
+
+ using OutputFormattedMessageFunction = base::RepeatingCallback<
+ void(WebContents*, ConsoleMessageLevel, const std::string&)>;
+
+ ConsoleMessagesDelegate();
+ virtual ~ConsoleMessagesDelegate();
+
+ // Logs a |text| message from |url| with |level|.
+ virtual void AddMessage(const GURL& url,
+ const std::string& text,
+ ConsoleMessageLevel level);
+
+ // Outputs stored messages to the console of WebContents identified by
+ // |web_contents_getter|.
+ virtual void OutputMessages(
+ const base::RepeatingCallback<WebContents*()>& web_contents_getter);
+
+ const std::vector<Message>& messages() const { return messages_; }
+
+ protected:
+ void SetOutputFormattedMessageFunctionForTesting(
+ const OutputFormattedMessageFunction& function);
+
+ private:
+ std::vector<Message> messages_;
+ OutputFormattedMessageFunction output_formatted_message_function_;
+ };
+
+ // |header_value| is the string value of the 'Clear-Site-Data' header. This
+ // method calls ParseHeader() to parse it, and then ExecuteClearingTask() if
+ // applicable.
+ static void HandleHeader(
+ base::RepeatingCallback<WebContents*()> web_contents_getter,
+ const GURL& url,
+ const std::string& header_value,
+ int load_flags,
+ base::OnceClosure callback);
+
+ // Exposes ParseHeader() publicly for testing.
+ static bool ParseHeaderForTesting(const std::string& header,
+ bool* clear_cookies,
+ bool* clear_storage,
+ bool* clear_cache,
+ ConsoleMessagesDelegate* delegate,
+ const GURL& current_url);
+
+ protected:
+ ClearSiteDataHandler(
+ base::RepeatingCallback<WebContents*()> web_contents_getter,
+ const GURL& url,
+ const std::string& header_value,
+ int load_flags,
+ base::OnceClosure callback,
+ std::unique_ptr<ConsoleMessagesDelegate> delegate);
+ virtual ~ClearSiteDataHandler();
+
+ // Calls |HandleHeaderImpl| to handle headers, and output console message if
+ // not deferred. Returns |true| if the request was deferred.
+ bool HandleHeaderAndOutputConsoleMessages();
+
+ // Handles headers and maybe execute clearing task. Returns |true| if the
+ // request was deferred.
+ bool Run();
+
+ // Parses the value of the 'Clear-Site-Data' header and outputs whether
+ // the header requests to |clear_cookies|, |clear_storage|, and |clear_cache|.
+ // The |delegate| will be filled with messages to be output in the console,
+ // prepended by the |current_url|. Returns true if parsing was successful.
+ static bool ParseHeader(const std::string& header,
+ bool* clear_cookies,
+ bool* clear_storage,
+ bool* clear_cache,
+ ConsoleMessagesDelegate* delegate,
+ const GURL& current_url);
+
+ // Executes the clearing task. Can be overridden for testing.
+ virtual void ExecuteClearingTask(const url::Origin& origin,
+ bool clear_cookies,
+ bool clear_storage,
+ bool clear_cache,
+ base::OnceClosure callback);
+
+ // Signals that a parsing and deletion task was finished.
+ // |clearing_started| is the time when the last clearing operation started.
+ // Used when clearing finishes to compute the duration.
+ static void TaskFinished(
+ base::TimeTicks clearing_started,
+ std::unique_ptr<ConsoleMessagesDelegate> delegate,
+ base::RepeatingCallback<WebContents*()> web_contents_getter,
+ base::OnceClosure callback);
+
+ // Outputs the console messages in the |delegate_|.
+ void OutputConsoleMessages();
+
+ // Run the callback to resume loading. No clearing actions were conducted.
+ void RunCallbackNotDeferred();
+
+ const GURL& GetURLForTesting();
+
+ private:
+ // Required to clear the data.
+ base::RepeatingCallback<WebContents*()> web_contents_getter_;
+
+ // Target URL whose data will be cleared.
+ GURL url_;
+
+ // Raw string value of the 'Clear-Site-Data' header.
+ std::string header_value_;
+
+ // Load flags of the current request, used to check cookie policies.
+ int load_flags_;
+
+ // Used to notify that the clearing has completed. Callers could resuming
+ // loading after this point.
+ base::OnceClosure callback_;
+
+ // The delegate that stores and outputs console messages.
+ std::unique_ptr<ConsoleMessagesDelegate> delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClearSiteDataHandler);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_BROWSING_DATA_CLEAR_SITE_DATA_HANDLER_H_
diff --git a/chromium/content/browser/browsing_data/clear_site_data_throttle_browsertest.cc b/chromium/content/browser/browsing_data/clear_site_data_handler_browsertest.cc
index 8fba2e45093..0bf7f3c6adc 100644
--- a/chromium/content/browser/browsing_data/clear_site_data_throttle_browsertest.cc
+++ b/chromium/content/browser/browsing_data/clear_site_data_handler_browsertest.cc
@@ -2,8 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "content/browser/browsing_data/clear_site_data_throttle.h"
-
+#include <algorithm>
#include <memory>
#include "base/bind.h"
@@ -24,6 +23,9 @@
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/service_manager_connection.h"
+#include "content/public/common/service_names.mojom.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/cache_test_util.h"
#include "content/public/test/content_browser_test.h"
@@ -32,6 +34,7 @@
#include "content/public/test/test_navigation_observer.h"
#include "content/shell/browser/shell.h"
#include "net/base/escape.h"
+#include "net/base/net_errors.h"
#include "net/base/url_util.h"
#include "net/cookies/cookie_store.h"
#include "net/dns/mock_host_resolver.h"
@@ -39,6 +42,9 @@
#include "net/test/embedded_test_server/http_response.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
+#include "services/network/public/cpp/features.h"
+#include "services/network/public/mojom/network_service_test.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
#include "storage/browser/quota/quota_settings.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "url/origin.h"
@@ -137,6 +143,7 @@ class ServiceWorkerActivationObserver
// ServiceWorkerContextCoreObserver overrides.
void OnVersionStateChanged(int64_t version_id,
+ const GURL& scope,
ServiceWorkerVersion::Status) override {
if (context_->GetLiveVersion(version_id)->status() ==
ServiceWorkerVersion::ACTIVATED) {
@@ -153,14 +160,22 @@ class ServiceWorkerActivationObserver
} // namespace
-class ClearSiteDataThrottleBrowserTest : public ContentBrowserTest {
+class ClearSiteDataHandlerBrowserTest : public ContentBrowserTest {
public:
void SetUpCommandLine(base::CommandLine* command_line) override {
ContentBrowserTest::SetUpCommandLine(command_line);
- // We're redirecting all hosts to localhost even on HTTPS, so we'll get
- // certificate errors.
- command_line->AppendSwitch(switches::kIgnoreCertificateErrors);
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService))
+ is_network_service_enabled_ = true;
+
+ if (is_network_service_enabled_) {
+ // |MockCertVerifier| only seems to work when Network Service was enabled.
+ command_line->AppendSwitch(switches::kUseMockCertVerifierForTesting);
+ } else {
+ // We're redirecting all hosts to localhost even on HTTPS, so we'll get
+ // certificate errors.
+ command_line->AppendSwitch(switches::kIgnoreCertificateErrors);
+ }
}
void SetUpOnMainThread() override {
@@ -172,17 +187,21 @@ class ClearSiteDataThrottleBrowserTest : public ContentBrowserTest {
// Set up HTTP and HTTPS test servers that handle all hosts.
host_resolver()->AddRule("*", "127.0.0.1");
+ if (is_network_service_enabled_)
+ SetUpMockCertVerifier(net::OK);
+
embedded_test_server()->RegisterRequestHandler(
- base::Bind(&ClearSiteDataThrottleBrowserTest::HandleRequest,
- base::Unretained(this)));
+ base::BindRepeating(&ClearSiteDataHandlerBrowserTest::HandleRequest,
+ base::Unretained(this)));
ASSERT_TRUE(embedded_test_server()->Start());
+ // Set up HTTPS server.
https_server_.reset(new net::EmbeddedTestServer(
net::test_server::EmbeddedTestServer::TYPE_HTTPS));
https_server_->SetSSLConfig(net::EmbeddedTestServer::CERT_OK);
https_server_->RegisterRequestHandler(
- base::Bind(&ClearSiteDataThrottleBrowserTest::HandleRequest,
- base::Unretained(this)));
+ base::BindRepeating(&ClearSiteDataHandlerBrowserTest::HandleRequest,
+ base::Unretained(this)));
ASSERT_TRUE(https_server_->Start());
// Initialize the cookie store pointer on the IO thread.
@@ -190,11 +209,9 @@ class ClearSiteDataThrottleBrowserTest : public ContentBrowserTest {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::BindOnce(
- &ClearSiteDataThrottleBrowserTest::InitializeCookieStore,
+ &ClearSiteDataHandlerBrowserTest::InitializeCookieStore,
base::Unretained(this),
- base::Unretained(
- BrowserContext::GetDefaultStoragePartition(browser_context())
- ->GetURLRequestContext()),
+ base::Unretained(storage_partition()->GetURLRequestContext()),
run_loop.QuitClosure()));
run_loop.Run();
}
@@ -203,6 +220,10 @@ class ClearSiteDataThrottleBrowserTest : public ContentBrowserTest {
return shell()->web_contents()->GetBrowserContext();
}
+ StoragePartition* storage_partition() {
+ return BrowserContext::GetDefaultStoragePartition(browser_context());
+ }
+
void InitializeCookieStore(
net::URLRequestContextGetter* request_context_getter,
base::Closure callback) {
@@ -214,30 +235,30 @@ class ClearSiteDataThrottleBrowserTest : public ContentBrowserTest {
// Adds a cookie for the |url|. Used in the cookie integration tests.
void AddCookie(const GURL& url) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ network::mojom::CookieManager* cookie_manager =
+ storage_partition()->GetCookieManagerForBrowserProcess();
+
+ std::unique_ptr<net::CanonicalCookie> cookie(net::CanonicalCookie::Create(
+ url, "A=1", base::Time::Now(), net::CookieOptions()));
+
base::RunLoop run_loop;
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(
- &net::CookieStore::SetCookieWithOptionsAsync,
- base::Unretained(cookie_store_), url, "A=1", net::CookieOptions(),
- base::Bind(&ClearSiteDataThrottleBrowserTest::AddCookieCallback,
- run_loop.QuitClosure())));
+ cookie_manager->SetCanonicalCookie(
+ *cookie, true /* secure_source */, false /* modify_http_only */,
+ base::BindOnce(&ClearSiteDataHandlerBrowserTest::AddCookieCallback,
+ run_loop.QuitClosure()));
run_loop.Run();
}
// Retrieves the list of all cookies. Used in the cookie integration tests.
net::CookieList GetCookies() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ network::mojom::CookieManager* cookie_manager =
+ storage_partition()->GetCookieManagerForBrowserProcess();
base::RunLoop run_loop;
net::CookieList cookie_list;
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(
- &net::CookieStore::GetAllCookiesAsync,
- base::Unretained(cookie_store_),
- base::Bind(&ClearSiteDataThrottleBrowserTest::GetCookiesCallback,
- run_loop.QuitClosure(),
- base::Unretained(&cookie_list))));
+ cookie_manager->GetAllCookies(base::BindRepeating(
+ &ClearSiteDataHandlerBrowserTest::GetCookiesCallback,
+ run_loop.QuitClosure(), base::Unretained(&cookie_list)));
run_loop.Run();
return cookie_list;
}
@@ -247,8 +268,7 @@ class ClearSiteDataThrottleBrowserTest : public ContentBrowserTest {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
ServiceWorkerContextWrapper* service_worker_context =
static_cast<ServiceWorkerContextWrapper*>(
- BrowserContext::GetDefaultStoragePartition(browser_context())
- ->GetServiceWorkerContext());
+ storage_partition()->GetServiceWorkerContext());
GURL scope_url = https_server()->GetURL(origin, "/");
GURL js_url = https_server()->GetURL(origin, "/?file=worker.js");
@@ -262,7 +282,7 @@ class ClearSiteDataThrottleBrowserTest : public ContentBrowserTest {
&ServiceWorkerContextWrapper::RegisterServiceWorker,
base::Unretained(service_worker_context), js_url, options,
base::Bind(
- &ClearSiteDataThrottleBrowserTest::AddServiceWorkerCallback,
+ &ClearSiteDataHandlerBrowserTest::AddServiceWorkerCallback,
base::Unretained(this))));
// Wait for its activation.
@@ -281,8 +301,7 @@ class ClearSiteDataThrottleBrowserTest : public ContentBrowserTest {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
ServiceWorkerContextWrapper* service_worker_context =
static_cast<ServiceWorkerContextWrapper*>(
- BrowserContext::GetDefaultStoragePartition(browser_context())
- ->GetServiceWorkerContext());
+ storage_partition()->GetServiceWorkerContext());
std::vector<ServiceWorkerUsageInfo> service_workers;
base::RunLoop run_loop;
@@ -293,7 +312,7 @@ class ClearSiteDataThrottleBrowserTest : public ContentBrowserTest {
&ServiceWorkerContextWrapper::GetAllOriginsInfo,
base::Unretained(service_worker_context),
base::Bind(
- &ClearSiteDataThrottleBrowserTest::GetServiceWorkersCallback,
+ &ClearSiteDataHandlerBrowserTest::GetServiceWorkersCallback,
base::Unretained(this), run_loop.QuitClosure(),
base::Unretained(&service_workers))));
run_loop.Run();
@@ -301,6 +320,44 @@ class ClearSiteDataThrottleBrowserTest : public ContentBrowserTest {
return service_workers;
}
+ void CreateCacheEntry(const GURL& url) {
+ if (is_network_service_enabled_) {
+ ASSERT_EQ(net::OK, LoadBasicRequest(
+ storage_partition()->GetNetworkContext(), url));
+ } else {
+ if (!cache_test_util_)
+ cache_test_util_ = std::make_unique<CacheTestUtil>(storage_partition());
+ cache_test_util_->CreateCacheEntries({url.spec()});
+ }
+ }
+
+ bool TestCacheEntry(const GURL& url) {
+ if (is_network_service_enabled_) {
+ return LoadBasicRequest(storage_partition()->GetNetworkContext(), url,
+ 0 /* process_id */, 0 /* render_frame_id */,
+ net::LOAD_ONLY_FROM_CACHE) == net::OK;
+ } else {
+ std::vector<std::string> cache_keys = cache_test_util_->GetEntryKeys();
+ return std::find(cache_keys.begin(), cache_keys.end(), url.spec()) !=
+ cache_keys.end();
+ }
+ }
+
+ // Causes |!g_base_sync_primitives_disallowed.Get().Get()| issue if we don't
+ // destroy it before test ends.
+ void DestroyCacheTestUtilIfNecessary() {
+ if (cache_test_util_)
+ cache_test_util_ = nullptr;
+ }
+
+ GURL GetURLForHTTPSHost1(const std::string& relative_url) {
+ return https_server_->GetURL("origin1.com", relative_url);
+ }
+
+ GURL GetURLForHTTPSHost2(const std::string& relative_url) {
+ return https_server_->GetURL("origin2.com", relative_url);
+ }
+
TestBrowsingDataRemoverDelegate* delegate() { return &embedder_delegate_; }
net::EmbeddedTestServer* https_server() { return https_server_.get(); }
@@ -375,12 +432,32 @@ class ClearSiteDataThrottleBrowserTest : public ContentBrowserTest {
response->set_content(buffer.get());
}
+ if (base::StartsWith(request.relative_url, "/cachetime",
+ base::CompareCase::SENSITIVE)) {
+ response->set_content(
+ "<html><head><title>Cache: max-age=60</title></head></html>");
+ response->set_content_type("text/html");
+ response->AddCustomHeader("Cache-Control", "max-age=60");
+ }
+
return std::move(response);
}
+ void SetUpMockCertVerifier(int32_t default_result) {
+ DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService));
+ network::mojom::NetworkServiceTestPtr network_service_test;
+ ServiceManagerConnection::GetForProcess()->GetConnector()->BindInterface(
+ mojom::kNetworkServiceName, &network_service_test);
+
+ base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+ network_service_test->MockCertVerifierSetDefaultResult(
+ default_result, run_loop.QuitClosure());
+ run_loop.Run();
+ }
+
// Callback handler for AddCookie().
static void AddCookieCallback(const base::Closure& callback, bool success) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
ASSERT_TRUE(success);
callback.Run();
}
@@ -389,7 +466,7 @@ class ClearSiteDataThrottleBrowserTest : public ContentBrowserTest {
static void GetCookiesCallback(const base::Closure& callback,
net::CookieList* out_cookie_list,
const net::CookieList& cookie_list) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
*out_cookie_list = cookie_list;
callback.Run();
}
@@ -406,6 +483,12 @@ class ClearSiteDataThrottleBrowserTest : public ContentBrowserTest {
callback.Run();
}
+ // We can only use |MockCertVerifier| when Network Service was enabled.
+ bool is_network_service_enabled_ = false;
+
+ // Only used when |is_network_service_enabled_| is false.
+ std::unique_ptr<CacheTestUtil> cache_test_util_ = nullptr;
+
std::unique_ptr<net::EmbeddedTestServer> https_server_;
TestBrowsingDataRemoverDelegate embedder_delegate_;
@@ -422,7 +505,7 @@ class ClearSiteDataThrottleBrowserTest : public ContentBrowserTest {
#else
#define MAYBE_RedirectNavigation RedirectNavigation
#endif
-IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest,
+IN_PROC_BROWSER_TEST_F(ClearSiteDataHandlerBrowserTest,
MAYBE_RedirectNavigation) {
GURL page_urls[3] = {
https_server()->GetURL("origin1.com", "/"),
@@ -470,7 +553,7 @@ IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest,
#else
#define MAYBE_RedirectResourceLoad RedirectResourceLoad
#endif
-IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest,
+IN_PROC_BROWSER_TEST_F(ClearSiteDataHandlerBrowserTest,
MAYBE_RedirectResourceLoad) {
GURL resource_urls[3] = {
https_server()->GetURL("origin1.com", "/redirect-start"),
@@ -515,7 +598,7 @@ IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest,
}
// Tests that the Clear-Site-Data header is ignored for insecure origins.
-IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, InsecureNavigation) {
+IN_PROC_BROWSER_TEST_F(ClearSiteDataHandlerBrowserTest, InsecureNavigation) {
// ClearSiteData() should not be called on HTTP.
GURL url = embedded_test_server()->GetURL("example.com", "/");
AddQuery(&url, "header", kClearCookiesHeader);
@@ -529,7 +612,7 @@ IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, InsecureNavigation) {
// Tests that the Clear-Site-Data header is honored for secure resource loads
// and ignored for insecure ones.
-IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest,
+IN_PROC_BROWSER_TEST_F(ClearSiteDataHandlerBrowserTest,
SecureAndInsecureResourceLoad) {
GURL insecure_image =
embedded_test_server()->GetURL("example.com", "/image.png");
@@ -593,7 +676,7 @@ IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest,
// Tests that the Clear-Site-Data header is ignored for service worker resource
// loads.
-IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, ServiceWorker) {
+IN_PROC_BROWSER_TEST_F(ClearSiteDataHandlerBrowserTest, ServiceWorker) {
GURL origin1 = https_server()->GetURL("origin1.com", "/");
GURL origin2 = https_server()->GetURL("origin2.com", "/");
GURL origin3 = https_server()->GetURL("origin3.com", "/");
@@ -651,7 +734,7 @@ IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, ServiceWorker) {
#else
#define MAYBE_Credentials Credentials
#endif
-IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, MAYBE_Credentials) {
+IN_PROC_BROWSER_TEST_F(ClearSiteDataHandlerBrowserTest, MAYBE_Credentials) {
GURL page_template = https_server()->GetURL("origin1.com", "/");
GURL same_origin_resource =
https_server()->GetURL("origin1.com", "/resource");
@@ -710,8 +793,7 @@ IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, MAYBE_Credentials) {
// Tests that the credentials flag is correctly taken into account when it
// interpretation changes after redirect.
-IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest,
- CredentialsOnRedirect) {
+IN_PROC_BROWSER_TEST_F(ClearSiteDataHandlerBrowserTest, CredentialsOnRedirect) {
GURL urls[2] = {
https_server()->GetURL("origin1.com", "/image.png"),
https_server()->GetURL("origin2.com", "/image.png"),
@@ -752,15 +834,15 @@ IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest,
}
// Tests that ClearSiteData() is called for the correct data types.
-IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, Types) {
+IN_PROC_BROWSER_TEST_F(ClearSiteDataHandlerBrowserTest, Types) {
GURL base_url = https_server()->GetURL("example.com", "/");
- struct TestCase {
+ const struct TestCase {
const char* value;
bool remove_cookies;
bool remove_storage;
bool remove_cache;
- } test_cases[] = {
+ } kTestCases[] = {
{"\"cookies\"", true, false, false},
{"\"storage\"", false, true, false},
{"\"cache\"", false, false, true},
@@ -770,7 +852,7 @@ IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, Types) {
{"\"cookies\", \"storage\", \"cache\"", true, true, true},
};
- for (const TestCase& test_case : test_cases) {
+ for (const TestCase& test_case : kTestCases) {
GURL url = base_url;
AddQuery(&url, "header", test_case.value);
@@ -785,7 +867,7 @@ IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, Types) {
}
// Integration test for the deletion of cookies.
-IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest,
+IN_PROC_BROWSER_TEST_F(ClearSiteDataHandlerBrowserTest,
CookiesIntegrationTest) {
AddCookie(https_server()->GetURL("origin1.com", "/abc"));
AddCookie(https_server()->GetURL("subdomain.origin1.com", "/"));
@@ -809,7 +891,7 @@ IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest,
}
// Integration test for the unregistering of service workers.
-IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest,
+IN_PROC_BROWSER_TEST_F(ClearSiteDataHandlerBrowserTest,
StorageServiceWorkersIntegrationTest) {
AddServiceWorker("origin1.com");
AddServiceWorker("origin2.com");
@@ -850,45 +932,41 @@ IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest,
// local storage, indexed DB, etc.
// Integration test for the deletion of cache entries.
-// NOTE: This test might be flaky. disk_cache::Backend calls back before cache
-// entries are actually written to the disk. Other tests using CacheTestUtil
-// show that a timeout of around 1s between cache operations is necessary to
-// avoid flakiness.
-IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, CacheIntegrationTest) {
- const int kTimeoutMs = 1000;
-
- CacheTestUtil util(
- BrowserContext::GetDefaultStoragePartition(browser_context()));
- std::string url1 = https_server()->GetURL("origin1.com", "/foo").spec();
- std::string url2 = https_server()->GetURL("origin1.com", "/bar").spec();
- std::string url3 = https_server()->GetURL("origin2.com", "/foo").spec();
- std::string url4 = https_server()->GetURL("origin2.com", "/bar").spec();
-
- std::set<std::string> entries_to_create = {url1, url2, url3, url4};
- util.CreateCacheEntries(entries_to_create);
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(kTimeoutMs));
+IN_PROC_BROWSER_TEST_F(ClearSiteDataHandlerBrowserTest, CacheIntegrationTest) {
+ GURL url1 = GetURLForHTTPSHost1("/cachetime/foo");
+ GURL url2 = GetURLForHTTPSHost1("/cachetime/bar");
+ GURL url3 = GetURLForHTTPSHost2("/cachetime/foo");
+ GURL url4 = GetURLForHTTPSHost2("/cachetime/bar");
+
+ // Load the url to create cache entries.
+ CreateCacheEntry(url1);
+ CreateCacheEntry(url2);
+ CreateCacheEntry(url3);
+ CreateCacheEntry(url4);
// There are four cache entries on two origins.
- std::vector<std::string> cache_keys = util.GetEntryKeys();
- EXPECT_EQ(4u, cache_keys.size());
+ EXPECT_TRUE(TestCacheEntry(url1));
+ EXPECT_TRUE(TestCacheEntry(url2));
+ EXPECT_TRUE(TestCacheEntry(url3));
+ EXPECT_TRUE(TestCacheEntry(url4));
- // Let Clear-Site-Data delete the "cache" of "origin1.com".
- GURL url = https_server()->GetURL("origin1.com", "/clear-site-data");
+ // Let Clear-Site-Data delete the "cache" of HTTPS host 2.
+ GURL url = GetURLForHTTPSHost2("/clear-site-data");
AddQuery(&url, "header", "\"cache\"");
NavigateToURL(shell(), url);
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(kTimeoutMs));
-
- // Only "origin2.com" now has cache entries.
- cache_keys = util.GetEntryKeys();
- ASSERT_EQ(2u, cache_keys.size());
- std::sort(cache_keys.begin(), cache_keys.end());
- EXPECT_EQ(url4, cache_keys[0]);
- EXPECT_EQ(url3, cache_keys[1]);
+
+ // Only HTTPS host 1 now has cache entries.
+ EXPECT_TRUE(TestCacheEntry(url1));
+ EXPECT_TRUE(TestCacheEntry(url2));
+ EXPECT_FALSE(TestCacheEntry(url3));
+ EXPECT_FALSE(TestCacheEntry(url4));
+
+ DestroyCacheTestUtilIfNecessary();
}
// Tests that closing the tab right after executing Clear-Site-Data does
// not crash.
-IN_PROC_BROWSER_TEST_F(ClearSiteDataThrottleBrowserTest, ClosedTab) {
+IN_PROC_BROWSER_TEST_F(ClearSiteDataHandlerBrowserTest, ClosedTab) {
GURL url = https_server()->GetURL("example.com", "/");
AddQuery(&url, "header", kClearCookiesHeader);
shell()->LoadURL(url);
diff --git a/chromium/content/browser/browsing_data/clear_site_data_handler_unittest.cc b/chromium/content/browser/browsing_data/clear_site_data_handler_unittest.cc
new file mode 100644
index 00000000000..c49509edccf
--- /dev/null
+++ b/chromium/content/browser/browsing_data/clear_site_data_handler_unittest.cc
@@ -0,0 +1,485 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/browsing_data/clear_site_data_handler.h"
+
+#include <memory>
+
+#include "base/bind_helpers.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/scoped_command_line.h"
+#include "base/test/scoped_task_environment.h"
+#include "content/public/browser/resource_request_info.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_util.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "net/url_request/redirect_info.h"
+#include "net/url_request/url_request_job.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+
+namespace content {
+
+using ConsoleMessagesDelegate = ClearSiteDataHandler::ConsoleMessagesDelegate;
+using Message = ClearSiteDataHandler::ConsoleMessagesDelegate::Message;
+
+namespace {
+
+const char kClearCookiesHeader[] = "\"cookies\"";
+
+WebContents* FakeWebContentsGetter() {
+ return nullptr;
+}
+
+// A slightly modified ClearSiteDataHandler for testing with dummy clearing
+// functionality.
+class TestHandler : public ClearSiteDataHandler {
+ public:
+ TestHandler(base::RepeatingCallback<WebContents*()> web_contents_getter,
+ const GURL& url,
+ const std::string& header_value,
+ int load_flags,
+ base::OnceClosure callback,
+ std::unique_ptr<ConsoleMessagesDelegate> delegate)
+ : ClearSiteDataHandler(std::move(web_contents_getter),
+ url,
+ header_value,
+ load_flags,
+ std::move(callback),
+ std::move(delegate)) {}
+ ~TestHandler() override = default;
+
+ // |HandleHeaderAndOutputConsoleMessages()| is protected and not visible in
+ // test cases.
+ bool DoHandleHeader() { return HandleHeaderAndOutputConsoleMessages(); }
+
+ MOCK_METHOD4(ClearSiteData,
+ void(const url::Origin& origin,
+ bool clear_cookies,
+ bool clear_storage,
+ bool clear_cache));
+
+ protected:
+ void ExecuteClearingTask(const url::Origin& origin,
+ bool clear_cookies,
+ bool clear_storage,
+ bool clear_cache,
+ base::OnceClosure callback) override {
+ ClearSiteData(origin, clear_cookies, clear_storage, clear_cache);
+
+ // NOTE: ResourceThrottle expects Resume() to be called asynchronously.
+ // For the purposes of this test, synchronous call works correctly, and
+ // is preferable for simplicity, so that we don't have to synchronize
+ // between triggering Clear-Site-Data and verifying test expectations.
+ std::move(callback).Run();
+ }
+};
+
+// A ConsoleDelegate that copies message to a vector |message_buffer| owned by
+// the caller instead of outputs to the console.
+// We need this override because otherwise messages are outputted as soon as
+// request finished, and we don't have a chance to check them.
+class VectorConsoleMessagesDelegate : public ConsoleMessagesDelegate {
+ public:
+ VectorConsoleMessagesDelegate(std::vector<Message>* message_buffer)
+ : message_buffer_(message_buffer) {}
+ ~VectorConsoleMessagesDelegate() override = default;
+
+ void OutputMessages(const base::RepeatingCallback<WebContents*()>&
+ web_contents_getter) override {
+ *message_buffer_ = messages();
+ }
+
+ private:
+ std::vector<Message>* message_buffer_;
+};
+
+// A ConsoleDelegate that outputs messages to a string |output_buffer| owned
+// by the caller instead of to the console (losing the level information).
+class StringConsoleMessagesDelegate : public ConsoleMessagesDelegate {
+ public:
+ StringConsoleMessagesDelegate(std::string* output_buffer) {
+ SetOutputFormattedMessageFunctionForTesting(base::BindRepeating(
+ &StringConsoleMessagesDelegate::OutputFormattedMessage,
+ base::Unretained(output_buffer)));
+ }
+
+ ~StringConsoleMessagesDelegate() override {}
+
+ private:
+ static void OutputFormattedMessage(std::string* output_buffer,
+ WebContents* web_contents,
+ ConsoleMessageLevel level,
+ const std::string& formatted_text) {
+ *output_buffer += formatted_text + "\n";
+ }
+};
+
+} // namespace
+
+class ClearSiteDataHandlerTest : public testing::Test {
+ public:
+ ClearSiteDataHandlerTest()
+ : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
+
+ private:
+ TestBrowserThreadBundle thread_bundle_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClearSiteDataHandlerTest);
+};
+
+TEST_F(ClearSiteDataHandlerTest, ParseHeaderAndExecuteClearingTask) {
+ struct TestCase {
+ const char* header;
+ bool cookies;
+ bool storage;
+ bool cache;
+ };
+
+ std::vector<TestCase> standard_test_cases = {
+ // One data type.
+ {"\"cookies\"", true, false, false},
+ {"\"storage\"", false, true, false},
+ {"\"cache\"", false, false, true},
+
+ // Two data types.
+ {"\"cookies\", \"storage\"", true, true, false},
+ {"\"cookies\", \"cache\"", true, false, true},
+ {"\"storage\", \"cache\"", false, true, true},
+
+ // Three data types.
+ {"\"storage\", \"cache\", \"cookies\"", true, true, true},
+ {"\"cache\", \"cookies\", \"storage\"", true, true, true},
+ {"\"cookies\", \"storage\", \"cache\"", true, true, true},
+
+ // The wildcard datatype is not yet shipped.
+ {"\"*\", \"storage\"", false, true, false},
+ {"\"cookies\", \"*\", \"storage\"", true, true, false},
+ {"\"*\", \"cookies\", \"*\"", true, false, false},
+
+ // Different formatting.
+ {"\"cookies\"", true, false, false},
+
+ // Duplicates.
+ {"\"cookies\", \"cookies\"", true, false, false},
+
+ // Other JSON-formatted items in the list.
+ {"\"storage\", { \"other_params\": {} }", false, true, false},
+
+ // Unknown types are ignored, but we still proceed with the deletion for
+ // those that we recognize.
+ {"\"cache\", \"foo\"", false, false, true},
+ };
+
+ std::vector<TestCase> experimental_test_cases = {
+ // Wildcard.
+ {"\"*\"", true, true, true},
+ {"\"*\", \"storage\"", true, true, true},
+ {"\"cache\", \"*\", \"storage\"", true, true, true},
+ {"\"*\", \"cookies\", \"*\"", true, true, true},
+ };
+
+ const std::vector<TestCase>* test_case_sets[] = {&standard_test_cases,
+ &experimental_test_cases};
+
+ for (const std::vector<TestCase>* test_cases : test_case_sets) {
+ base::test::ScopedCommandLine scoped_command_line;
+ if (test_cases == &experimental_test_cases) {
+ scoped_command_line.GetProcessCommandLine()->AppendSwitch(
+ switches::kEnableExperimentalWebPlatformFeatures);
+ }
+
+ for (const TestCase& test_case : *test_cases) {
+ SCOPED_TRACE(test_case.header);
+
+ // Test that ParseHeader works correctly.
+ bool actual_cookies;
+ bool actual_storage;
+ bool actual_cache;
+
+ GURL url("https://example.com");
+ ConsoleMessagesDelegate console_delegate;
+
+ EXPECT_TRUE(ClearSiteDataHandler::ParseHeaderForTesting(
+ test_case.header, &actual_cookies, &actual_storage, &actual_cache,
+ &console_delegate, url));
+
+ EXPECT_EQ(test_case.cookies, actual_cookies);
+ EXPECT_EQ(test_case.storage, actual_storage);
+ EXPECT_EQ(test_case.cache, actual_cache);
+
+ // Test that a call with the above parameters actually reaches
+ // ExecuteClearingTask().
+ net::TestURLRequestContext context;
+ std::unique_ptr<net::URLRequest> request(context.CreateRequest(
+ url, net::DEFAULT_PRIORITY, nullptr, TRAFFIC_ANNOTATION_FOR_TESTS));
+ TestHandler handler(base::BindRepeating(&FakeWebContentsGetter),
+ request->url(), test_case.header,
+ request->load_flags(), base::DoNothing(),
+ std::make_unique<ConsoleMessagesDelegate>());
+
+ EXPECT_CALL(handler,
+ ClearSiteData(url::Origin::Create(url), test_case.cookies,
+ test_case.storage, test_case.cache));
+ bool defer = handler.DoHandleHeader();
+ EXPECT_TRUE(defer);
+
+ testing::Mock::VerifyAndClearExpectations(&handler);
+ }
+ }
+}
+
+TEST_F(ClearSiteDataHandlerTest, InvalidHeader) {
+ struct TestCase {
+ const char* header;
+ const char* console_message;
+ } test_cases[] = {{"", "No recognized types specified.\n"},
+ {"\"unclosed",
+ "Unrecognized type: \"unclosed.\n"
+ "No recognized types specified.\n"},
+ {"\"passwords\"",
+ "Unrecognized type: \"passwords\".\n"
+ "No recognized types specified.\n"},
+ // The wildcard datatype is not yet shipped.
+ {"[ \"*\" ]",
+ "Unrecognized type: [ \"*\" ].\n"
+ "No recognized types specified.\n"},
+ {"[ \"list\" ]",
+ "Unrecognized type: [ \"list\" ].\n"
+ "No recognized types specified.\n"},
+ {"{ \"cookies\": [ \"a\" ] }",
+ "Unrecognized type: { \"cookies\": [ \"a\" ] }.\n"
+ "No recognized types specified.\n"},
+ {"\"кукис\", \"сторидж\", \"кэш\"",
+ "Must only contain ASCII characters.\n"}};
+
+ for (const TestCase& test_case : test_cases) {
+ SCOPED_TRACE(test_case.header);
+
+ bool actual_cookies;
+ bool actual_storage;
+ bool actual_cache;
+
+ ConsoleMessagesDelegate console_delegate;
+
+ EXPECT_FALSE(ClearSiteDataHandler::ParseHeaderForTesting(
+ test_case.header, &actual_cookies, &actual_storage, &actual_cache,
+ &console_delegate, GURL()));
+
+ std::string multiline_message;
+ for (const auto& message : console_delegate.messages()) {
+ EXPECT_EQ(CONSOLE_MESSAGE_LEVEL_ERROR, message.level);
+ multiline_message += message.text + "\n";
+ }
+
+ EXPECT_EQ(test_case.console_message, multiline_message);
+ }
+}
+
+TEST_F(ClearSiteDataHandlerTest, ClearCookieSuccess) {
+ net::TestURLRequestContext context;
+ std::unique_ptr<net::URLRequest> request(
+ context.CreateRequest(GURL("https://example.com"), net::DEFAULT_PRIORITY,
+ nullptr, TRAFFIC_ANNOTATION_FOR_TESTS));
+ std::vector<Message> message_buffer;
+ TestHandler handler(
+ base::BindRepeating(&FakeWebContentsGetter), request->url(),
+ kClearCookiesHeader, request->load_flags(), base::DoNothing(),
+ std::make_unique<VectorConsoleMessagesDelegate>(&message_buffer));
+
+ EXPECT_CALL(handler, ClearSiteData(_, _, _, _));
+ bool defer = handler.DoHandleHeader();
+ EXPECT_TRUE(defer);
+ EXPECT_EQ(1u, message_buffer.size());
+ EXPECT_EQ(
+ "Cleared data types: \"cookies\". "
+ "Clearing channel IDs and HTTP authentication cache is currently "
+ "not supported, as it breaks active network connections.",
+ message_buffer.front().text);
+ EXPECT_EQ(message_buffer.front().level, CONSOLE_MESSAGE_LEVEL_INFO);
+ testing::Mock::VerifyAndClearExpectations(&handler);
+}
+
+TEST_F(ClearSiteDataHandlerTest, LoadDoNotSaveCookies) {
+ net::TestURLRequestContext context;
+ std::unique_ptr<net::URLRequest> request(
+ context.CreateRequest(GURL("https://example.com"), net::DEFAULT_PRIORITY,
+ nullptr, TRAFFIC_ANNOTATION_FOR_TESTS));
+ request->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES);
+ std::vector<Message> message_buffer;
+ TestHandler handler(
+ base::BindRepeating(&FakeWebContentsGetter), request->url(),
+ kClearCookiesHeader, request->load_flags(), base::DoNothing(),
+ std::make_unique<VectorConsoleMessagesDelegate>(&message_buffer));
+
+ EXPECT_CALL(handler, ClearSiteData(_, _, _, _)).Times(0);
+ bool defer = handler.DoHandleHeader();
+ EXPECT_FALSE(defer);
+ EXPECT_EQ(1u, message_buffer.size());
+ EXPECT_EQ(
+ "The request's credentials mode prohibits modifying cookies "
+ "and other local data.",
+ message_buffer.front().text);
+ EXPECT_EQ(CONSOLE_MESSAGE_LEVEL_ERROR, message_buffer.front().level);
+ testing::Mock::VerifyAndClearExpectations(&handler);
+}
+
+TEST_F(ClearSiteDataHandlerTest, InvalidOrigin) {
+ struct TestCase {
+ const char* origin;
+ bool expect_success;
+ std::string error_message; // Tested only if |expect_success| = false.
+ } kTestCases[] = {
+ // The handler only works on secure origins.
+ {"https://secure-origin.com", true, ""},
+ {"filesystem:https://secure-origin.com/temporary/", true, ""},
+
+ // That includes localhost.
+ {"http://localhost", true, ""},
+
+ // Not on insecure origins.
+ {"http://insecure-origin.com", false,
+ "Not supported for insecure origins."},
+ {"filesystem:http://insecure-origin.com/temporary/", false,
+ "Not supported for insecure origins."},
+
+ // Not on unique origins.
+ {"data:unique-origin;", false, "Not supported for unique origins."},
+ };
+
+ net::TestURLRequestContext context;
+
+ for (const TestCase& test_case : kTestCases) {
+ std::unique_ptr<net::URLRequest> request(
+ context.CreateRequest(GURL(test_case.origin), net::DEFAULT_PRIORITY,
+ nullptr, TRAFFIC_ANNOTATION_FOR_TESTS));
+ std::vector<Message> message_buffer;
+ TestHandler handler(
+ base::BindRepeating(&FakeWebContentsGetter), request->url(),
+ kClearCookiesHeader, request->load_flags(), base::DoNothing(),
+ std::make_unique<VectorConsoleMessagesDelegate>(&message_buffer));
+
+ EXPECT_CALL(handler, ClearSiteData(_, _, _, _))
+ .Times(test_case.expect_success ? 1 : 0);
+
+ bool defer = handler.DoHandleHeader();
+
+ EXPECT_EQ(defer, test_case.expect_success);
+ EXPECT_EQ(message_buffer.size(), 1u);
+ EXPECT_EQ(test_case.expect_success ? CONSOLE_MESSAGE_LEVEL_INFO
+ : CONSOLE_MESSAGE_LEVEL_ERROR,
+ message_buffer.front().level);
+ if (!test_case.expect_success) {
+ EXPECT_EQ(test_case.error_message, message_buffer.front().text);
+ }
+ testing::Mock::VerifyAndClearExpectations(&handler);
+ }
+}
+
+// Verifies that console outputs from various actions on different URLs
+// are correctly pretty-printed to the console.
+TEST_F(ClearSiteDataHandlerTest, FormattedConsoleOutput) {
+ struct TestCase {
+ const char* header;
+ const char* url;
+ const char* output;
+ } kTestCases[] = {
+ // Successful deletion outputs one line, and in case of cookies, also
+ // a disclaimer about omitted data (https://crbug.com/798760).
+ {"\"cookies\"", "https://origin1.com/foo",
+ "Clear-Site-Data header on 'https://origin1.com/foo': "
+ "Cleared data types: \"cookies\". "
+ "Clearing channel IDs and HTTP authentication cache is currently "
+ "not supported, as it breaks active network connections.\n"},
+
+ // Another successful deletion.
+ {"\"storage\"", "https://origin2.com/foo",
+ "Clear-Site-Data header on 'https://origin2.com/foo': "
+ "Cleared data types: \"storage\".\n"},
+
+ // Redirect to the same URL. Unsuccessful deletion outputs two lines.
+ {"\"foo\"", "https://origin2.com/foo",
+ "Clear-Site-Data header on 'https://origin2.com/foo': "
+ "Unrecognized type: \"foo\".\n"
+ "Clear-Site-Data header on 'https://origin2.com/foo': "
+ "No recognized types specified.\n"},
+
+ // Redirect to another URL. Another unsuccessful deletion.
+ {"\"some text\"", "https://origin3.com/bar",
+ "Clear-Site-Data header on 'https://origin3.com/bar': "
+ "Unrecognized type: \"some text\".\n"
+ "Clear-Site-Data header on 'https://origin3.com/bar': "
+ "No recognized types specified.\n"},
+
+ // Yet another on the same URL.
+ {"\"passwords\"", "https://origin3.com/bar",
+ "Clear-Site-Data header on 'https://origin3.com/bar': "
+ "Unrecognized type: \"passwords\".\n"
+ "Clear-Site-Data header on 'https://origin3.com/bar': "
+ "No recognized types specified.\n"},
+
+ // Successful deletion on the same URL.
+ {"\"cache\"", "https://origin3.com/bar",
+ "Clear-Site-Data header on 'https://origin3.com/bar': "
+ "Cleared data types: \"cache\".\n"},
+
+ // Redirect to the original URL.
+ // Successful deletion outputs one line.
+ {"", "https://origin1.com/foo",
+ "Clear-Site-Data header on 'https://origin1.com/foo': "
+ "No recognized types specified.\n"}};
+
+ // TODO(crbug.com/876931): Delay output until next frame for navigations.
+ bool kHandlerTypeIsNavigation[] = {false};
+
+ for (bool navigation : kHandlerTypeIsNavigation) {
+ SCOPED_TRACE(navigation ? "Navigation test." : "Subresource test.");
+
+ net::TestURLRequestContext context;
+ std::unique_ptr<net::URLRequest> request(
+ context.CreateRequest(GURL(kTestCases[0].url), net::DEFAULT_PRIORITY,
+ nullptr, TRAFFIC_ANNOTATION_FOR_TESTS));
+
+ std::string output_buffer;
+ std::string last_seen_console_output;
+
+ // |NetworkServiceClient| creates a new |ClearSiteDataHandler| for each
+ // navigation, redirect, or subresource header responses.
+ for (size_t i = 0; i < base::size(kTestCases); i++) {
+ TestHandler handler(
+ base::BindRepeating(&FakeWebContentsGetter), GURL(kTestCases[i].url),
+ kTestCases[i].header, request->load_flags(), base::DoNothing(),
+ std::make_unique<StringConsoleMessagesDelegate>(&output_buffer));
+ handler.DoHandleHeader();
+
+ // For navigations, the console should be still empty. For subresource
+ // requests, messages should be added progressively.
+ if (navigation) {
+ EXPECT_TRUE(output_buffer.empty());
+ } else {
+ EXPECT_EQ(last_seen_console_output + kTestCases[i].output,
+ output_buffer);
+ }
+
+ last_seen_console_output = output_buffer;
+ }
+
+ // At the end, the console must contain all messages regardless of whether
+ // it was a navigation or a subresource request.
+ std::string expected_output;
+ for (struct TestCase& test_case : kTestCases)
+ expected_output += test_case.output;
+ EXPECT_EQ(expected_output, output_buffer);
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/browsing_data/clear_site_data_throttle.cc b/chromium/content/browser/browsing_data/clear_site_data_throttle.cc
index 2f644a6dd4d..ba0a6e39c53 100644
--- a/chromium/content/browser/browsing_data/clear_site_data_throttle.cc
+++ b/chromium/content/browser/browsing_data/clear_site_data_throttle.cc
@@ -34,22 +34,24 @@ namespace content {
namespace {
-const char kNameForLogging[] = "ClearSiteDataThrottle";
+// Appending '2' to avoid naming conflicts with 'clear_site_data_handler.h' in
+// jumbo builds. This file will be removed later as mentioned in the header.
+const char kNameForLogging2[] = "ClearSiteDataThrottle";
-const char kClearSiteDataHeader[] = "Clear-Site-Data";
+const char kClearSiteDataHeader2[] = "Clear-Site-Data";
// Datatypes.
-const char kDatatypeWildcard[] = "\"*\"";
-const char kDatatypeCookies[] = "\"cookies\"";
-const char kDatatypeStorage[] = "\"storage\"";
-const char kDatatypeCache[] = "\"cache\"";
+const char kDatatypeWildcard2[] = "\"*\"";
+const char kDatatypeCookies2[] = "\"cookies\"";
+const char kDatatypeStorage2[] = "\"storage\"";
+const char kDatatypeCache2[] = "\"cache\"";
// Pretty-printed log output.
-const char kConsoleMessageTemplate[] = "Clear-Site-Data header on '%s': %s";
-const char kConsoleMessageCleared[] = "Cleared data types: %s.";
-const char kConsoleMessageDatatypeSeparator[] = ", ";
+const char kConsoleMessageTemplate2[] = "Clear-Site-Data header on '%s': %s";
+const char kConsoleMessageCleared2[] = "Cleared data types: %s.";
+const char kConsoleMessageDatatypeSeparator2[] = ", ";
-bool AreExperimentalFeaturesEnabled() {
+bool AreExperimentalFeaturesEnabled2() {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableExperimentalWebPlatformFeatures);
}
@@ -60,7 +62,7 @@ bool IsNavigationRequest(net::URLRequest* request) {
}
// Represents the parameters as a single number to be recorded in a histogram.
-int ParametersMask(bool clear_cookies, bool clear_storage, bool clear_cache) {
+int ParametersMask2(bool clear_cookies, bool clear_storage, bool clear_cache) {
return static_cast<int>(clear_cookies) * (1 << 0) +
static_cast<int>(clear_storage) * (1 << 1) +
static_cast<int>(clear_cache) * (1 << 2);
@@ -202,9 +204,9 @@ class UIThreadSiteDataClearer : public BrowsingDataRemover::Observer {
};
// Outputs a single |formatted_message| on the UI thread.
-void OutputFormattedMessage(WebContents* web_contents,
- ConsoleMessageLevel level,
- const std::string& formatted_text) {
+void OutputFormattedMessage2(WebContents* web_contents,
+ ConsoleMessageLevel level,
+ const std::string& formatted_text) {
if (web_contents)
web_contents->GetMainFrame()->AddMessageToConsole(level, formatted_text);
}
@@ -222,10 +224,10 @@ void OutputMessagesOnUIThread(
WebContents* web_contents = web_contents_getter.Run();
for (const auto& message : messages) {
- // Prefix each message with |kConsoleMessageTemplate|.
+ // Prefix each message with |kConsoleMessageTemplate2|.
output_formatted_message_function.Run(
web_contents, message.level,
- base::StringPrintf(kConsoleMessageTemplate, message.url.spec().c_str(),
+ base::StringPrintf(kConsoleMessageTemplate2, message.url.spec().c_str(),
message.text.c_str()));
}
}
@@ -236,7 +238,8 @@ void OutputMessagesOnUIThread(
// ConsoleMessagesDelegate
ClearSiteDataThrottle::ConsoleMessagesDelegate::ConsoleMessagesDelegate()
- : output_formatted_message_function_(base::Bind(&OutputFormattedMessage)) {}
+ : output_formatted_message_function_(
+ base::BindRepeating(&OutputFormattedMessage2)) {}
ClearSiteDataThrottle::ConsoleMessagesDelegate::~ConsoleMessagesDelegate() {}
@@ -292,7 +295,7 @@ ClearSiteDataThrottle::~ClearSiteDataThrottle() {
}
const char* ClearSiteDataThrottle::GetNameForLogging() const {
- return kNameForLogging;
+ return kNameForLogging2;
}
void ClearSiteDataThrottle::WillRedirectRequest(
@@ -351,7 +354,7 @@ bool ClearSiteDataThrottle::HandleHeader() {
std::string header_value;
if (!headers ||
- !headers->GetNormalizedHeader(kClearSiteDataHeader, &header_value)) {
+ !headers->GetNormalizedHeader(kClearSiteDataHeader2, &header_value)) {
return false;
}
@@ -422,7 +425,7 @@ bool ClearSiteDataThrottle::HandleHeader() {
// Record the call parameters.
UMA_HISTOGRAM_ENUMERATION(
"Navigation.ClearSiteData.Parameters",
- ParametersMask(clear_cookies, clear_storage, clear_cache), (1 << 3));
+ ParametersMask2(clear_cookies, clear_storage, clear_cache), (1 << 3));
base::WeakPtr<ClearSiteDataThrottle> weak_ptr =
weak_ptr_factory_.GetWeakPtr();
@@ -463,17 +466,17 @@ bool ClearSiteDataThrottle::ParseHeader(const std::string& header,
for (unsigned i = 0; i < input_types.size(); i++) {
bool* data_type = nullptr;
- if (AreExperimentalFeaturesEnabled() &&
- input_types[i] == kDatatypeWildcard) {
- input_types.push_back(kDatatypeCookies);
- input_types.push_back(kDatatypeStorage);
- input_types.push_back(kDatatypeCache);
+ if (AreExperimentalFeaturesEnabled2() &&
+ input_types[i] == kDatatypeWildcard2) {
+ input_types.push_back(kDatatypeCookies2);
+ input_types.push_back(kDatatypeStorage2);
+ input_types.push_back(kDatatypeCache2);
continue;
- } else if (input_types[i] == kDatatypeCookies) {
+ } else if (input_types[i] == kDatatypeCookies2) {
data_type = clear_cookies;
- } else if (input_types[i] == kDatatypeStorage) {
+ } else if (input_types[i] == kDatatypeStorage2) {
data_type = clear_storage;
- } else if (input_types[i] == kDatatypeCache) {
+ } else if (input_types[i] == kDatatypeCache2) {
data_type = clear_cache;
} else {
delegate->AddMessage(
@@ -490,7 +493,7 @@ bool ClearSiteDataThrottle::ParseHeader(const std::string& header,
*data_type = true;
if (!output_types.empty())
- output_types += kConsoleMessageDatatypeSeparator;
+ output_types += kConsoleMessageDatatypeSeparator2;
output_types += input_types[i];
}
@@ -503,7 +506,7 @@ bool ClearSiteDataThrottle::ParseHeader(const std::string& header,
// Pretty-print which types are to be cleared.
// TODO(crbug.com/798760): Remove the disclaimer about cookies.
std::string console_output =
- base::StringPrintf(kConsoleMessageCleared, output_types.c_str());
+ base::StringPrintf(kConsoleMessageCleared2, output_types.c_str());
if (*clear_cookies) {
console_output +=
" Clearing channel IDs and HTTP authentication cache is currently not"
diff --git a/chromium/content/browser/browsing_data/clear_site_data_throttle.h b/chromium/content/browser/browsing_data/clear_site_data_throttle.h
index 31d26541c9f..053ce9fe6f2 100644
--- a/chromium/content/browser/browsing_data/clear_site_data_throttle.h
+++ b/chromium/content/browser/browsing_data/clear_site_data_throttle.h
@@ -34,6 +34,9 @@ namespace content {
class WebContents;
+// TODO(crbug.com/876931): To be removed after Network Service was enabled by
+// default. The header will be handled by |NetworkServiceNetworkDelegate| and
+// |ClearSiteDataHandler| instead.
// This throttle parses the Clear-Site-Data header and executes the clearing
// of browsing data. The resource load is delayed until the header is parsed
// and, if valid, until the browsing data are deleted. See the W3C working draft
diff --git a/chromium/content/browser/browsing_data/conditional_cache_deletion_helper.cc b/chromium/content/browser/browsing_data/conditional_cache_deletion_helper.cc
index fcaa95d6025..d0a5a8e4e67 100644
--- a/chromium/content/browser/browsing_data/conditional_cache_deletion_helper.cc
+++ b/chromium/content/browser/browsing_data/conditional_cache_deletion_helper.cc
@@ -85,8 +85,8 @@ void ConditionalCacheDeletionHelper::IterateOverEntries(int error) {
previous_entry_ = current_entry_;
error = iterator_->OpenNextEntry(
&current_entry_,
- base::Bind(&ConditionalCacheDeletionHelper::IterateOverEntries,
- base::Unretained(this)));
+ base::BindOnce(&ConditionalCacheDeletionHelper::IterateOverEntries,
+ base::Unretained(this)));
}
}
diff --git a/chromium/content/browser/browsing_data/storage_partition_http_cache_data_remover.cc b/chromium/content/browser/browsing_data/storage_partition_http_cache_data_remover.cc
index df1debded9d..a6551a0c099 100644
--- a/chromium/content/browser/browsing_data/storage_partition_http_cache_data_remover.cc
+++ b/chromium/content/browser/browsing_data/storage_partition_http_cache_data_remover.cc
@@ -9,8 +9,11 @@
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/browser/browsing_data/conditional_cache_deletion_helper.h"
+#include "content/browser/code_cache/generated_code_cache.h"
+#include "content/browser/code_cache/generated_code_cache_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
+#include "content/public/common/content_features.h"
#include "net/disk_cache/disk_cache.h"
#include "net/http/http_cache.h"
#include "net/url_request/url_request_context.h"
@@ -24,12 +27,14 @@ StoragePartitionHttpCacheDataRemover::StoragePartitionHttpCacheDataRemover(
base::Time delete_begin,
base::Time delete_end,
net::URLRequestContextGetter* main_context_getter,
- net::URLRequestContextGetter* media_context_getter)
+ net::URLRequestContextGetter* media_context_getter,
+ GeneratedCodeCacheContext* generated_code_cache_context)
: url_predicate_(url_predicate),
delete_begin_(delete_begin),
delete_end_(delete_end),
main_context_getter_(main_context_getter),
media_context_getter_(media_context_getter),
+ generated_code_cache_context_(generated_code_cache_context),
next_cache_state_(CacheState::NONE),
cache_(nullptr) {}
@@ -42,7 +47,8 @@ StoragePartitionHttpCacheDataRemover::CreateForRange(
return new StoragePartitionHttpCacheDataRemover(
base::Callback<bool(const GURL&)>(), // Null callback.
delete_begin, delete_end, storage_partition->GetURLRequestContext(),
- storage_partition->GetMediaURLRequestContext());
+ storage_partition->GetMediaURLRequestContext(),
+ storage_partition->GetGeneratedCodeCacheContext());
}
// static.
@@ -55,7 +61,8 @@ StoragePartitionHttpCacheDataRemover::CreateForURLsAndRange(
return new StoragePartitionHttpCacheDataRemover(
url_predicate, delete_begin, delete_end,
storage_partition->GetURLRequestContext(),
- storage_partition->GetMediaURLRequestContext());
+ storage_partition->GetMediaURLRequestContext(),
+ storage_partition->GetGeneratedCodeCacheContext());
}
StoragePartitionHttpCacheDataRemover::~StoragePartitionHttpCacheDataRemover() {}
@@ -90,7 +97,8 @@ void StoragePartitionHttpCacheDataRemover::ClearedHttpCache() {
// The expected state sequence is CacheState::NONE --> CacheState::CREATE_MAIN
// --> CacheState::DELETE_MAIN --> CacheState::CREATE_MEDIA -->
-// CacheState::DELETE_MEDIA --> CacheState::DONE, and any errors are ignored.
+// CacheState::DELETE_MEDIA --> CacheState::DELETE_CODE --> CacheState::DONE,
+// and any errors are ignored.
void StoragePartitionHttpCacheDataRemover::DoClearCache(int rv) {
DCHECK_NE(CacheState::NONE, next_cache_state_);
@@ -108,7 +116,7 @@ void StoragePartitionHttpCacheDataRemover::DoClearCache(int rv) {
if (!getter) {
next_cache_state_ = (next_cache_state_ == CacheState::CREATE_MAIN)
? CacheState::CREATE_MEDIA
- : CacheState::DONE;
+ : CacheState::DELETE_CODE;
break;
}
@@ -127,15 +135,15 @@ void StoragePartitionHttpCacheDataRemover::DoClearCache(int rv) {
rv = http_cache->GetBackend(
&cache_,
- base::Bind(&StoragePartitionHttpCacheDataRemover::DoClearCache,
- base::Unretained(this)));
+ base::BindOnce(&StoragePartitionHttpCacheDataRemover::DoClearCache,
+ base::Unretained(this)));
break;
}
case CacheState::DELETE_MAIN:
case CacheState::DELETE_MEDIA: {
next_cache_state_ = (next_cache_state_ == CacheState::DELETE_MAIN)
? CacheState::CREATE_MEDIA
- : CacheState::DONE;
+ : CacheState::DELETE_CODE;
// |cache_| can be null if it cannot be initialized.
if (cache_) {
@@ -148,19 +156,38 @@ void StoragePartitionHttpCacheDataRemover::DoClearCache(int rv) {
&StoragePartitionHttpCacheDataRemover::DoClearCache,
base::Unretained(this)));
} else if (delete_begin_.is_null() && delete_end_.is_max()) {
- rv = cache_->DoomAllEntries(
- base::Bind(&StoragePartitionHttpCacheDataRemover::DoClearCache,
- base::Unretained(this)));
+ rv = cache_->DoomAllEntries(base::BindOnce(
+ &StoragePartitionHttpCacheDataRemover::DoClearCache,
+ base::Unretained(this)));
} else {
rv = cache_->DoomEntriesBetween(
delete_begin_, delete_end_,
- base::Bind(&StoragePartitionHttpCacheDataRemover::DoClearCache,
- base::Unretained(this)));
+ base::BindOnce(
+ &StoragePartitionHttpCacheDataRemover::DoClearCache,
+ base::Unretained(this)));
}
cache_ = nullptr;
}
break;
}
+ case CacheState::DELETE_CODE: {
+ next_cache_state_ = CacheState::DONE;
+ if (base::FeatureList::IsEnabled(features::kIsolatedCodeCache)) {
+ DCHECK(generated_code_cache_context_);
+ GeneratedCodeCache* code_cache =
+ generated_code_cache_context_->generated_code_cache();
+ if (code_cache) {
+ auto callback = base::BindRepeating(
+ &StoragePartitionHttpCacheDataRemover::DoClearCache,
+ base::Unretained(this));
+ // TODO(crbug.com/866419): Currently we just clear the entire cache.
+ // Change it to conditionally clear the entries based on the
+ // filters.
+ rv = code_cache->ClearCache(callback);
+ }
+ }
+ break;
+ }
case CacheState::DONE: {
cache_ = nullptr;
next_cache_state_ = CacheState::NONE;
diff --git a/chromium/content/browser/browsing_data/storage_partition_http_cache_data_remover.h b/chromium/content/browser/browsing_data/storage_partition_http_cache_data_remover.h
index 6d644173b52..665a8f4e6b8 100644
--- a/chromium/content/browser/browsing_data/storage_partition_http_cache_data_remover.h
+++ b/chromium/content/browser/browsing_data/storage_partition_http_cache_data_remover.h
@@ -25,6 +25,7 @@ class URLRequestContextGetter;
namespace content {
class StoragePartition;
+class GeneratedCodeCacheContext;
// Helper to remove http cache data from a StoragePartition.
class StoragePartitionHttpCacheDataRemover {
@@ -56,6 +57,7 @@ class StoragePartitionHttpCacheDataRemover {
CREATE_MEDIA,
DELETE_MAIN,
DELETE_MEDIA,
+ DELETE_CODE,
DONE
};
@@ -64,7 +66,8 @@ class StoragePartitionHttpCacheDataRemover {
base::Time delete_begin,
base::Time delete_end,
net::URLRequestContextGetter* main_context_getter,
- net::URLRequestContextGetter* media_context_getter);
+ net::URLRequestContextGetter* media_context_getter,
+ GeneratedCodeCacheContext* generated_code_cache_context);
// StoragePartitionHttpCacheDataRemover deletes itself (using DeleteHelper)
// and is not supposed to be deleted by other objects so make destructor
@@ -84,6 +87,7 @@ class StoragePartitionHttpCacheDataRemover {
const scoped_refptr<net::URLRequestContextGetter> main_context_getter_;
const scoped_refptr<net::URLRequestContextGetter> media_context_getter_;
+ const scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context_;
base::OnceClosure done_callback_;
diff --git a/chromium/content/browser/browsing_instance.cc b/chromium/content/browser/browsing_instance.cc
index 3758184e743..9b24ae580a6 100644
--- a/chromium/content/browser/browsing_instance.cc
+++ b/chromium/content/browser/browsing_instance.cc
@@ -21,16 +21,15 @@ BrowsingInstance::BrowsingInstance(BrowserContext* browser_context)
}
bool BrowsingInstance::HasSiteInstance(const GURL& url) {
- std::string site =
- SiteInstanceImpl::GetSiteForURL(browser_context_, url)
- .possibly_invalid_spec();
+ std::string site = SiteInstance::GetSiteForURL(browser_context_, url)
+ .possibly_invalid_spec();
return site_instance_map_.find(site) != site_instance_map_.end();
}
scoped_refptr<SiteInstanceImpl> BrowsingInstance::GetSiteInstanceForURL(
const GURL& url) {
- std::string site = SiteInstanceImpl::GetSiteForURL(browser_context_, url)
+ std::string site = SiteInstance::GetSiteForURL(browser_context_, url)
.possibly_invalid_spec();
SiteInstanceMap::iterator i = site_instance_map_.find(site);
diff --git a/chromium/content/browser/cache_storage/OWNERS b/chromium/content/browser/cache_storage/OWNERS
index f802dd14208..fd09fa5dd2c 100644
--- a/chromium/content/browser/cache_storage/OWNERS
+++ b/chromium/content/browser/cache_storage/OWNERS
@@ -1,6 +1,7 @@
nhiroki@chromium.org
jkarlin@chromium.org
jsbell@chromium.org
+pwnall@chromium.org
# TEAM: storage-dev@chromium.org
# COMPONENT: Blink>Storage>CacheStorage
diff --git a/chromium/content/browser/cache_storage/cache_storage.cc b/chromium/content/browser/cache_storage/cache_storage.cc
index d91b54a4d2a..78508c8b6f1 100644
--- a/chromium/content/browser/cache_storage/cache_storage.cc
+++ b/chromium/content/browser/cache_storage/cache_storage.cc
@@ -104,7 +104,7 @@ struct CacheStorage::CacheMatchResponse {
~CacheMatchResponse() = default;
CacheStorageError error;
- std::unique_ptr<ServiceWorkerResponse> service_worker_response;
+ blink::mojom::FetchAPIResponsePtr response;
std::unique_ptr<storage::BlobDataHandle> blob_data_handle;
};
@@ -717,7 +717,7 @@ void CacheStorage::MatchAllCaches(
void CacheStorage::WriteToCache(
const std::string& cache_name,
std::unique_ptr<ServiceWorkerFetchRequest> request,
- std::unique_ptr<ServiceWorkerResponse> response,
+ blink::mojom::FetchAPIResponsePtr response,
CacheStorage::ErrorCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -1038,7 +1038,7 @@ void CacheStorage::MatchCacheDidMatch(
CacheStorageCacheHandle cache_handle,
CacheStorageCache::ResponseCallback callback,
CacheStorageError error,
- std::unique_ptr<ServiceWorkerResponse> response) {
+ blink::mojom::FetchAPIResponsePtr response) {
std::move(callback).Run(error, std::move(response));
}
@@ -1076,10 +1076,9 @@ void CacheStorage::MatchAllCachesDidMatch(
CacheMatchResponse* out_match_response,
const base::RepeatingClosure& barrier_closure,
CacheStorageError error,
- std::unique_ptr<ServiceWorkerResponse> service_worker_response) {
+ blink::mojom::FetchAPIResponsePtr response) {
out_match_response->error = error;
- out_match_response->service_worker_response =
- std::move(service_worker_response);
+ out_match_response->response = std::move(response);
barrier_closure.Run();
}
@@ -1090,7 +1089,7 @@ void CacheStorage::MatchAllCachesDidMatchAll(
if (match_response.error == CacheStorageError::kErrorNotFound)
continue;
std::move(callback).Run(match_response.error,
- std::move(match_response.service_worker_response));
+ std::move(match_response.response));
return;
}
std::move(callback).Run(CacheStorageError::kErrorNotFound, nullptr);
@@ -1099,7 +1098,7 @@ void CacheStorage::MatchAllCachesDidMatchAll(
void CacheStorage::WriteToCacheImpl(
const std::string& cache_name,
std::unique_ptr<ServiceWorkerFetchRequest> request,
- std::unique_ptr<ServiceWorkerResponse> response,
+ blink::mojom::FetchAPIResponsePtr response,
CacheStorage::ErrorCallback callback) {
CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_name);
diff --git a/chromium/content/browser/cache_storage/cache_storage.h b/chromium/content/browser/cache_storage/cache_storage.h
index af34ef18253..a594d0923ea 100644
--- a/chromium/content/browser/cache_storage/cache_storage.h
+++ b/chromium/content/browser/cache_storage/cache_storage.h
@@ -121,7 +121,7 @@ class CONTENT_EXPORT CacheStorage : public CacheStorageCacheObserver {
// Puts the request/response pair in the cache.
void WriteToCache(const std::string& cache_name,
std::unique_ptr<ServiceWorkerFetchRequest> request,
- std::unique_ptr<ServiceWorkerResponse> response,
+ blink::mojom::FetchAPIResponsePtr response,
CacheStorage::ErrorCallback callback);
// Sums the sizes of each cache and closes them. Runs |callback| with the
@@ -214,18 +214,17 @@ class CONTENT_EXPORT CacheStorage : public CacheStorageCacheObserver {
void MatchCacheDidMatch(CacheStorageCacheHandle cache_handle,
CacheStorageCache::ResponseCallback callback,
blink::mojom::CacheStorageError error,
- std::unique_ptr<ServiceWorkerResponse> response);
+ blink::mojom::FetchAPIResponsePtr response);
// The MatchAllCaches callbacks are below.
void MatchAllCachesImpl(std::unique_ptr<ServiceWorkerFetchRequest> request,
blink::mojom::QueryParamsPtr match_params,
CacheStorageCache::ResponseCallback callback);
- void MatchAllCachesDidMatch(
- CacheStorageCacheHandle cache_handle,
- CacheMatchResponse* out_match_response,
- const base::RepeatingClosure& barrier_closure,
- blink::mojom::CacheStorageError error,
- std::unique_ptr<ServiceWorkerResponse> service_worker_response);
+ void MatchAllCachesDidMatch(CacheStorageCacheHandle cache_handle,
+ CacheMatchResponse* out_match_response,
+ const base::RepeatingClosure& barrier_closure,
+ blink::mojom::CacheStorageError error,
+ blink::mojom::FetchAPIResponsePtr response);
void MatchAllCachesDidMatchAll(
std::unique_ptr<std::vector<CacheMatchResponse>> match_responses,
CacheStorageCache::ResponseCallback callback);
@@ -233,7 +232,7 @@ class CONTENT_EXPORT CacheStorage : public CacheStorageCacheObserver {
// WriteToCache callbacks.
void WriteToCacheImpl(const std::string& cache_name,
std::unique_ptr<ServiceWorkerFetchRequest> request,
- std::unique_ptr<ServiceWorkerResponse> response,
+ blink::mojom::FetchAPIResponsePtr response,
CacheStorage::ErrorCallback callback);
void GetSizeThenCloseAllCachesImpl(SizeCallback callback);
diff --git a/chromium/content/browser/cache_storage/cache_storage_cache.cc b/chromium/content/browser/cache_storage/cache_storage_cache.cc
index f853ed819ad..a4e3aa14d58 100644
--- a/chromium/content/browser/cache_storage/cache_storage_cache.cc
+++ b/chromium/content/browser/cache_storage/cache_storage_cache.cc
@@ -14,6 +14,7 @@
#include "base/barrier_closure.h"
#include "base/bind_helpers.h"
+#include "base/containers/flat_map.h"
#include "base/files/file_path.h"
#include "base/guid.h"
#include "base/macros.h"
@@ -22,6 +23,7 @@
#include "base/numerics/checked_math.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/browser/cache_storage/cache_storage.pb.h"
#include "content/browser/cache_storage/cache_storage_blob_to_disk_cache.h"
@@ -48,14 +50,18 @@
#include "storage/browser/quota/quota_manager_proxy.h"
#include "storage/common/blob_storage/blob_handle.h"
#include "storage/common/storage_histograms.h"
+#include "third_party/blink/public/common/cache_storage/cache_storage_utils.h"
#include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
using blink::mojom::CacheStorageError;
+using blink::mojom::CacheStorageVerboseError;
namespace content {
namespace {
+using ResponseHeaderMap = base::flat_map<std::string, std::string>;
+
const size_t kMaxQueryCacheResultBytes =
1024 * 1024 * 10; // 10MB query cache limit
@@ -131,8 +137,12 @@ void ReadMetadataDidReadMetadata(disk_cache::Entry* entry,
bool VaryMatches(const ServiceWorkerHeaderMap& request,
const ServiceWorkerHeaderMap& cached_request,
- const ServiceWorkerHeaderMap& response) {
- ServiceWorkerHeaderMap::const_iterator vary_iter = response.find("vary");
+ const ResponseHeaderMap& response) {
+ auto vary_iter = std::find_if(
+ response.begin(), response.end(),
+ [](const ResponseHeaderMap::value_type& pair) -> bool {
+ return base::CompareCaseInsensitiveASCII(pair.first, "vary") == 0;
+ });
if (vary_iter == response.end())
return true;
@@ -161,6 +171,84 @@ bool VaryMatches(const ServiceWorkerHeaderMap& request,
return true;
}
+// Check a batch operation list for duplicate entries. A StackVector
+// must be passed to store any resulting duplicate URL strings. Returns
+// true if any duplicates were found.
+bool FindDuplicateOperations(
+ const std::vector<blink::mojom::BatchOperationPtr>& operations,
+ std::vector<std::string>* duplicate_url_list_out) {
+ using blink::mojom::BatchOperation;
+ DCHECK(duplicate_url_list_out);
+
+ if (operations.size() < 2) {
+ return false;
+ }
+
+ // Create a temporary sorted vector of the operations to support quickly
+ // finding potentially duplicate entries. Multiple entries may have the
+ // same URL, but differ by VARY header, so a sorted list is easier to
+ // work with than a map.
+ //
+ // Note, this will use 512 bytes of stack space on 64-bit devices. The
+ // static size attempts to accommodate most typical Cache.addAll() uses in
+ // service worker install events while not blowing up the stack too much.
+ base::StackVector<BatchOperation*, 64> sorted;
+ sorted->reserve(operations.size());
+ for (const auto& op : operations) {
+ sorted->push_back(op.get());
+ }
+ std::sort(sorted->begin(), sorted->end(),
+ [](BatchOperation* left, BatchOperation* right) {
+ return left->request.url < right->request.url;
+ });
+
+ // Check each entry in the sorted vector for any duplicates. Since the
+ // list is sorted we only need to inspect the immediate neighbors that
+ // have the same URL. This results in an average complexity of O(n log n).
+ // If the entire list has entries with the same URL and different VARY
+ // headers then this devolves into O(n^2).
+ for (auto outer = sorted->cbegin(); outer != sorted->cend(); ++outer) {
+ const BatchOperation* outer_op = *outer;
+
+ // Note, the spec checks CacheQueryOptions like ignoreSearch, etc, but
+ // currently there is no way for script to trigger a batch operation with
+ // multiple entries and non-default options. The only exposed API that
+ // supports multiple operations is addAll() and it does not allow options
+ // to be passed. Therefore we assume we do not need to take any options
+ // into account here.
+ DCHECK(!outer_op->match_params);
+
+ // If this entry already matches a duplicate we found, then just skip
+ // ahead to find any remaining duplicates.
+ if (!duplicate_url_list_out->empty() &&
+ outer_op->request.url.spec() == duplicate_url_list_out->back()) {
+ continue;
+ }
+
+ for (auto inner = std::next(outer); inner != sorted->cend(); ++inner) {
+ const BatchOperation* inner_op = *inner;
+ // Since the list is sorted we can stop looking at neighbors after
+ // the first different URL.
+ if (outer_op->request.url != inner_op->request.url) {
+ break;
+ }
+ // VaryMatches() is asymmetric since the operation depends on the VARY
+ // header in the target response. Since we only visit each pair of
+ // entries once we need to perform the VaryMatches() call in both
+ // directions.
+ if (VaryMatches(outer_op->request.headers, inner_op->request.headers,
+ inner_op->response->headers) ||
+ VaryMatches(outer_op->request.headers, inner_op->request.headers,
+ outer_op->response->headers)) {
+ duplicate_url_list_out->push_back(inner_op->request.url.spec());
+ break;
+ }
+ }
+ }
+
+ return !duplicate_url_list_out->empty();
+}
+
GURL RemoveQueryParam(const GURL& url) {
url::Replacements<char> replacements;
replacements.ClearQuery();
@@ -223,42 +311,41 @@ std::unique_ptr<ServiceWorkerFetchRequest> CreateRequest(
return request;
}
-std::unique_ptr<ServiceWorkerResponse> CreateResponse(
+blink::mojom::FetchAPIResponsePtr CreateResponse(
const proto::CacheMetadata& metadata,
const std::string& cache_name) {
- std::unique_ptr<std::vector<GURL>> url_list =
- std::make_unique<std::vector<GURL>>();
+ std::vector<GURL> url_list;
// From Chrome 57, proto::CacheMetadata's url field was deprecated.
UMA_HISTOGRAM_BOOLEAN("ServiceWorkerCache.Response.HasDeprecatedURL",
metadata.response().has_url());
if (metadata.response().has_url()) {
- url_list->push_back(GURL(metadata.response().url()));
+ url_list.push_back(GURL(metadata.response().url()));
} else {
- url_list->reserve(metadata.response().url_list_size());
+ url_list.reserve(metadata.response().url_list_size());
for (int i = 0; i < metadata.response().url_list_size(); ++i)
- url_list->push_back(GURL(metadata.response().url_list(i)));
+ url_list.push_back(GURL(metadata.response().url_list(i)));
}
- std::unique_ptr<ServiceWorkerHeaderMap> headers =
- std::make_unique<ServiceWorkerHeaderMap>();
+ ResponseHeaderMap headers;
for (int i = 0; i < metadata.response().headers_size(); ++i) {
const proto::CacheHeaderMap header = metadata.response().headers(i);
DCHECK_EQ(std::string::npos, header.name().find('\0'));
DCHECK_EQ(std::string::npos, header.value().find('\0'));
- headers->insert(std::make_pair(header.name(), header.value()));
+ headers.insert(std::make_pair(header.name(), header.value()));
}
- return std::make_unique<ServiceWorkerResponse>(
- std::move(url_list), metadata.response().status_code(),
+ return blink::mojom::FetchAPIResponse::New(
+ url_list, metadata.response().status_code(),
metadata.response().status_text(),
ProtoResponseTypeToFetchResponseType(metadata.response().response_type()),
- std::move(headers), "", 0, nullptr /* blob */,
+ headers, nullptr /* blob */,
blink::mojom::ServiceWorkerResponseError::kUnknown,
base::Time::FromInternalValue(metadata.response().response_time()),
- true /* is_in_cache_storage */, cache_name,
- std::make_unique<ServiceWorkerHeaderList>(
+ cache_name,
+ std::vector<std::string>(
metadata.response().cors_exposed_header_names().begin(),
- metadata.response().cors_exposed_header_names().end()));
+ metadata.response().cors_exposed_header_names().end()),
+ true /* is_in_cache_storage */, nullptr /* side_data_blob */);
}
// The size of opaque (non-cors) resource responses are padded in order
@@ -285,9 +372,9 @@ bool ShouldPadResourceSize(const content::proto::CacheResponse* response) {
response->url_list_size());
}
-bool ShouldPadResourceSize(const ServiceWorkerResponse* response) {
- return ShouldPadResponseType(response->response_type,
- !response->url_list.empty());
+bool ShouldPadResourceSize(const blink::mojom::FetchAPIResponse& response) {
+ return ShouldPadResponseType(response.response_type,
+ !response.url_list.empty());
}
int64_t CalculateResponsePaddingInternal(
@@ -357,7 +444,7 @@ class CacheStorageCache::BlobDataHandle
// The state needed to pass between CacheStorageCache::Put callbacks.
struct CacheStorageCache::PutContext {
PutContext(std::unique_ptr<ServiceWorkerFetchRequest> request,
- std::unique_ptr<ServiceWorkerResponse> response,
+ blink::mojom::FetchAPIResponsePtr response,
blink::mojom::BlobPtr blob,
blink::mojom::BlobPtr side_data_blob,
CacheStorageCache::ErrorCallback callback)
@@ -369,7 +456,7 @@ struct CacheStorageCache::PutContext {
// Input parameters to the Put function.
std::unique_ptr<ServiceWorkerFetchRequest> request;
- std::unique_ptr<ServiceWorkerResponse> response;
+ blink::mojom::FetchAPIResponsePtr response;
blink::mojom::BlobPtr blob;
blink::mojom::BlobPtr side_data_blob;
@@ -384,7 +471,7 @@ struct CacheStorageCache::QueryCacheResult {
explicit QueryCacheResult(base::Time entry_time) : entry_time(entry_time) {}
std::unique_ptr<ServiceWorkerFetchRequest> request;
- std::unique_ptr<ServiceWorkerResponse> response;
+ blink::mojom::FetchAPIResponsePtr response;
disk_cache::ScopedEntryPtr entry;
base::Time entry_time;
};
@@ -495,7 +582,7 @@ void CacheStorageCache::MatchAll(
ResponsesCallback callback) {
if (backend_state_ == BACKEND_CLOSED) {
std::move(callback).Run(CacheStorageError::kErrorStorage,
- std::vector<ServiceWorkerResponse>());
+ std::vector<blink::mojom::FetchAPIResponsePtr>());
return;
}
@@ -529,31 +616,83 @@ void CacheStorageCache::WriteSideData(ErrorCallback callback,
void CacheStorageCache::BatchOperation(
std::vector<blink::mojom::BatchOperationPtr> operations,
- ErrorCallback callback,
+ bool fail_on_duplicates,
+ VerboseErrorCallback callback,
BadMessageCallback bad_message_callback) {
+ // This method may produce a warning message that should be returned in the
+ // final VerboseErrorCallback. A message may be present in both the failure
+ // and success paths.
+ base::Optional<std::string> message;
+
if (backend_state_ == BACKEND_CLOSED) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(callback), CacheStorageError::kErrorStorage));
+ FROM_HERE, base::BindOnce(std::move(callback),
+ CacheStorageVerboseError::New(
+ CacheStorageError::kErrorStorage,
+ std::move(message))));
return;
}
+ // From BatchCacheOperations:
+ //
+ // https://w3c.github.io/ServiceWorker/#batch-cache-operations-algorithm
+ //
+ // "If the result of running Query Cache with operation’s request,
+ // operation’s options, and addedItems is not empty, throw an
+ // InvalidStateError DOMException."
+ //
+ // Note, we are currently only rejecting on duplicates based on a feature
+ // flag while web compat is assessed. (https://crbug.com/720919)
+ std::vector<std::string> duplicate_url_list;
+ if (FindDuplicateOperations(operations, &duplicate_url_list)) {
+ // If we found any duplicates we need to at least warn the user. Format
+ // the URL list into a comma-separated list.
+ std::string url_list_string = base::JoinString(duplicate_url_list, ", ");
+
+ // Place the duplicate list into an error message.
+ // NOTE: This must use kDuplicateOperationsBaseMessage in the string so
+ // that the renderer can identify successes with duplicates and log the
+ // appropriate use counter.
+ // TODO(crbug.com/877737): Remove this note once the cache.addAll()
+ // duplicate rejection finally ships.
+ message.emplace(base::StringPrintf(
+ "%s (%s)", blink::cache_storage::kDuplicateOperationBaseMessage,
+ url_list_string.c_str()));
+
+ // Depending on the feature flag, we may treat this as an error or allow
+ // the batch operation to continue.
+ if (fail_on_duplicates) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(callback),
+ CacheStorageVerboseError::New(
+ CacheStorageError::kErrorDuplicateOperation,
+ std::move(message))));
+ return;
+ }
+ }
+
// Estimate the required size of the put operations. The size of the deletes
// is unknown and not considered.
base::CheckedNumeric<uint64_t> safe_space_required = 0;
base::CheckedNumeric<uint64_t> safe_side_data_size = 0;
for (const auto& operation : operations) {
if (operation->operation_type == blink::mojom::OperationType::kPut) {
- safe_space_required += operation->response->blob_size;
- safe_side_data_size += operation->response->side_data_blob_size;
+ safe_space_required +=
+ (operation->response->blob ? operation->response->blob->size : 0);
+ safe_side_data_size += (operation->response->side_data_blob
+ ? operation->response->side_data_blob->size
+ : 0);
}
}
if (!safe_space_required.IsValid() || !safe_side_data_size.IsValid()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, std::move(bad_message_callback));
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(callback), CacheStorageError::kErrorStorage));
+ FROM_HERE, base::BindOnce(std::move(callback),
+ CacheStorageVerboseError::New(
+ CacheStorageError::kErrorStorage,
+ std::move(message))));
return;
}
uint64_t space_required = safe_space_required.ValueOrDie();
@@ -570,12 +709,12 @@ void CacheStorageCache::BatchOperation(
base::BindOnce(&CacheStorageCache::BatchDidGetUsageAndQuota,
weak_ptr_factory_.GetWeakPtr(), std::move(operations),
std::move(callback), std::move(bad_message_callback),
- space_required, side_data_size));
+ std::move(message), space_required, side_data_size));
return;
}
BatchDidGetUsageAndQuota(std::move(operations), std::move(callback),
- std::move(bad_message_callback),
+ std::move(bad_message_callback), std::move(message),
0 /* space_required */, 0 /* side_data_size */,
blink::mojom::QuotaStatusCode::kOk, 0 /* usage */,
0 /* quota */);
@@ -583,8 +722,9 @@ void CacheStorageCache::BatchOperation(
void CacheStorageCache::BatchDidGetUsageAndQuota(
std::vector<blink::mojom::BatchOperationPtr> operations,
- ErrorCallback callback,
+ VerboseErrorCallback callback,
BadMessageCallback bad_message_callback,
+ base::Optional<std::string> message,
uint64_t space_required,
uint64_t side_data_size,
blink::mojom::QuotaStatusCode status_code,
@@ -599,15 +739,19 @@ void CacheStorageCache::BatchDidGetUsageAndQuota(
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, std::move(bad_message_callback));
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(callback), CacheStorageError::kErrorStorage));
+ FROM_HERE, base::BindOnce(std::move(callback),
+ CacheStorageVerboseError::New(
+ CacheStorageError::kErrorStorage,
+ std::move(message))));
return;
}
if (status_code != blink::mojom::QuotaStatusCode::kOk ||
safe_space_required.ValueOrDie() > quota) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback),
- CacheStorageError::kErrorQuotaExceeded));
+ CacheStorageVerboseError::New(
+ CacheStorageError::kErrorQuotaExceeded,
+ std::move(message))));
return;
}
bool skip_side_data = safe_space_required_with_side_data.ValueOrDie() > quota;
@@ -620,10 +764,10 @@ void CacheStorageCache::BatchDidGetUsageAndQuota(
auto barrier_closure = base::BarrierClosure(
operations.size(),
base::BindOnce(&CacheStorageCache::BatchDidAllOperations,
- weak_ptr_factory_.GetWeakPtr(), callback_copy));
+ weak_ptr_factory_.GetWeakPtr(), callback_copy, message));
auto completion_callback = base::BindRepeating(
&CacheStorageCache::BatchDidOneOperation, weak_ptr_factory_.GetWeakPtr(),
- std::move(barrier_closure), std::move(callback_copy));
+ std::move(barrier_closure), std::move(callback_copy), std::move(message));
// Operations may synchronously invoke |callback| which could release the
// last reference to this instance. Hold a handle for the duration of this
@@ -635,8 +779,6 @@ void CacheStorageCache::BatchDidGetUsageAndQuota(
switch (operation->operation_type) {
case blink::mojom::OperationType::kPut:
if (skip_side_data) {
- operation->response->side_data_blob_uuid = std::string();
- operation->response->side_data_blob_size = 0;
operation->response->side_data_blob = nullptr;
Put(std::move(operation), completion_callback);
} else {
@@ -659,21 +801,26 @@ void CacheStorageCache::BatchDidGetUsageAndQuota(
void CacheStorageCache::BatchDidOneOperation(
base::OnceClosure completion_closure,
- ErrorCallback error_callback,
+ VerboseErrorCallback error_callback,
+ base::Optional<std::string> message,
CacheStorageError error) {
if (error != CacheStorageError::kSuccess) {
// This relies on |callback| being created by AdaptCallbackForRepeating
// and ignoring anything but the first invocation.
- std::move(error_callback).Run(error);
+ std::move(error_callback)
+ .Run(CacheStorageVerboseError::New(error, std::move(message)));
}
std::move(completion_closure).Run();
}
-void CacheStorageCache::BatchDidAllOperations(ErrorCallback callback) {
+void CacheStorageCache::BatchDidAllOperations(
+ VerboseErrorCallback callback,
+ base::Optional<std::string> message) {
// This relies on |callback| being created by AdaptCallbackForRepeating
// and ignoring anything but the first invocation.
- std::move(callback).Run(CacheStorageError::kSuccess);
+ std::move(callback).Run(CacheStorageVerboseError::New(
+ CacheStorageError::kSuccess, std::move(message)));
}
void CacheStorageCache::Keys(std::unique_ptr<ServiceWorkerFetchRequest> request,
@@ -967,7 +1114,7 @@ void CacheStorageCache::QueryCacheDidReadMetadata(
if (query_cache_context->query_types & QUERY_CACHE_RESPONSES_WITH_BODIES) {
query_cache_context->estimated_out_bytes +=
- match->response->EstimatedStructSize();
+ EstimatedResponseSizeWithoutBlob(*match->response);
if (query_cache_context->estimated_out_bytes > max_query_size_bytes_) {
std::move(query_cache_context->callback)
.Run(CacheStorageError::kErrorQueryTooLarge, nullptr);
@@ -1000,11 +1147,29 @@ bool CacheStorageCache::QueryCacheResultCompare(const QueryCacheResult& lhs,
}
// static
+size_t CacheStorageCache::EstimatedResponseSizeWithoutBlob(
+ const blink::mojom::FetchAPIResponse& response) {
+ size_t size = sizeof(blink::mojom::FetchAPIResponse);
+ for (const auto& url : response.url_list)
+ size += url.spec().size();
+ size += response.status_text.size();
+ if (response.cache_storage_cache_name)
+ size += response.cache_storage_cache_name->size();
+ for (const auto& key_and_value : response.headers) {
+ size += key_and_value.first.size();
+ size += key_and_value.second.size();
+ }
+ for (const auto& header : response.cors_exposed_header_names)
+ size += header.size();
+ return size;
+}
+
+// static
int64_t CacheStorageCache::CalculateResponsePadding(
- const ServiceWorkerResponse& response,
+ const blink::mojom::FetchAPIResponse& response,
const crypto::SymmetricKey* padding_key,
int side_data_size) {
- if (!ShouldPadResourceSize(&response))
+ if (!ShouldPadResourceSize(response))
return 0;
return CalculateResponsePaddingInternal(response.url_list.back().spec(),
padding_key, side_data_size);
@@ -1028,7 +1193,7 @@ void CacheStorageCache::MatchImpl(
void CacheStorageCache::MatchDidMatchAll(
ResponseCallback callback,
CacheStorageError match_all_error,
- std::vector<ServiceWorkerResponse> match_all_responses) {
+ std::vector<blink::mojom::FetchAPIResponsePtr> match_all_responses) {
if (match_all_error != CacheStorageError::kSuccess) {
std::move(callback).Run(match_all_error, nullptr);
return;
@@ -1039,10 +1204,8 @@ void CacheStorageCache::MatchDidMatchAll(
return;
}
- std::unique_ptr<ServiceWorkerResponse> response =
- std::make_unique<ServiceWorkerResponse>(match_all_responses[0]);
-
- std::move(callback).Run(CacheStorageError::kSuccess, std::move(response));
+ std::move(callback).Run(CacheStorageError::kSuccess,
+ std::move(match_all_responses[0]));
}
void CacheStorageCache::MatchAllImpl(
@@ -1052,7 +1215,7 @@ void CacheStorageCache::MatchAllImpl(
DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_);
if (backend_state_ != BACKEND_OPEN) {
std::move(callback).Run(CacheStorageError::kErrorStorage,
- std::vector<ServiceWorkerResponse>());
+ std::vector<blink::mojom::FetchAPIResponsePtr>());
return;
}
@@ -1068,15 +1231,16 @@ void CacheStorageCache::MatchAllDidQueryCache(
CacheStorageError error,
std::unique_ptr<QueryCacheResults> query_cache_results) {
if (error != CacheStorageError::kSuccess) {
- std::move(callback).Run(error, std::vector<ServiceWorkerResponse>());
+ std::move(callback).Run(error,
+ std::vector<blink::mojom::FetchAPIResponsePtr>());
return;
}
- std::vector<ServiceWorkerResponse> out_responses;
+ std::vector<blink::mojom::FetchAPIResponsePtr> out_responses;
out_responses.reserve(query_cache_results->size());
for (auto& result : *query_cache_results) {
- out_responses.push_back(*result.response);
+ out_responses.push_back(std::move(result.response));
}
std::move(callback).Run(CacheStorageError::kSuccess,
@@ -1232,14 +1396,11 @@ void CacheStorageCache::Put(blink::mojom::BatchOperationPtr operation,
operation->request.headers, operation->request.referrer,
operation->request.is_reload));
- std::unique_ptr<ServiceWorkerResponse> response =
- std::make_unique<ServiceWorkerResponse>(*operation->response);
-
- Put(std::move(request), std::move(response), std::move(callback));
+ Put(std::move(request), std::move(operation->response), std::move(callback));
}
void CacheStorageCache::Put(std::unique_ptr<ServiceWorkerFetchRequest> request,
- std::unique_ptr<ServiceWorkerResponse> response,
+ blink::mojom::FetchAPIResponsePtr response,
ErrorCallback callback) {
DCHECK(BACKEND_OPEN == backend_state_ || initializing_);
@@ -1247,9 +1408,9 @@ void CacheStorageCache::Put(std::unique_ptr<ServiceWorkerFetchRequest> request,
blink::mojom::BlobPtr side_data_blob;
if (response->blob)
- blob = response->blob->Clone();
+ blob.Bind(std::move(response->blob->blob));
if (response->side_data_blob)
- side_data_blob = response->side_data_blob->Clone();
+ side_data_blob.Bind(std::move(response->side_data_blob->blob));
UMA_HISTOGRAM_ENUMERATION("ServiceWorkerCache.Cache.AllWritesResponseType",
response->response_type);
@@ -1355,7 +1516,7 @@ void CacheStorageCache::PutDidCreateEntry(
response_metadata->add_url_list(url.spec());
response_metadata->set_response_time(
put_context->response->response_time.ToInternalValue());
- for (ServiceWorkerHeaderMap::const_iterator it =
+ for (ResponseHeaderMap::const_iterator it =
put_context->response->headers.begin();
it != put_context->response->headers.end(); ++it) {
DCHECK_EQ(std::string::npos, it->first.find('\0'));
@@ -1405,7 +1566,7 @@ void CacheStorageCache::PutDidWriteHeaders(
if (rv > 0)
storage::RecordBytesWritten(kRecordBytesLabel, rv);
- if (ShouldPadResourceSize(put_context->response.get())) {
+ if (ShouldPadResourceSize(*put_context->response)) {
cache_padding_ += CalculateResponsePadding(*put_context->response,
cache_padding_key_.get(),
0 /* side_data_size */);
@@ -1413,7 +1574,8 @@ void CacheStorageCache::PutDidWriteHeaders(
// The metadata is written, now for the response content. The data is streamed
// from the blob into the cache entry.
- if (put_context->response->blob_uuid.empty()) {
+ if (!put_context->response->blob ||
+ put_context->response->blob->uuid.empty()) {
UpdateCacheSize(base::BindOnce(std::move(put_context->callback),
CacheStorageError::kSuccess));
return;
@@ -1508,7 +1670,7 @@ void CacheStorageCache::PaddingDidQueryCache(
int64_t cache_padding = 0;
if (error == CacheStorageError::kSuccess) {
for (const auto& result : *query_cache_results) {
- if (ShouldPadResourceSize(result.response.get())) {
+ if (ShouldPadResourceSize(*result.response)) {
int32_t side_data_size =
result.entry ? result.entry->GetDataSize(INDEX_SIDE_DATA) : 0;
cache_padding += CalculateResponsePadding(
@@ -1612,7 +1774,7 @@ void CacheStorageCache::DeleteDidQueryCache(
for (auto& result : *query_cache_results) {
disk_cache::ScopedEntryPtr entry = std::move(result.entry);
- if (ShouldPadResourceSize(result.response.get())) {
+ if (ShouldPadResourceSize(*result.response)) {
cache_padding_ -=
CalculateResponsePadding(*result.response, cache_padding_key_.get(),
entry->GetDataSize(INDEX_SIDE_DATA));
@@ -1759,7 +1921,7 @@ void CacheStorageCache::InitDidCreateBackend(
auto calculate_size_callback =
base::AdaptCallbackForRepeating(std::move(callback));
- int rv = backend_->CalculateSizeOfAllEntries(base::Bind(
+ int rv = backend_->CalculateSizeOfAllEntries(base::BindOnce(
&CacheStorageCache::InitGotCacheSize, weak_ptr_factory_.GetWeakPtr(),
calculate_size_callback, cache_create_error));
@@ -1836,15 +1998,17 @@ void CacheStorageCache::InitGotCacheSizeAndPadding(
std::move(callback).Run();
}
-void CacheStorageCache::PopulateResponseBody(disk_cache::ScopedEntryPtr entry,
- ServiceWorkerResponse* response) {
+void CacheStorageCache::PopulateResponseBody(
+ disk_cache::ScopedEntryPtr entry,
+ blink::mojom::FetchAPIResponse* response) {
DCHECK(blob_storage_context_);
// Create a blob with the response body data.
- response->blob_size = entry->GetDataSize(INDEX_RESPONSE_BODY);
- response->blob_uuid = base::GenerateGUID();
+ response->blob = blink::mojom::SerializedBlob::New();
+ response->blob->size = entry->GetDataSize(INDEX_RESPONSE_BODY);
+ response->blob->uuid = base::GenerateGUID();
auto blob_data =
- std::make_unique<storage::BlobDataBuilder>(response->blob_uuid);
+ std::make_unique<storage::BlobDataBuilder>(response->blob->uuid);
disk_cache::Entry* temp_entry = entry.get();
auto data_handle = base::MakeRefCounted<BlobDataHandle>(CreateCacheHandle(),
@@ -1855,10 +2019,8 @@ void CacheStorageCache::PopulateResponseBody(disk_cache::ScopedEntryPtr entry,
auto blob_handle =
blob_storage_context_->AddFinishedBlob(std::move(blob_data));
- blink::mojom::BlobPtr blob_ptr;
- storage::BlobImpl::Create(std::move(blob_handle), MakeRequest(&blob_ptr));
- response->blob =
- base::MakeRefCounted<storage::BlobHandle>(std::move(blob_ptr));
+ storage::BlobImpl::Create(std::move(blob_handle),
+ MakeRequest(&response->blob->blob));
}
CacheStorageCacheHandle CacheStorageCache::CreateCacheHandle() {
diff --git a/chromium/content/browser/cache_storage/cache_storage_cache.h b/chromium/content/browser/cache_storage/cache_storage_cache.h
index f065161eedb..d0ab8ce63db 100644
--- a/chromium/content/browser/cache_storage/cache_storage_cache.h
+++ b/chromium/content/browser/cache_storage/cache_storage_cache.h
@@ -16,6 +16,7 @@
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
#include "content/common/service_worker/service_worker_types.h"
#include "net/base/io_buffer.h"
#include "net/disk_cache/disk_cache.h"
@@ -63,13 +64,15 @@ class CONTENT_EXPORT CacheStorageCache {
public:
using ErrorCallback =
base::OnceCallback<void(blink::mojom::CacheStorageError)>;
+ using VerboseErrorCallback =
+ base::OnceCallback<void(blink::mojom::CacheStorageVerboseErrorPtr)>;
using BadMessageCallback = base::OnceCallback<void()>;
using ResponseCallback =
base::OnceCallback<void(blink::mojom::CacheStorageError,
- std::unique_ptr<ServiceWorkerResponse>)>;
+ blink::mojom::FetchAPIResponsePtr)>;
using ResponsesCallback =
base::OnceCallback<void(blink::mojom::CacheStorageError,
- std::vector<ServiceWorkerResponse>)>;
+ std::vector<blink::mojom::FetchAPIResponsePtr>)>;
using Requests = std::vector<ServiceWorkerFetchRequest>;
using RequestsCallback =
base::OnceCallback<void(blink::mojom::CacheStorageError,
@@ -101,7 +104,7 @@ class CONTENT_EXPORT CacheStorageCache {
int64_t cache_padding,
std::unique_ptr<crypto::SymmetricKey> cache_padding_key);
static int64_t CalculateResponsePadding(
- const ServiceWorkerResponse& response,
+ const blink::mojom::FetchAPIResponse& response,
const crypto::SymmetricKey* padding_key,
int side_data_size);
static int32_t GetResponsePaddingVersion();
@@ -144,12 +147,14 @@ class CONTENT_EXPORT CacheStorageCache {
// TODO(nhiroki): This function should run all operations atomically.
// http://crbug.com/486637
void BatchOperation(std::vector<blink::mojom::BatchOperationPtr> operations,
- ErrorCallback callback,
+ bool fail_on_duplicates,
+ VerboseErrorCallback callback,
BadMessageCallback bad_message_callback);
void BatchDidGetUsageAndQuota(
std::vector<blink::mojom::BatchOperationPtr> operations,
- ErrorCallback callback,
+ VerboseErrorCallback callback,
BadMessageCallback bad_message_callback,
+ base::Optional<std::string> message,
uint64_t space_required,
uint64_t side_data_size,
blink::mojom::QuotaStatusCode status_code,
@@ -159,11 +164,13 @@ class CONTENT_EXPORT CacheStorageCache {
// |error_callback|. Always invokes |completion_closure| to signal
// completion.
void BatchDidOneOperation(base::OnceClosure completion_closure,
- ErrorCallback error_callback,
+ VerboseErrorCallback error_callback,
+ base::Optional<std::string> message,
blink::mojom::CacheStorageError error);
// Callback invoked once all BatchDidOneOperation() calls have run.
// Invokes |error_callback|.
- void BatchDidAllOperations(ErrorCallback error_callback);
+ void BatchDidAllOperations(VerboseErrorCallback error_callback,
+ base::Optional<std::string> message);
// Returns blink::mojom::CacheStorageError::kSuccess and a vector of
// requests if there are no errors.
@@ -187,7 +194,7 @@ class CONTENT_EXPORT CacheStorageCache {
// by non-CacheAPI owners. The Cache Storage API uses batch operations defined
// in the dispatcher.
void Put(std::unique_ptr<ServiceWorkerFetchRequest> request,
- std::unique_ptr<ServiceWorkerResponse> response,
+ blink::mojom::FetchAPIResponsePtr response,
ErrorCallback callback);
// Async operations in progress will cancel and not run their callbacks.
@@ -288,14 +295,17 @@ class CONTENT_EXPORT CacheStorageCache {
std::unique_ptr<proto::CacheMetadata> metadata);
static bool QueryCacheResultCompare(const QueryCacheResult& lhs,
const QueryCacheResult& rhs);
+ static size_t EstimatedResponseSizeWithoutBlob(
+ const blink::mojom::FetchAPIResponse& response);
// Match callbacks
void MatchImpl(std::unique_ptr<ServiceWorkerFetchRequest> request,
blink::mojom::QueryParamsPtr match_params,
ResponseCallback callback);
- void MatchDidMatchAll(ResponseCallback callback,
- blink::mojom::CacheStorageError match_all_error,
- std::vector<ServiceWorkerResponse> match_all_responses);
+ void MatchDidMatchAll(
+ ResponseCallback callback,
+ blink::mojom::CacheStorageError match_all_error,
+ std::vector<blink::mojom::FetchAPIResponsePtr> match_all_responses);
// MatchAll callbacks
void MatchAllImpl(std::unique_ptr<ServiceWorkerFetchRequest> request,
@@ -443,7 +453,7 @@ class CONTENT_EXPORT CacheStorageCache {
void DeleteBackendCompletedIO();
void PopulateResponseBody(disk_cache::ScopedEntryPtr entry,
- ServiceWorkerResponse* response);
+ blink::mojom::FetchAPIResponse* response);
// Virtual for testing.
virtual CacheStorageCacheHandle CreateCacheHandle();
diff --git a/chromium/content/browser/cache_storage/cache_storage_cache_unittest.cc b/chromium/content/browser/cache_storage/cache_storage_cache_unittest.cc
index d20905a639a..5578dd58900 100644
--- a/chromium/content/browser/cache_storage/cache_storage_cache_unittest.cc
+++ b/chromium/content/browser/cache_storage/cache_storage_cache_unittest.cc
@@ -53,6 +53,7 @@
#include "url/origin.h"
using blink::mojom::CacheStorageError;
+using blink::mojom::CacheStorageVerboseErrorPtr;
using storage::BlobDataItem;
namespace content {
@@ -61,6 +62,10 @@ namespace cache_storage_cache_unittest {
const char kTestData[] = "Hello World";
const char kOrigin[] = "http://example.com";
const char kCacheName[] = "test_cache";
+const GURL kBodyUrl("http://example.com/body.html");
+const GURL kBodyUrlWithQuery("http://example.com/body.html?query=test");
+const GURL kNoBodyUrl("http://example.com/no_body.html");
+const ServiceWorkerHeaderMap kHeaders({{"a", "a"}, {"b", "b"}});
// Returns a BlobProtocolHandler that uses |blob_storage_context|. Caller owns
// the memory.
@@ -70,6 +75,16 @@ std::unique_ptr<storage::BlobProtocolHandler> CreateMockBlobProtocolHandler(
new storage::BlobProtocolHandler(blob_storage_context));
}
+void SizeCallback(base::RunLoop* run_loop,
+ bool* callback_called,
+ int64_t* out_size,
+ int64_t size) {
+ *callback_called = true;
+ *out_size = size;
+ if (run_loop)
+ run_loop->Quit();
+}
+
// A disk_cache::Backend wrapper that can delay operations.
class DelayableBackend : public disk_cache::Backend {
public:
@@ -204,8 +219,8 @@ std::string CopySideData(blink::mojom::Blob* actual_blob) {
return output;
}
-bool ResponseMetadataEqual(const ServiceWorkerResponse& expected,
- const ServiceWorkerResponse& actual) {
+bool ResponseMetadataEqual(const blink::mojom::FetchAPIResponse& expected,
+ const blink::mojom::FetchAPIResponse& actual) {
EXPECT_EQ(expected.status_code, actual.status_code);
if (expected.status_code != actual.status_code)
return false;
@@ -220,18 +235,20 @@ bool ResponseMetadataEqual(const ServiceWorkerResponse& expected,
if (expected.url_list[i] != actual.url_list[i])
return false;
}
- EXPECT_EQ(expected.blob_size, actual.blob_size);
- if (expected.blob_size != actual.blob_size)
+ EXPECT_EQ(!expected.blob, !actual.blob);
+ if (!expected.blob != !actual.blob)
return false;
- if (expected.blob_size == 0) {
- EXPECT_STREQ("", actual.blob_uuid.c_str());
- if (!actual.blob_uuid.empty())
- return false;
- } else {
- EXPECT_STRNE("", actual.blob_uuid.c_str());
- if (actual.blob_uuid.empty())
- return false;
+ if (expected.blob) {
+ if (expected.blob->size == 0) {
+ EXPECT_STREQ("", actual.blob->uuid.c_str());
+ if (!actual.blob->uuid.empty())
+ return false;
+ } else {
+ EXPECT_STRNE("", actual.blob->uuid.c_str());
+ if (actual.blob->uuid.empty())
+ return false;
+ }
}
EXPECT_EQ(expected.response_time, actual.response_time);
@@ -262,11 +279,11 @@ bool ResponseSideDataEqual(const std::string& expected_side_data,
return expected_side_data == actual_body;
}
-ServiceWorkerResponse SetCacheName(const ServiceWorkerResponse& original) {
- ServiceWorkerResponse result(original);
- result.is_in_cache_storage = true;
- result.cache_storage_cache_name = kCacheName;
- return result;
+blink::mojom::FetchAPIResponsePtr SetCacheName(
+ blink::mojom::FetchAPIResponsePtr response) {
+ response->is_in_cache_storage = true;
+ response->cache_storage_cache_name = kCacheName;
+ return response;
}
std::unique_ptr<crypto::SymmetricKey> CreateTestPaddingKey() {
@@ -386,6 +403,14 @@ class CacheStorageCacheTest : public testing::Test {
CreateRequests(blob_storage_context);
+ response_time_ = base::Time::Now();
+ for (int i = 0; i < 100; ++i)
+ expected_blob_data_ += kTestData;
+ blob_handle_ = BuildBlobHandle("blob-id:myblob", expected_blob_data_);
+ storage::BlobImpl::Create(
+ std::make_unique<storage::BlobDataHandle>(*blob_handle_),
+ MakeRequest(&blob_ptr_));
+
cache_ = std::make_unique<TestCacheStorageCache>(
url::Origin::Create(GURL(kOrigin)), kCacheName, temp_dir_path,
nullptr /* CacheStorage */,
@@ -402,71 +427,46 @@ class CacheStorageCacheTest : public testing::Test {
}
void CreateRequests(ChromeBlobStorageContext* blob_storage_context) {
- ServiceWorkerHeaderMap headers;
- headers.insert(std::make_pair("a", "a"));
- headers.insert(std::make_pair("b", "b"));
body_request_ =
- ServiceWorkerFetchRequest(GURL("http://example.com/body.html"), "GET",
- headers, Referrer(), false);
+ ServiceWorkerFetchRequest(kBodyUrl, "GET", kHeaders, Referrer(), false);
body_request_with_query_ = ServiceWorkerFetchRequest(
- GURL("http://example.com/body.html?query=test"), "GET", headers,
- Referrer(), false);
- no_body_request_ =
- ServiceWorkerFetchRequest(GURL("http://example.com/no_body.html"),
- "GET", headers, Referrer(), false);
- body_head_request_ =
- ServiceWorkerFetchRequest(GURL("http://example.com/body.html"), "HEAD",
- headers, Referrer(), false);
-
- std::string expected_response;
- for (int i = 0; i < 100; ++i)
- expected_blob_data_ += kTestData;
+ kBodyUrlWithQuery, "GET", kHeaders, Referrer(), false);
+ no_body_request_ = ServiceWorkerFetchRequest(kNoBodyUrl, "GET", kHeaders,
+ Referrer(), false);
+ body_head_request_ = ServiceWorkerFetchRequest(kBodyUrl, "HEAD", kHeaders,
+ Referrer(), false);
+ }
- blob_handle_ = BuildBlobHandle("blob-id:myblob", expected_blob_data_);
+ blink::mojom::FetchAPIResponsePtr CreateBlobBodyResponse() {
+ auto blob = blink::mojom::SerializedBlob::New();
+ blob->uuid = blob_handle_->uuid();
+ blob->size = expected_blob_data_.size();
+ // Use cloned blob pointer for all responses with blob body.
+ blob_ptr_->Clone(mojo::MakeRequest(&blob->blob));
+
+ blink::mojom::FetchAPIResponsePtr response = CreateNoBodyResponse();
+ response->url_list = {kBodyUrl};
+ response->blob = std::move(blob);
+ return response;
+ }
- scoped_refptr<storage::BlobHandle> blob;
- blink::mojom::BlobPtr blob_ptr;
- storage::BlobImpl::Create(
- std::make_unique<storage::BlobDataHandle>(*blob_handle_),
- MakeRequest(&blob_ptr));
- blob = base::MakeRefCounted<storage::BlobHandle>(std::move(blob_ptr));
-
- body_response_ = CreateResponse(
- "http://example.com/body.html",
- std::make_unique<ServiceWorkerHeaderMap>(headers), blob_handle_->uuid(),
- expected_blob_data_.size(), blob,
- std::make_unique<
- ServiceWorkerHeaderList>() /* cors_exposed_header_names */);
-
- body_response_with_query_ =
- CreateResponse("http://example.com/body.html?query=test",
- std::make_unique<ServiceWorkerHeaderMap>(headers),
- blob_handle_->uuid(), expected_blob_data_.size(), blob,
- std::make_unique<ServiceWorkerHeaderList>(
- 1, "a") /* cors_exposed_header_names */);
-
- no_body_response_ = CreateResponse(
- "http://example.com/no_body.html",
- std::make_unique<ServiceWorkerHeaderMap>(headers), "", 0, nullptr,
- std::make_unique<
- ServiceWorkerHeaderList>() /* cors_exposed_header_names */);
+ blink::mojom::FetchAPIResponsePtr CreateBlobBodyResponseWithQuery() {
+ blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
+ response->url_list = {kBodyUrlWithQuery};
+ response->cors_exposed_header_names = {"a"};
+ return response;
}
- static ServiceWorkerResponse CreateResponse(
- const std::string& url,
- std::unique_ptr<ServiceWorkerHeaderMap> headers,
- const std::string& blob_uuid,
- uint64_t blob_size,
- scoped_refptr<storage::BlobHandle> blob_handle,
- std::unique_ptr<ServiceWorkerHeaderList> cors_exposed_header_names) {
- return ServiceWorkerResponse(
- std::make_unique<std::vector<GURL>>(1, GURL(url)), 200, "OK",
- network::mojom::FetchResponseType::kDefault, std::move(headers),
- blob_uuid, blob_size, std::move(blob_handle),
- blink::mojom::ServiceWorkerResponseError::kUnknown, base::Time::Now(),
- false /* is_in_cache_storage */,
- std::string() /* cache_storage_cache_name */,
- std::move(cors_exposed_header_names));
+ blink::mojom::FetchAPIResponsePtr CreateNoBodyResponse() {
+ return blink::mojom::FetchAPIResponse::New(
+ std::vector<GURL>({kNoBodyUrl}), 200, "OK",
+ network::mojom::FetchResponseType::kDefault,
+ base::flat_map<std::string, std::string>(kHeaders.cbegin(),
+ kHeaders.cend()),
+ nullptr /* blob */, blink::mojom::ServiceWorkerResponseError::kUnknown,
+ response_time_, std::string() /* cache_storage_cache_name */,
+ std::vector<std::string>() /* cors_exposed_header_names */,
+ false /* is_in_cache_storage */, nullptr /* side_data_blob */);
}
std::unique_ptr<storage::BlobDataHandle> BuildBlobHandle(
@@ -479,15 +479,13 @@ class CacheStorageCacheTest : public testing::Test {
}
void CopySideDataToResponse(storage::BlobDataHandle* side_data_blob_handle,
- ServiceWorkerResponse* response) {
- response->side_data_blob_uuid = side_data_blob_handle->uuid();
- response->side_data_blob_size = side_data_blob_handle->size();
- blink::mojom::BlobPtr blob_ptr;
+ blink::mojom::FetchAPIResponse* response) {
+ response->side_data_blob = blink::mojom::SerializedBlob::New();
+ response->side_data_blob->uuid = side_data_blob_handle->uuid();
+ response->side_data_blob->size = side_data_blob_handle->size();
storage::BlobImpl::Create(
std::make_unique<storage::BlobDataHandle>(*side_data_blob_handle),
- MakeRequest(&blob_ptr));
- response->side_data_blob =
- base::MakeRefCounted<storage::BlobHandle>(std::move(blob_ptr));
+ MakeRequest(&response->side_data_blob->blob));
}
std::unique_ptr<ServiceWorkerFetchRequest> CopyFetchRequest(
@@ -498,12 +496,13 @@ class CacheStorageCacheTest : public testing::Test {
}
CacheStorageError BatchOperation(
- std::vector<blink::mojom::BatchOperationPtr> operations) {
+ std::vector<blink::mojom::BatchOperationPtr> operations,
+ bool fail_on_duplicates = true) {
std::unique_ptr<base::RunLoop> loop(new base::RunLoop());
cache_->BatchOperation(
- std::move(operations),
- base::BindOnce(&CacheStorageCacheTest::ErrorTypeCallback,
+ std::move(operations), fail_on_duplicates,
+ base::BindOnce(&CacheStorageCacheTest::VerboseErrorTypeCallback,
base::Unretained(this), base::Unretained(loop.get())),
base::BindOnce(&OnBadMessage, base::Unretained(&bad_message_reason_)));
// TODO(jkarlin): These functions should use base::RunLoop().RunUntilIdle()
@@ -514,12 +513,12 @@ class CacheStorageCacheTest : public testing::Test {
}
bool Put(const ServiceWorkerFetchRequest& request,
- const ServiceWorkerResponse& response) {
+ blink::mojom::FetchAPIResponsePtr response) {
blink::mojom::BatchOperationPtr operation =
blink::mojom::BatchOperation::New();
operation->operation_type = blink::mojom::OperationType::kPut;
operation->request = request;
- operation->response = response;
+ operation->response = std::move(response);
std::vector<blink::mojom::BatchOperationPtr> operations;
operations.emplace_back(std::move(operation));
@@ -542,7 +541,7 @@ class CacheStorageCacheTest : public testing::Test {
bool MatchAll(const ServiceWorkerFetchRequest& request,
blink::mojom::QueryParamsPtr match_params,
- std::vector<ServiceWorkerResponse>* responses) {
+ std::vector<blink::mojom::FetchAPIResponsePtr>* responses) {
base::RunLoop loop;
cache_->MatchAll(
CopyFetchRequest(request), std::move(match_params),
@@ -552,7 +551,7 @@ class CacheStorageCacheTest : public testing::Test {
return callback_error_ == CacheStorageError::kSuccess;
}
- bool MatchAll(std::vector<ServiceWorkerResponse>* responses) {
+ bool MatchAll(std::vector<blink::mojom::FetchAPIResponsePtr>* responses) {
return MatchAll(ServiceWorkerFetchRequest(), nullptr, responses);
}
@@ -615,23 +614,23 @@ class CacheStorageCacheTest : public testing::Test {
base::RunLoop run_loop;
bool callback_called = false;
- cache_->Size(base::BindOnce(&CacheStorageCacheTest::SizeCallback,
- base::Unretained(this), &run_loop,
- &callback_called));
+ int64_t result = 0;
+ cache_->Size(
+ base::BindOnce(&SizeCallback, &run_loop, &callback_called, &result));
run_loop.Run();
EXPECT_TRUE(callback_called);
- return callback_size_;
+ return result;
}
int64_t GetSizeThenClose() {
base::RunLoop run_loop;
bool callback_called = false;
+ int64_t result = 0;
cache_->GetSizeThenClose(
- base::BindOnce(&CacheStorageCacheTest::SizeCallback,
- base::Unretained(this), &run_loop, &callback_called));
+ base::BindOnce(&SizeCallback, &run_loop, &callback_called, &result));
run_loop.Run();
EXPECT_TRUE(callback_called);
- return callback_size_;
+ return result;
}
void RequestsCallback(base::RunLoop* run_loop,
@@ -647,7 +646,14 @@ class CacheStorageCacheTest : public testing::Test {
run_loop->Quit();
}
+ void VerboseErrorTypeCallback(base::RunLoop* run_loop,
+ CacheStorageVerboseErrorPtr error) {
+ ErrorTypeCallback(run_loop, error->value);
+ callback_message_ = error->message;
+ }
+
void ErrorTypeCallback(base::RunLoop* run_loop, CacheStorageError error) {
+ callback_message_ = base::nullopt;
callback_error_ = error;
if (run_loop)
run_loop->Quit();
@@ -656,17 +662,16 @@ class CacheStorageCacheTest : public testing::Test {
void SequenceCallback(int sequence,
int* sequence_out,
base::RunLoop* run_loop,
- CacheStorageError error) {
+ CacheStorageVerboseErrorPtr error) {
*sequence_out = sequence;
- callback_error_ = error;
+ callback_error_ = error->value;
if (run_loop)
run_loop->Quit();
}
- void ResponseAndErrorCallback(
- base::RunLoop* run_loop,
- CacheStorageError error,
- std::unique_ptr<ServiceWorkerResponse> response) {
+ void ResponseAndErrorCallback(base::RunLoop* run_loop,
+ CacheStorageError error,
+ blink::mojom::FetchAPIResponsePtr response) {
callback_error_ = error;
callback_response_ = std::move(response);
@@ -676,9 +681,9 @@ class CacheStorageCacheTest : public testing::Test {
void ResponsesAndErrorCallback(
base::OnceClosure quit_closure,
- std::vector<ServiceWorkerResponse>* responses_out,
+ std::vector<blink::mojom::FetchAPIResponsePtr>* responses_out,
CacheStorageError error,
- std::vector<ServiceWorkerResponse> responses) {
+ std::vector<blink::mojom::FetchAPIResponsePtr> responses) {
callback_error_ = error;
*responses_out = std::move(responses);
std::move(quit_closure).Run();
@@ -691,25 +696,17 @@ class CacheStorageCacheTest : public testing::Test {
run_loop->Quit();
}
- void SizeCallback(base::RunLoop* run_loop,
- bool* callback_called,
- int64_t size) {
- *callback_called = true;
- callback_size_ = size;
- if (run_loop)
- run_loop->Quit();
- }
-
bool TestResponseType(network::mojom::FetchResponseType response_type) {
- body_response_.response_type = response_type;
- EXPECT_TRUE(Put(body_request_, body_response_));
+ blink::mojom::FetchAPIResponsePtr body_response = CreateBlobBodyResponse();
+ body_response->response_type = response_type;
+ EXPECT_TRUE(Put(body_request_, std::move(body_response)));
EXPECT_TRUE(Match(body_request_));
EXPECT_TRUE(Delete(body_request_));
return response_type == callback_response_->response_type;
}
void VerifyAllOpsFail() {
- EXPECT_FALSE(Put(no_body_request_, no_body_response_));
+ EXPECT_FALSE(Put(no_body_request_, CreateNoBodyResponse()));
EXPECT_FALSE(Match(no_body_request_));
EXPECT_FALSE(Delete(body_request_));
EXPECT_FALSE(Keys());
@@ -721,6 +718,11 @@ class CacheStorageCacheTest : public testing::Test {
cache_->max_query_size_bytes_ = max_bytes;
}
+ size_t EstimatedResponseSizeWithoutBlob(
+ const blink::mojom::FetchAPIResponse& response) {
+ return CacheStorageCache::EstimatedResponseSizeWithoutBlob(response);
+ }
+
protected:
base::ScopedTempDir temp_dir_;
TestBrowserThreadBundle browser_thread_bundle_;
@@ -734,21 +736,21 @@ class CacheStorageCacheTest : public testing::Test {
std::unique_ptr<TestCacheStorageCache> cache_;
ServiceWorkerFetchRequest body_request_;
- ServiceWorkerResponse body_response_;
ServiceWorkerFetchRequest body_request_with_query_;
- ServiceWorkerResponse body_response_with_query_;
ServiceWorkerFetchRequest no_body_request_;
- ServiceWorkerResponse no_body_response_;
ServiceWorkerFetchRequest body_head_request_;
std::unique_ptr<storage::BlobDataHandle> blob_handle_;
+ // Holds a Mojo connection to the BlobImpl containing |blob_handle_|.
+ blink::mojom::BlobPtr blob_ptr_;
+ base::Time response_time_;
std::string expected_blob_data_;
CacheStorageError callback_error_ = CacheStorageError::kSuccess;
- std::unique_ptr<ServiceWorkerResponse> callback_response_;
+ base::Optional<std::string> callback_message_ = base::nullopt;
+ blink::mojom::FetchAPIResponsePtr callback_response_;
std::vector<std::string> callback_strings_;
std::string bad_message_reason_;
bool callback_closed_ = false;
- int64_t callback_size_ = 0;
};
class CacheStorageCacheTestP : public CacheStorageCacheTest,
@@ -758,11 +760,11 @@ class CacheStorageCacheTestP : public CacheStorageCacheTest,
};
TEST_P(CacheStorageCacheTestP, PutNoBody) {
- EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
}
TEST_P(CacheStorageCacheTestP, PutBody) {
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
}
TEST_P(CacheStorageCacheTestP, PutBody_Multiple) {
@@ -771,42 +773,45 @@ TEST_P(CacheStorageCacheTestP, PutBody_Multiple) {
operation1->operation_type = blink::mojom::OperationType::kPut;
operation1->request = body_request_;
operation1->request.url = GURL("http://example.com/1");
- operation1->response = body_response_;
+ operation1->response = CreateBlobBodyResponse();
operation1->response->url_list.push_back(GURL("http://example.com/1"));
+ ServiceWorkerFetchRequest request1 = operation1->request;
blink::mojom::BatchOperationPtr operation2 =
blink::mojom::BatchOperation::New();
operation2->operation_type = blink::mojom::OperationType::kPut;
operation2->request = body_request_;
operation2->request.url = GURL("http://example.com/2");
- operation2->response = body_response_;
+ operation2->response = CreateBlobBodyResponse();
operation2->response->url_list.push_back(GURL("http://example.com/2"));
+ ServiceWorkerFetchRequest request2 = operation2->request;
blink::mojom::BatchOperationPtr operation3 =
blink::mojom::BatchOperation::New();
operation3->operation_type = blink::mojom::OperationType::kPut;
operation3->request = body_request_;
operation3->request.url = GURL("http://example.com/3");
- operation3->response = body_response_;
+ operation3->response = CreateBlobBodyResponse();
operation3->response->url_list.push_back(GURL("http://example.com/3"));
+ ServiceWorkerFetchRequest request3 = operation3->request;
std::vector<blink::mojom::BatchOperationPtr> operations;
- operations.push_back(operation1->Clone());
- operations.push_back(operation2->Clone());
- operations.push_back(operation3->Clone());
+ operations.push_back(std::move(operation1));
+ operations.push_back(std::move(operation2));
+ operations.push_back(std::move(operation3));
EXPECT_EQ(CacheStorageError::kSuccess, BatchOperation(std::move(operations)));
- EXPECT_TRUE(Match(operation1->request));
- EXPECT_TRUE(Match(operation2->request));
- EXPECT_TRUE(Match(operation3->request));
+ EXPECT_TRUE(Match(request1));
+ EXPECT_TRUE(Match(request2));
+ EXPECT_TRUE(Match(request3));
}
TEST_P(CacheStorageCacheTestP, MatchLimit) {
- EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
EXPECT_TRUE(Match(no_body_request_));
size_t max_size = no_body_request_.EstimatedStructSize() +
- callback_response_->EstimatedStructSize();
+ EstimatedResponseSizeWithoutBlob(*callback_response_);
SetMaxQuerySizeBytes(max_size);
EXPECT_TRUE(Match(no_body_request_));
@@ -816,16 +821,18 @@ TEST_P(CacheStorageCacheTestP, MatchLimit) {
}
TEST_P(CacheStorageCacheTestP, MatchAllLimit) {
- EXPECT_TRUE(Put(body_request_, no_body_response_));
- EXPECT_TRUE(Put(body_request_with_query_, no_body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateNoBodyResponse()));
+ EXPECT_TRUE(Put(body_request_with_query_, CreateNoBodyResponse()));
EXPECT_TRUE(Match(body_request_));
- size_t body_request_size = body_request_.EstimatedStructSize() +
- callback_response_->EstimatedStructSize();
- size_t query_request_size = body_request_with_query_.EstimatedStructSize() +
- callback_response_->EstimatedStructSize();
+ size_t body_request_size =
+ body_request_.EstimatedStructSize() +
+ EstimatedResponseSizeWithoutBlob(*callback_response_);
+ size_t query_request_size =
+ body_request_with_query_.EstimatedStructSize() +
+ EstimatedResponseSizeWithoutBlob(*callback_response_);
- std::vector<ServiceWorkerResponse> responses;
+ std::vector<blink::mojom::FetchAPIResponsePtr> responses;
blink::mojom::QueryParamsPtr match_params = blink::mojom::QueryParams::New();
// There is enough room for both requests and responses
@@ -849,8 +856,8 @@ TEST_P(CacheStorageCacheTestP, MatchAllLimit) {
}
TEST_P(CacheStorageCacheTestP, KeysLimit) {
- EXPECT_TRUE(Put(no_body_request_, no_body_response_));
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
size_t max_size = no_body_request_.EstimatedStructSize() +
body_request_.EstimatedStructSize();
@@ -868,11 +875,12 @@ TEST_P(CacheStorageCacheTestP, KeysLimit) {
// browser side (http://crbug.com/425505).
TEST_P(CacheStorageCacheTestP, ResponseURLDiffersFromRequestURL) {
- no_body_response_.url_list.clear();
- no_body_response_.url_list.push_back(GURL("http://example.com/foobar"));
+ blink::mojom::FetchAPIResponsePtr no_body_response = CreateNoBodyResponse();
+ no_body_response->url_list.clear();
+ no_body_response->url_list.push_back(GURL("http://example.com/foobar"));
EXPECT_STRNE("http://example.com/foobar",
no_body_request_.url.spec().c_str());
- EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Put(no_body_request_, std::move(no_body_response)));
EXPECT_TRUE(Match(no_body_request_));
ASSERT_EQ(1u, callback_response_->url_list.size());
EXPECT_STREQ("http://example.com/foobar",
@@ -880,9 +888,10 @@ TEST_P(CacheStorageCacheTestP, ResponseURLDiffersFromRequestURL) {
}
TEST_P(CacheStorageCacheTestP, ResponseURLEmpty) {
- no_body_response_.url_list.clear();
+ blink::mojom::FetchAPIResponsePtr no_body_response = CreateNoBodyResponse();
+ no_body_response->url_list.clear();
EXPECT_STRNE("", no_body_request_.url.spec().c_str());
- EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Put(no_body_request_, std::move(no_body_response)));
EXPECT_TRUE(Match(no_body_request_));
EXPECT_EQ(0u, callback_response_->url_list.size());
}
@@ -892,14 +901,14 @@ TEST_P(CacheStorageCacheTestP, PutBodyDropBlobRef) {
blink::mojom::BatchOperation::New();
operation->operation_type = blink::mojom::OperationType::kPut;
operation->request = body_request_;
- operation->response = body_response_;
+ operation->response = CreateBlobBodyResponse();
std::vector<blink::mojom::BatchOperationPtr> operations;
operations.emplace_back(std::move(operation));
std::unique_ptr<base::RunLoop> loop(new base::RunLoop());
cache_->BatchOperation(
- std::move(operations),
- base::BindOnce(&CacheStorageCacheTestP::ErrorTypeCallback,
+ std::move(operations), true /* fail_on_duplicate */,
+ base::BindOnce(&CacheStorageCacheTestP::VerboseErrorTypeCallback,
base::Unretained(this), base::Unretained(loop.get())),
CacheStorageCache::BadMessageCallback());
// The handle should be held by the cache now so the deref here should be
@@ -911,16 +920,22 @@ TEST_P(CacheStorageCacheTestP, PutBodyDropBlobRef) {
}
TEST_P(CacheStorageCacheTestP, PutBadMessage) {
- blink::mojom::BatchOperationPtr operation =
- blink::mojom::BatchOperation::New();
- operation->operation_type = blink::mojom::OperationType::kPut;
- operation->request = body_request_;
- operation->response = body_response_;
- operation->response->blob_size = UINT64_MAX;
+ // Two unique puts that will collectively overflow unit64_t size of the
+ // batch operation.
+ blink::mojom::BatchOperationPtr operation1 =
+ blink::mojom::BatchOperation::New(blink::mojom::OperationType::kPut,
+ body_request_, CreateBlobBodyResponse(),
+ nullptr /* match_params */);
+ operation1->response->blob->size = std::numeric_limits<uint64_t>::max();
+ blink::mojom::BatchOperationPtr operation2 =
+ blink::mojom::BatchOperation::New(
+ blink::mojom::OperationType::kPut, body_request_with_query_,
+ CreateBlobBodyResponse(), nullptr /* match_params */);
+ operation2->response->blob->size = std::numeric_limits<uint64_t>::max();
std::vector<blink::mojom::BatchOperationPtr> operations;
- operations.push_back(operation->Clone());
- operations.push_back(operation->Clone());
+ operations.push_back(std::move(operation1));
+ operations.push_back(std::move(operation2));
EXPECT_EQ(CacheStorageError::kErrorStorage,
BatchOperation(std::move(operations)));
EXPECT_EQ("CSDH_UNEXPECTED_OPERATION", bad_message_reason_);
@@ -929,112 +944,148 @@ TEST_P(CacheStorageCacheTestP, PutBadMessage) {
}
TEST_P(CacheStorageCacheTestP, PutReplace) {
- EXPECT_TRUE(Put(body_request_, no_body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateNoBodyResponse()));
EXPECT_TRUE(Match(body_request_));
EXPECT_FALSE(callback_response_->blob);
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
EXPECT_TRUE(Match(body_request_));
EXPECT_TRUE(callback_response_->blob);
- EXPECT_TRUE(Put(body_request_, no_body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateNoBodyResponse()));
EXPECT_TRUE(Match(body_request_));
EXPECT_FALSE(callback_response_->blob);
}
-TEST_P(CacheStorageCacheTestP, PutReplaceInBatch) {
+TEST_P(CacheStorageCacheTestP, PutReplaceInBatchFails) {
blink::mojom::BatchOperationPtr operation1 =
blink::mojom::BatchOperation::New();
operation1->operation_type = blink::mojom::OperationType::kPut;
operation1->request = body_request_;
- operation1->response = no_body_response_;
+ operation1->response = CreateNoBodyResponse();
blink::mojom::BatchOperationPtr operation2 =
blink::mojom::BatchOperation::New();
operation2->operation_type = blink::mojom::OperationType::kPut;
operation2->request = body_request_;
- operation2->response = body_response_;
+ operation2->response = CreateBlobBodyResponse();
std::vector<blink::mojom::BatchOperationPtr> operations;
- operations.push_back(operation1->Clone());
- operations.push_back(operation2->Clone());
+ operations.push_back(std::move(operation1));
+ operations.push_back(std::move(operation2));
- EXPECT_EQ(CacheStorageError::kSuccess, BatchOperation(std::move(operations)));
+ EXPECT_EQ(CacheStorageError::kErrorDuplicateOperation,
+ BatchOperation(std::move(operations)));
+
+ // A duplicate operation error should provide an informative message
+ // containing the URL of the duplicate request.
+ ASSERT_TRUE(callback_message_);
+ EXPECT_NE(std::string::npos, callback_message_.value().find(kBodyUrl.spec()));
+
+ // Neither operation should have completed.
+ EXPECT_FALSE(Match(body_request_));
+}
+
+TEST_P(CacheStorageCacheTestP, PutReplaceInBatchWithDuplicateCheckingDisabled) {
+ blink::mojom::BatchOperationPtr operation1 =
+ blink::mojom::BatchOperation::New();
+ operation1->operation_type = blink::mojom::OperationType::kPut;
+ operation1->request = body_request_;
+ operation1->response = CreateNoBodyResponse();
+
+ blink::mojom::BatchOperationPtr operation2 =
+ blink::mojom::BatchOperation::New();
+ operation2->operation_type = blink::mojom::OperationType::kPut;
+ operation2->request = body_request_;
+ operation2->response = CreateBlobBodyResponse();
+
+ std::vector<blink::mojom::BatchOperationPtr> operations;
+ operations.push_back(std::move(operation1));
+ operations.push_back(std::move(operation2));
+
+ EXPECT_EQ(
+ CacheStorageError::kSuccess,
+ BatchOperation(std::move(operations), false /* fail_on_duplicates */));
+
+ // Even when we don't fail on duplicates we should still provide an
+ // informative message to the user that includes the duplicate URLs.
+ ASSERT_TRUE(callback_message_);
+ EXPECT_NE(std::string::npos, callback_message_.value().find(kBodyUrl.spec()));
// |operation2| should win.
- EXPECT_TRUE(Match(operation2->request));
+ EXPECT_TRUE(Match(body_request_));
EXPECT_TRUE(callback_response_->blob);
}
TEST_P(CacheStorageCacheTestP, MatchNoBody) {
- EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
EXPECT_TRUE(Match(no_body_request_));
- EXPECT_TRUE(ResponseMetadataEqual(SetCacheName(no_body_response_),
+ EXPECT_TRUE(ResponseMetadataEqual(*SetCacheName(CreateNoBodyResponse()),
*callback_response_));
EXPECT_FALSE(callback_response_->blob);
}
TEST_P(CacheStorageCacheTestP, MatchBody) {
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
EXPECT_TRUE(Match(body_request_));
- EXPECT_TRUE(
- ResponseMetadataEqual(SetCacheName(body_response_), *callback_response_));
- EXPECT_TRUE(ResponseBodiesEqual(expected_blob_data_,
- callback_response_->blob->get()));
+ EXPECT_TRUE(ResponseMetadataEqual(*SetCacheName(CreateBlobBodyResponse()),
+ *callback_response_));
+ blink::mojom::BlobPtr blob(std::move(callback_response_->blob->blob));
+ EXPECT_TRUE(ResponseBodiesEqual(expected_blob_data_, blob.get()));
}
TEST_P(CacheStorageCacheTestP, MatchBodyHead) {
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
EXPECT_FALSE(Match(body_head_request_));
}
TEST_P(CacheStorageCacheTestP, MatchAll_Empty) {
- std::vector<ServiceWorkerResponse> responses;
+ std::vector<blink::mojom::FetchAPIResponsePtr> responses;
EXPECT_TRUE(MatchAll(&responses));
EXPECT_TRUE(responses.empty());
}
TEST_P(CacheStorageCacheTestP, MatchAll_NoBody) {
- EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
- std::vector<ServiceWorkerResponse> responses;
+ std::vector<blink::mojom::FetchAPIResponsePtr> responses;
EXPECT_TRUE(MatchAll(&responses));
ASSERT_EQ(1u, responses.size());
- EXPECT_TRUE(
- ResponseMetadataEqual(SetCacheName(no_body_response_), responses[0]));
- EXPECT_FALSE(responses[0].blob);
+ EXPECT_TRUE(ResponseMetadataEqual(*SetCacheName(CreateNoBodyResponse()),
+ *responses[0]));
+ EXPECT_FALSE(responses[0]->blob);
}
TEST_P(CacheStorageCacheTestP, MatchAll_Body) {
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
- std::vector<ServiceWorkerResponse> responses;
+ std::vector<blink::mojom::FetchAPIResponsePtr> responses;
EXPECT_TRUE(MatchAll(&responses));
ASSERT_EQ(1u, responses.size());
- EXPECT_TRUE(
- ResponseMetadataEqual(SetCacheName(body_response_), responses[0]));
- EXPECT_TRUE(
- ResponseBodiesEqual(expected_blob_data_, responses[0].blob->get()));
+ EXPECT_TRUE(ResponseMetadataEqual(*SetCacheName(CreateBlobBodyResponse()),
+ *responses[0]));
+ blink::mojom::BlobPtr blob(std::move(responses[0]->blob->blob));
+ EXPECT_TRUE(ResponseBodiesEqual(expected_blob_data_, blob.get()));
}
TEST_P(CacheStorageCacheTestP, MatchAll_TwoResponsesThenOne) {
- EXPECT_TRUE(Put(no_body_request_, no_body_response_));
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
- std::vector<ServiceWorkerResponse> responses;
+ std::vector<blink::mojom::FetchAPIResponsePtr> responses;
EXPECT_TRUE(MatchAll(&responses));
ASSERT_EQ(2u, responses.size());
- EXPECT_TRUE(responses[1].blob);
-
- EXPECT_TRUE(
- ResponseMetadataEqual(SetCacheName(no_body_response_), responses[0]));
- EXPECT_FALSE(responses[0].blob);
- EXPECT_TRUE(
- ResponseMetadataEqual(SetCacheName(body_response_), responses[1]));
- EXPECT_TRUE(
- ResponseBodiesEqual(expected_blob_data_, responses[1].blob->get()));
+ EXPECT_TRUE(responses[1]->blob);
+
+ EXPECT_TRUE(ResponseMetadataEqual(*SetCacheName(CreateNoBodyResponse()),
+ *responses[0]));
+ EXPECT_FALSE(responses[0]->blob);
+ EXPECT_TRUE(ResponseMetadataEqual(*SetCacheName(CreateBlobBodyResponse()),
+ *responses[1]));
+ blink::mojom::BlobPtr blob(std::move(responses[1]->blob->blob));
+ EXPECT_TRUE(ResponseBodiesEqual(expected_blob_data_, blob.get()));
responses.clear();
@@ -1042,13 +1093,13 @@ TEST_P(CacheStorageCacheTestP, MatchAll_TwoResponsesThenOne) {
EXPECT_TRUE(MatchAll(&responses));
ASSERT_EQ(1u, responses.size());
- EXPECT_TRUE(
- ResponseMetadataEqual(SetCacheName(no_body_response_), responses[0]));
- EXPECT_FALSE(responses[0].blob);
+ EXPECT_TRUE(ResponseMetadataEqual(*SetCacheName(CreateNoBodyResponse()),
+ *responses[0]));
+ EXPECT_FALSE(responses[0]->blob);
}
TEST_P(CacheStorageCacheTestP, Match_IgnoreSearch) {
- EXPECT_TRUE(Put(body_request_with_query_, body_response_with_query_));
+ EXPECT_TRUE(Put(body_request_with_query_, CreateBlobBodyResponseWithQuery()));
EXPECT_FALSE(Match(body_request_));
blink::mojom::QueryParamsPtr match_params = blink::mojom::QueryParams::New();
@@ -1057,7 +1108,7 @@ TEST_P(CacheStorageCacheTestP, Match_IgnoreSearch) {
}
TEST_P(CacheStorageCacheTestP, Match_IgnoreMethod) {
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
ServiceWorkerFetchRequest post_request = body_request_;
post_request.method = "POST";
@@ -1070,8 +1121,9 @@ TEST_P(CacheStorageCacheTestP, Match_IgnoreMethod) {
TEST_P(CacheStorageCacheTestP, Match_IgnoreVary) {
body_request_.headers["vary_foo"] = "foo";
- body_response_.headers["vary"] = "vary_foo";
- EXPECT_TRUE(Put(body_request_, body_response_));
+ blink::mojom::FetchAPIResponsePtr body_response = CreateBlobBodyResponse();
+ body_response->headers["vary"] = "vary_foo";
+ EXPECT_TRUE(Put(body_request_, std::move(body_response)));
EXPECT_TRUE(Match(body_request_));
body_request_.headers["vary_foo"] = "bar";
@@ -1083,7 +1135,7 @@ TEST_P(CacheStorageCacheTestP, Match_IgnoreVary) {
}
TEST_P(CacheStorageCacheTestP, Keys_IgnoreSearch) {
- EXPECT_TRUE(Put(body_request_with_query_, body_response_with_query_));
+ EXPECT_TRUE(Put(body_request_with_query_, CreateBlobBodyResponseWithQuery()));
EXPECT_TRUE(Keys(body_request_));
EXPECT_EQ(0u, callback_strings_.size());
@@ -1095,7 +1147,7 @@ TEST_P(CacheStorageCacheTestP, Keys_IgnoreSearch) {
}
TEST_P(CacheStorageCacheTestP, Keys_IgnoreMethod) {
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
ServiceWorkerFetchRequest post_request = body_request_;
post_request.method = "POST";
@@ -1110,8 +1162,9 @@ TEST_P(CacheStorageCacheTestP, Keys_IgnoreMethod) {
TEST_P(CacheStorageCacheTestP, Keys_IgnoreVary) {
body_request_.headers["vary_foo"] = "foo";
- body_response_.headers["vary"] = "vary_foo";
- EXPECT_TRUE(Put(body_request_, body_response_));
+ blink::mojom::FetchAPIResponsePtr body_response = CreateBlobBodyResponse();
+ body_response->headers["vary"] = "vary_foo";
+ EXPECT_TRUE(Put(body_request_, std::move(body_response)));
EXPECT_TRUE(Keys(body_request_));
EXPECT_EQ(1u, callback_strings_.size());
@@ -1126,7 +1179,7 @@ TEST_P(CacheStorageCacheTestP, Keys_IgnoreVary) {
}
TEST_P(CacheStorageCacheTestP, Delete_IgnoreSearch) {
- EXPECT_TRUE(Put(body_request_with_query_, body_response_with_query_));
+ EXPECT_TRUE(Put(body_request_with_query_, CreateBlobBodyResponseWithQuery()));
EXPECT_FALSE(Delete(body_request_));
blink::mojom::QueryParamsPtr match_params = blink::mojom::QueryParams::New();
@@ -1135,7 +1188,7 @@ TEST_P(CacheStorageCacheTestP, Delete_IgnoreSearch) {
}
TEST_P(CacheStorageCacheTestP, Delete_IgnoreMethod) {
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
ServiceWorkerFetchRequest post_request = body_request_;
post_request.method = "POST";
@@ -1148,8 +1201,9 @@ TEST_P(CacheStorageCacheTestP, Delete_IgnoreMethod) {
TEST_P(CacheStorageCacheTestP, Delete_IgnoreVary) {
body_request_.headers["vary_foo"] = "foo";
- body_response_.headers["vary"] = "vary_foo";
- EXPECT_TRUE(Put(body_request_, body_response_));
+ blink::mojom::FetchAPIResponsePtr body_response = CreateBlobBodyResponse();
+ body_response->headers["vary"] = "vary_foo";
+ EXPECT_TRUE(Put(body_request_, std::move(body_response)));
body_request_.headers["vary_foo"] = "bar";
EXPECT_FALSE(Delete(body_request_));
@@ -1160,11 +1214,11 @@ TEST_P(CacheStorageCacheTestP, Delete_IgnoreVary) {
}
TEST_P(CacheStorageCacheTestP, MatchAll_IgnoreMethod) {
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
ServiceWorkerFetchRequest post_request = body_request_;
post_request.method = "POST";
- std::vector<ServiceWorkerResponse> responses;
+ std::vector<blink::mojom::FetchAPIResponsePtr> responses;
EXPECT_TRUE(MatchAll(post_request, nullptr, &responses));
EXPECT_EQ(0u, responses.size());
@@ -1177,9 +1231,10 @@ TEST_P(CacheStorageCacheTestP, MatchAll_IgnoreMethod) {
TEST_P(CacheStorageCacheTestP, MatchAll_IgnoreVary) {
body_request_.headers["vary_foo"] = "foo";
- body_response_.headers["vary"] = "vary_foo";
- EXPECT_TRUE(Put(body_request_, body_response_));
- std::vector<ServiceWorkerResponse> responses;
+ blink::mojom::FetchAPIResponsePtr body_response = CreateBlobBodyResponse();
+ body_response->headers["vary"] = "vary_foo";
+ EXPECT_TRUE(Put(body_request_, std::move(body_response)));
+ std::vector<blink::mojom::FetchAPIResponsePtr> responses;
EXPECT_TRUE(MatchAll(body_request_, nullptr, &responses));
EXPECT_EQ(1u, responses.size());
@@ -1195,11 +1250,11 @@ TEST_P(CacheStorageCacheTestP, MatchAll_IgnoreVary) {
}
TEST_P(CacheStorageCacheTestP, MatchAll_IgnoreSearch) {
- EXPECT_TRUE(Put(body_request_, body_response_));
- EXPECT_TRUE(Put(body_request_with_query_, body_response_with_query_));
- EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
+ EXPECT_TRUE(Put(body_request_with_query_, CreateBlobBodyResponseWithQuery()));
+ EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
- std::vector<ServiceWorkerResponse> responses;
+ std::vector<blink::mojom::FetchAPIResponsePtr> responses;
blink::mojom::QueryParamsPtr match_params = blink::mojom::QueryParams::New();
match_params->ignore_search = true;
EXPECT_TRUE(MatchAll(body_request_, std::move(match_params), &responses));
@@ -1208,26 +1263,25 @@ TEST_P(CacheStorageCacheTestP, MatchAll_IgnoreSearch) {
// Order of returned responses is not guaranteed.
std::set<std::string> matched_set;
- for (const ServiceWorkerResponse& response : responses) {
- ASSERT_EQ(1u, response.url_list.size());
- if (response.url_list[0].spec() ==
- "http://example.com/body.html?query=test") {
- EXPECT_TRUE(ResponseMetadataEqual(SetCacheName(body_response_with_query_),
- response));
- matched_set.insert(response.url_list[0].spec());
- } else if (response.url_list[0].spec() == "http://example.com/body.html") {
- EXPECT_TRUE(
- ResponseMetadataEqual(SetCacheName(body_response_), response));
- matched_set.insert(response.url_list[0].spec());
+ for (const blink::mojom::FetchAPIResponsePtr& response : responses) {
+ ASSERT_EQ(1u, response->url_list.size());
+ if (response->url_list[0].spec() == kBodyUrlWithQuery.spec()) {
+ EXPECT_TRUE(ResponseMetadataEqual(
+ *SetCacheName(CreateBlobBodyResponseWithQuery()), *response));
+ matched_set.insert(response->url_list[0].spec());
+ } else if (response->url_list[0].spec() == kBodyUrl.spec()) {
+ EXPECT_TRUE(ResponseMetadataEqual(*SetCacheName(CreateBlobBodyResponse()),
+ *response));
+ matched_set.insert(response->url_list[0].spec());
}
}
EXPECT_EQ(2u, matched_set.size());
}
TEST_P(CacheStorageCacheTestP, MatchAll_Head) {
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
- std::vector<ServiceWorkerResponse> responses;
+ std::vector<blink::mojom::FetchAPIResponsePtr> responses;
blink::mojom::QueryParamsPtr match_params = blink::mojom::QueryParams::New();
match_params->ignore_search = true;
EXPECT_TRUE(MatchAll(body_head_request_, match_params->Clone(), &responses));
@@ -1236,16 +1290,17 @@ TEST_P(CacheStorageCacheTestP, MatchAll_Head) {
match_params->ignore_method = true;
EXPECT_TRUE(MatchAll(body_head_request_, match_params->Clone(), &responses));
ASSERT_EQ(1u, responses.size());
- EXPECT_TRUE(
- ResponseMetadataEqual(SetCacheName(body_response_), responses[0]));
- EXPECT_TRUE(
- ResponseBodiesEqual(expected_blob_data_, responses[0].blob->get()));
+ EXPECT_TRUE(ResponseMetadataEqual(*SetCacheName(CreateBlobBodyResponse()),
+ *responses[0]));
+ blink::mojom::BlobPtr blob(std::move(responses[0]->blob->blob));
+ EXPECT_TRUE(ResponseBodiesEqual(expected_blob_data_, blob.get()));
}
TEST_P(CacheStorageCacheTestP, Vary) {
body_request_.headers["vary_foo"] = "foo";
- body_response_.headers["vary"] = "vary_foo";
- EXPECT_TRUE(Put(body_request_, body_response_));
+ blink::mojom::FetchAPIResponsePtr body_response = CreateBlobBodyResponse();
+ body_response->headers["vary"] = "vary_foo";
+ EXPECT_TRUE(Put(body_request_, std::move(body_response)));
EXPECT_TRUE(Match(body_request_));
body_request_.headers["vary_foo"] = "bar";
@@ -1256,8 +1311,9 @@ TEST_P(CacheStorageCacheTestP, Vary) {
}
TEST_P(CacheStorageCacheTestP, EmptyVary) {
- body_response_.headers["vary"] = "";
- EXPECT_TRUE(Put(body_request_, body_response_));
+ blink::mojom::FetchAPIResponsePtr body_response = CreateBlobBodyResponse();
+ body_response->headers["vary"] = "";
+ EXPECT_TRUE(Put(body_request_, std::move(body_response)));
EXPECT_TRUE(Match(body_request_));
body_request_.headers["zoo"] = "zoo";
@@ -1265,7 +1321,7 @@ TEST_P(CacheStorageCacheTestP, EmptyVary) {
}
TEST_P(CacheStorageCacheTestP, NoVaryButDiffHeaders) {
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
EXPECT_TRUE(Match(body_request_));
body_request_.headers["zoo"] = "zoo";
@@ -1275,8 +1331,9 @@ TEST_P(CacheStorageCacheTestP, NoVaryButDiffHeaders) {
TEST_P(CacheStorageCacheTestP, VaryMultiple) {
body_request_.headers["vary_foo"] = "foo";
body_request_.headers["vary_bar"] = "bar";
- body_response_.headers["vary"] = " vary_foo , vary_bar";
- EXPECT_TRUE(Put(body_request_, body_response_));
+ blink::mojom::FetchAPIResponsePtr body_response = CreateBlobBodyResponse();
+ body_response->headers["vary"] = " vary_foo , vary_bar";
+ EXPECT_TRUE(Put(body_request_, std::move(body_response)));
EXPECT_TRUE(Match(body_request_));
body_request_.headers["vary_bar"] = "foo";
@@ -1288,8 +1345,9 @@ TEST_P(CacheStorageCacheTestP, VaryMultiple) {
TEST_P(CacheStorageCacheTestP, VaryNewHeader) {
body_request_.headers["vary_foo"] = "foo";
- body_response_.headers["vary"] = " vary_foo, vary_bar";
- EXPECT_TRUE(Put(body_request_, body_response_));
+ blink::mojom::FetchAPIResponsePtr body_response = CreateBlobBodyResponse();
+ body_response->headers["vary"] = " vary_foo, vary_bar";
+ EXPECT_TRUE(Put(body_request_, std::move(body_response)));
EXPECT_TRUE(Match(body_request_));
body_request_.headers["vary_bar"] = "bar";
@@ -1297,8 +1355,9 @@ TEST_P(CacheStorageCacheTestP, VaryNewHeader) {
}
TEST_P(CacheStorageCacheTestP, VaryStar) {
- body_response_.headers["vary"] = "*";
- EXPECT_TRUE(Put(body_request_, body_response_));
+ blink::mojom::FetchAPIResponsePtr body_response = CreateBlobBodyResponse();
+ body_response->headers["vary"] = "*";
+ EXPECT_TRUE(Put(body_request_, std::move(body_response)));
EXPECT_FALSE(Match(body_request_));
}
@@ -1308,8 +1367,8 @@ TEST_P(CacheStorageCacheTestP, EmptyKeys) {
}
TEST_P(CacheStorageCacheTestP, TwoKeys) {
- EXPECT_TRUE(Put(no_body_request_, no_body_response_));
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
EXPECT_TRUE(Keys());
std::vector<std::string> expected_keys{no_body_request_.url.spec(),
body_request_.url.spec()};
@@ -1317,8 +1376,8 @@ TEST_P(CacheStorageCacheTestP, TwoKeys) {
}
TEST_P(CacheStorageCacheTestP, TwoKeysThenOne) {
- EXPECT_TRUE(Put(no_body_request_, no_body_response_));
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
EXPECT_TRUE(Keys());
std::vector<std::string> expected_keys{no_body_request_.url.spec(),
body_request_.url.spec()};
@@ -1331,9 +1390,9 @@ TEST_P(CacheStorageCacheTestP, TwoKeysThenOne) {
}
TEST_P(CacheStorageCacheTestP, KeysWithIgnoreSearchTrue) {
- EXPECT_TRUE(Put(no_body_request_, no_body_response_));
- EXPECT_TRUE(Put(body_request_, body_response_));
- EXPECT_TRUE(Put(body_request_with_query_, body_response_with_query_));
+ EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
+ EXPECT_TRUE(Put(body_request_with_query_, CreateBlobBodyResponseWithQuery()));
blink::mojom::QueryParamsPtr match_params = blink::mojom::QueryParams::New();
match_params->ignore_search = true;
@@ -1345,9 +1404,9 @@ TEST_P(CacheStorageCacheTestP, KeysWithIgnoreSearchTrue) {
}
TEST_P(CacheStorageCacheTestP, KeysWithIgnoreSearchFalse) {
- EXPECT_TRUE(Put(no_body_request_, no_body_response_));
- EXPECT_TRUE(Put(body_request_, body_response_));
- EXPECT_TRUE(Put(body_request_with_query_, body_response_with_query_));
+ EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
+ EXPECT_TRUE(Put(body_request_with_query_, CreateBlobBodyResponseWithQuery()));
// Default value of ignore_search is false.
blink::mojom::QueryParamsPtr match_params = blink::mojom::QueryParams::New();
@@ -1360,31 +1419,31 @@ TEST_P(CacheStorageCacheTestP, KeysWithIgnoreSearchFalse) {
}
TEST_P(CacheStorageCacheTestP, DeleteNoBody) {
- EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
EXPECT_TRUE(Match(no_body_request_));
EXPECT_TRUE(Delete(no_body_request_));
EXPECT_FALSE(Match(no_body_request_));
EXPECT_FALSE(Delete(no_body_request_));
- EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
EXPECT_TRUE(Match(no_body_request_));
EXPECT_TRUE(Delete(no_body_request_));
}
TEST_P(CacheStorageCacheTestP, DeleteBody) {
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
EXPECT_TRUE(Match(body_request_));
EXPECT_TRUE(Delete(body_request_));
EXPECT_FALSE(Match(body_request_));
EXPECT_FALSE(Delete(body_request_));
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
EXPECT_TRUE(Match(body_request_));
EXPECT_TRUE(Delete(body_request_));
}
TEST_P(CacheStorageCacheTestP, DeleteWithIgnoreSearchTrue) {
- EXPECT_TRUE(Put(no_body_request_, no_body_response_));
- EXPECT_TRUE(Put(body_request_, body_response_));
- EXPECT_TRUE(Put(body_request_with_query_, body_response_with_query_));
+ EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
+ EXPECT_TRUE(Put(body_request_with_query_, CreateBlobBodyResponseWithQuery()));
EXPECT_TRUE(Keys());
std::vector<std::string> expected_keys{no_body_request_.url.spec(),
@@ -1405,9 +1464,9 @@ TEST_P(CacheStorageCacheTestP, DeleteWithIgnoreSearchTrue) {
}
TEST_P(CacheStorageCacheTestP, DeleteWithIgnoreSearchFalse) {
- EXPECT_TRUE(Put(no_body_request_, no_body_response_));
- EXPECT_TRUE(Put(body_request_, body_response_));
- EXPECT_TRUE(Put(body_request_with_query_, body_response_with_query_));
+ EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
+ EXPECT_TRUE(Put(body_request_with_query_, CreateBlobBodyResponseWithQuery()));
EXPECT_TRUE(Keys());
std::vector<std::string> expected_keys{no_body_request_.url.spec(),
@@ -1430,7 +1489,7 @@ TEST_P(CacheStorageCacheTestP, DeleteWithIgnoreSearchFalse) {
TEST_P(CacheStorageCacheTestP, QuickStressNoBody) {
for (int i = 0; i < 100; ++i) {
EXPECT_FALSE(Match(no_body_request_));
- EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
EXPECT_TRUE(Match(no_body_request_));
EXPECT_TRUE(Delete(no_body_request_));
}
@@ -1439,7 +1498,7 @@ TEST_P(CacheStorageCacheTestP, QuickStressNoBody) {
TEST_P(CacheStorageCacheTestP, QuickStressBody) {
for (int i = 0; i < 100; ++i) {
ASSERT_FALSE(Match(body_request_));
- ASSERT_TRUE(Put(body_request_, body_response_));
+ ASSERT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
ASSERT_TRUE(Match(body_request_));
ASSERT_TRUE(Delete(body_request_));
}
@@ -1456,36 +1515,35 @@ TEST_P(CacheStorageCacheTestP, PutResponseType) {
}
TEST_P(CacheStorageCacheTestP, PutWithSideData) {
- ServiceWorkerResponse response(body_response_);
+ blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
const std::string expected_side_data = "SideData";
std::unique_ptr<storage::BlobDataHandle> side_data_blob_handle =
BuildBlobHandle("blob-id:mysideblob", expected_side_data);
- CopySideDataToResponse(side_data_blob_handle.get(), &response);
- EXPECT_TRUE(Put(body_request_, response));
+ CopySideDataToResponse(side_data_blob_handle.get(), response.get());
+ EXPECT_TRUE(Put(body_request_, std::move(response)));
EXPECT_TRUE(Match(body_request_));
ASSERT_TRUE(callback_response_->blob);
- EXPECT_TRUE(ResponseBodiesEqual(expected_blob_data_,
- callback_response_->blob->get()));
- EXPECT_TRUE(ResponseSideDataEqual(expected_side_data,
- callback_response_->blob->get()));
+ blink::mojom::BlobPtr blob(std::move(callback_response_->blob->blob));
+ EXPECT_TRUE(ResponseBodiesEqual(expected_blob_data_, blob.get()));
+ EXPECT_TRUE(ResponseSideDataEqual(expected_side_data, blob.get()));
}
TEST_P(CacheStorageCacheTestP, PutWithSideData_QuotaExceeded) {
mock_quota_manager_->SetQuota(GURL(kOrigin),
blink::mojom::StorageType::kTemporary,
expected_blob_data_.size() - 1);
- ServiceWorkerResponse response(body_response_);
+ blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
const std::string expected_side_data = "SideData";
std::unique_ptr<storage::BlobDataHandle> side_data_blob_handle =
BuildBlobHandle("blob-id:mysideblob", expected_side_data);
- CopySideDataToResponse(side_data_blob_handle.get(), &response);
+ CopySideDataToResponse(side_data_blob_handle.get(), response.get());
// When the available space is not enough for the body, Put operation must
// fail.
- EXPECT_FALSE(Put(body_request_, response));
+ EXPECT_FALSE(Put(body_request_, std::move(response)));
EXPECT_EQ(CacheStorageError::kErrorQuotaExceeded, callback_error_);
}
@@ -1493,39 +1551,39 @@ TEST_P(CacheStorageCacheTestP, PutWithSideData_QuotaExceededSkipSideData) {
mock_quota_manager_->SetQuota(GURL(kOrigin),
blink::mojom::StorageType::kTemporary,
expected_blob_data_.size());
- ServiceWorkerResponse response(body_response_);
+ blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
const std::string expected_side_data = "SideData";
std::unique_ptr<storage::BlobDataHandle> side_data_blob_handle =
BuildBlobHandle("blob-id:mysideblob", expected_side_data);
- CopySideDataToResponse(side_data_blob_handle.get(), &response);
+ CopySideDataToResponse(side_data_blob_handle.get(), response.get());
// When the available space is enough for the body but not enough for the side
// data, Put operation must succeed.
- EXPECT_TRUE(Put(body_request_, response));
+ EXPECT_TRUE(Put(body_request_, std::move(response)));
EXPECT_TRUE(Match(body_request_));
ASSERT_TRUE(callback_response_->blob);
- EXPECT_TRUE(ResponseBodiesEqual(expected_blob_data_,
- callback_response_->blob->get()));
+ blink::mojom::BlobPtr blob(std::move(callback_response_->blob->blob));
+ EXPECT_TRUE(ResponseBodiesEqual(expected_blob_data_, blob.get()));
// The side data should not be written.
- EXPECT_TRUE(ResponseSideDataEqual("", callback_response_->blob->get()));
+ EXPECT_TRUE(ResponseSideDataEqual("", blob.get()));
}
TEST_P(CacheStorageCacheTestP, PutWithSideData_BadMessage) {
- ServiceWorkerResponse response(body_response_);
+ blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
const std::string expected_side_data = "SideData";
std::unique_ptr<storage::BlobDataHandle> side_data_blob_handle =
BuildBlobHandle("blob-id:mysideblob", expected_side_data);
- CopySideDataToResponse(side_data_blob_handle.get(), &response);
+ CopySideDataToResponse(side_data_blob_handle.get(), response.get());
blink::mojom::BatchOperationPtr operation =
blink::mojom::BatchOperation::New();
operation->operation_type = blink::mojom::OperationType::kPut;
operation->request = body_request_;
- operation->response = response;
- operation->response->blob_size = UINT64_MAX;
+ operation->response = std::move(response);
+ operation->response->blob->size = std::numeric_limits<uint64_t>::max();
std::vector<blink::mojom::BatchOperationPtr> operations;
operations.emplace_back(std::move(operation));
@@ -1538,9 +1596,9 @@ TEST_P(CacheStorageCacheTestP, PutWithSideData_BadMessage) {
TEST_P(CacheStorageCacheTestP, WriteSideData) {
base::Time response_time(base::Time::Now());
- ServiceWorkerResponse response(body_response_);
- response.response_time = response_time;
- EXPECT_TRUE(Put(body_request_, response));
+ blink::mojom::FetchAPIResponsePtr response = CreateBlobBodyResponse();
+ response->response_time = response_time;
+ EXPECT_TRUE(Put(body_request_, std::move(response)));
const std::string expected_side_data1 = "SideDataSample";
scoped_refptr<net::IOBuffer> buffer1(
@@ -1550,10 +1608,9 @@ TEST_P(CacheStorageCacheTestP, WriteSideData) {
EXPECT_TRUE(Match(body_request_));
ASSERT_TRUE(callback_response_->blob);
- EXPECT_TRUE(ResponseBodiesEqual(expected_blob_data_,
- callback_response_->blob->get()));
- EXPECT_TRUE(ResponseSideDataEqual(expected_side_data1,
- callback_response_->blob->get()));
+ blink::mojom::BlobPtr blob1(std::move(callback_response_->blob->blob));
+ EXPECT_TRUE(ResponseBodiesEqual(expected_blob_data_, blob1.get()));
+ EXPECT_TRUE(ResponseSideDataEqual(expected_side_data1, blob1.get()));
const std::string expected_side_data2 = "New data";
scoped_refptr<net::IOBuffer> buffer2(
@@ -1562,10 +1619,9 @@ TEST_P(CacheStorageCacheTestP, WriteSideData) {
expected_side_data2.length()));
EXPECT_TRUE(Match(body_request_));
ASSERT_TRUE(callback_response_->blob);
- EXPECT_TRUE(ResponseBodiesEqual(expected_blob_data_,
- callback_response_->blob->get()));
- EXPECT_TRUE(ResponseSideDataEqual(expected_side_data2,
- callback_response_->blob->get()));
+ blink::mojom::BlobPtr blob2(std::move(callback_response_->blob->blob));
+ EXPECT_TRUE(ResponseBodiesEqual(expected_blob_data_, blob2.get()));
+ EXPECT_TRUE(ResponseSideDataEqual(expected_side_data2, blob2.get()));
ASSERT_TRUE(Delete(body_request_));
}
@@ -1574,9 +1630,9 @@ TEST_P(CacheStorageCacheTestP, WriteSideData_QuotaExceeded) {
mock_quota_manager_->SetQuota(
GURL(kOrigin), blink::mojom::StorageType::kTemporary, 1024 * 1023);
base::Time response_time(base::Time::Now());
- ServiceWorkerResponse response;
- response.response_time = response_time;
- EXPECT_TRUE(Put(no_body_request_, response));
+ blink::mojom::FetchAPIResponsePtr response(CreateNoBodyResponse());
+ response->response_time = response_time;
+ EXPECT_TRUE(Put(no_body_request_, std::move(response)));
const size_t kSize = 1024 * 1024;
scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize));
@@ -1589,10 +1645,10 @@ TEST_P(CacheStorageCacheTestP, WriteSideData_QuotaExceeded) {
TEST_P(CacheStorageCacheTestP, WriteSideData_QuotaManagerModified) {
base::Time response_time(base::Time::Now());
- ServiceWorkerResponse response;
- response.response_time = response_time;
+ blink::mojom::FetchAPIResponsePtr response(CreateNoBodyResponse());
+ response->response_time = response_time;
EXPECT_EQ(0, quota_manager_proxy_->notify_storage_modified_count());
- EXPECT_TRUE(Put(no_body_request_, response));
+ EXPECT_TRUE(Put(no_body_request_, std::move(response)));
// Storage notification happens after the operation returns, so continue the
// event loop.
base::RunLoop().RunUntilIdle();
@@ -1610,9 +1666,9 @@ TEST_P(CacheStorageCacheTestP, WriteSideData_QuotaManagerModified) {
TEST_P(CacheStorageCacheTestP, WriteSideData_DifferentTimeStamp) {
base::Time response_time(base::Time::Now());
- ServiceWorkerResponse response;
- response.response_time = response_time;
- EXPECT_TRUE(Put(no_body_request_, response));
+ blink::mojom::FetchAPIResponsePtr response(CreateNoBodyResponse());
+ response->response_time = response_time;
+ EXPECT_TRUE(Put(no_body_request_, std::move(response)));
const size_t kSize = 10;
scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize));
@@ -1633,23 +1689,6 @@ TEST_P(CacheStorageCacheTestP, WriteSideData_NotFound) {
EXPECT_EQ(CacheStorageError::kErrorNotFound, callback_error_);
}
-TEST_F(CacheStorageCacheTest, CaselessServiceWorkerResponseHeaders) {
- // CacheStorageCache depends on ServiceWorkerResponse having caseless
- // headers so that it can quickly lookup vary headers.
- ServiceWorkerResponse response(
- std::make_unique<std::vector<GURL>>(), 200, "OK",
- network::mojom::FetchResponseType::kDefault,
- std::make_unique<ServiceWorkerHeaderMap>(), "", 0, nullptr /* blob */,
- blink::mojom::ServiceWorkerResponseError::kUnknown, base::Time(),
- false /* is_in_cache_storage */,
- std::string() /* cache_storage_cache_name */,
- std::make_unique<
- ServiceWorkerHeaderList>() /* cors_exposed_header_names */);
- response.headers["content-type"] = "foo";
- response.headers["Content-Type"] = "bar";
- EXPECT_EQ("bar", response.headers["content-type"]);
-}
-
TEST_F(CacheStorageCacheTest, CaselessServiceWorkerFetchRequestHeaders) {
// CacheStorageCache depends on ServiceWorkerFetchRequest having caseless
// headers so that it can quickly lookup vary headers.
@@ -1664,7 +1703,7 @@ TEST_F(CacheStorageCacheTest, CaselessServiceWorkerFetchRequestHeaders) {
TEST_P(CacheStorageCacheTestP, QuotaManagerModified) {
EXPECT_EQ(0, quota_manager_proxy_->notify_storage_modified_count());
- EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
// Storage notification happens after the operation returns, so continue the
// event loop.
base::RunLoop().RunUntilIdle();
@@ -1672,7 +1711,7 @@ TEST_P(CacheStorageCacheTestP, QuotaManagerModified) {
EXPECT_LT(0, quota_manager_proxy_->last_notified_delta());
int64_t sum_delta = quota_manager_proxy_->last_notified_delta();
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(2, quota_manager_proxy_->notify_storage_modified_count());
EXPECT_LT(sum_delta, quota_manager_proxy_->last_notified_delta());
@@ -1694,20 +1733,20 @@ TEST_P(CacheStorageCacheTestP, QuotaManagerModified) {
TEST_P(CacheStorageCacheTestP, PutObeysQuotaLimits) {
mock_quota_manager_->SetQuota(GURL(kOrigin),
blink::mojom::StorageType::kTemporary, 0);
- EXPECT_FALSE(Put(body_request_, body_response_));
+ EXPECT_FALSE(Put(body_request_, CreateBlobBodyResponse()));
EXPECT_EQ(CacheStorageError::kErrorQuotaExceeded, callback_error_);
}
TEST_P(CacheStorageCacheTestP, Size) {
EXPECT_EQ(0, Size());
- EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Put(no_body_request_, CreateNoBodyResponse()));
EXPECT_LT(0, Size());
int64_t no_body_size = Size();
EXPECT_TRUE(Delete(no_body_request_));
EXPECT_EQ(0, Size());
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
EXPECT_LT(no_body_size, Size());
EXPECT_TRUE(Delete(body_request_));
@@ -1719,12 +1758,13 @@ TEST_F(CacheStorageCacheTest, VerifyOpaqueSizePadding) {
ServiceWorkerFetchRequest non_opaque_request(body_request_);
non_opaque_request.url = GURL("http://example.com/no-pad.html");
- ServiceWorkerResponse non_opaque_response(body_response_);
- non_opaque_response.response_time = response_time;
+ blink::mojom::FetchAPIResponsePtr non_opaque_response =
+ CreateBlobBodyResponse();
+ non_opaque_response->response_time = response_time;
EXPECT_EQ(0, CacheStorageCache::CalculateResponsePadding(
- non_opaque_response, CreateTestPaddingKey().get(),
+ *non_opaque_response, CreateTestPaddingKey().get(),
0 /* side_data_size */));
- EXPECT_TRUE(Put(non_opaque_request, non_opaque_response));
+ EXPECT_TRUE(Put(non_opaque_request, std::move(non_opaque_response)));
int64_t unpadded_no_data_cache_size = Size();
// Now write some side data to that cache.
@@ -1738,8 +1778,11 @@ TEST_F(CacheStorageCacheTest, VerifyOpaqueSizePadding) {
unpadded_total_resource_size - unpadded_no_data_cache_size;
EXPECT_EQ(expected_side_data.size(),
static_cast<size_t>(unpadded_side_data_size));
+ blink::mojom::FetchAPIResponsePtr non_opaque_response_clone =
+ CreateBlobBodyResponse();
+ non_opaque_response_clone->response_time = response_time;
EXPECT_EQ(0, CacheStorageCache::CalculateResponsePadding(
- non_opaque_response, CreateTestPaddingKey().get(),
+ *non_opaque_response_clone, CreateTestPaddingKey().get(),
unpadded_side_data_size));
// Now write an identically sized opaque response.
@@ -1748,11 +1791,11 @@ TEST_F(CacheStorageCacheTest, VerifyOpaqueSizePadding) {
// Same URL length means same cache sizes (ignoring padding).
EXPECT_EQ(opaque_request.url.spec().length(),
non_opaque_request.url.spec().length());
- ServiceWorkerResponse opaque_response(non_opaque_response);
- opaque_response.response_type = network::mojom::FetchResponseType::kOpaque;
- opaque_response.response_time = response_time;
+ blink::mojom::FetchAPIResponsePtr opaque_response(CreateBlobBodyResponse());
+ opaque_response->response_type = network::mojom::FetchResponseType::kOpaque;
+ opaque_response->response_time = response_time;
- EXPECT_TRUE(Put(opaque_request, opaque_response));
+ EXPECT_TRUE(Put(opaque_request, std::move(opaque_response)));
// This test is fragile. Right now it deterministically adds non-zero padding.
// But if the url, padding key, or padding algorithm change it might become
// zero.
@@ -1784,11 +1827,11 @@ TEST_F(CacheStorageCacheTest, VerifyOpaqueSizePadding) {
TEST_F(CacheStorageCacheTest, TestDifferentOpaqueSideDataSizes) {
ServiceWorkerFetchRequest request(body_request_);
- ServiceWorkerResponse response(body_response_);
- response.response_type = network::mojom::FetchResponseType::kOpaque;
+ blink::mojom::FetchAPIResponsePtr response(CreateBlobBodyResponse());
+ response->response_type = network::mojom::FetchResponseType::kOpaque;
base::Time response_time(base::Time::Now());
- response.response_time = response_time;
- EXPECT_TRUE(Put(request, response));
+ response->response_time = response_time;
+ EXPECT_TRUE(Put(request, std::move(response)));
int64_t opaque_cache_size_no_side_data = Size();
const std::string small_side_data(1024, 'X');
@@ -1816,27 +1859,27 @@ TEST_F(CacheStorageCacheTest, TestDoubleOpaquePut) {
base::Time response_time(base::Time::Now());
- ServiceWorkerResponse response(body_response_);
- response.response_type = network::mojom::FetchResponseType::kOpaque;
- response.response_time = response_time;
- EXPECT_TRUE(Put(request, response));
+ blink::mojom::FetchAPIResponsePtr response(CreateBlobBodyResponse());
+ response->response_type = network::mojom::FetchResponseType::kOpaque;
+ response->response_time = response_time;
+ EXPECT_TRUE(Put(request, std::move(response)));
int64_t size_after_first_put = Size();
ServiceWorkerFetchRequest request2(body_request_);
- ServiceWorkerResponse response2(body_response_);
- response2.response_type = network::mojom::FetchResponseType::kOpaque;
- response2.response_time = response_time;
- EXPECT_TRUE(Put(request2, response2));
+ blink::mojom::FetchAPIResponsePtr response2(CreateBlobBodyResponse());
+ response2->response_type = network::mojom::FetchResponseType::kOpaque;
+ response2->response_time = response_time;
+ EXPECT_TRUE(Put(request2, std::move(response2)));
EXPECT_EQ(size_after_first_put, Size());
}
TEST_P(CacheStorageCacheTestP, GetSizeThenClose) {
// Create the backend and put something in it.
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
// Get a reference to the response in the cache.
EXPECT_TRUE(Match(body_request_));
- blink::mojom::BlobPtr blob = callback_response_->blob->TakeBlobPtr();
+ blink::mojom::BlobPtr blob(std::move(callback_response_->blob->blob));
callback_response_ = nullptr;
int64_t cache_size = Size();
@@ -1849,17 +1892,17 @@ TEST_P(CacheStorageCacheTestP, GetSizeThenClose) {
TEST_P(CacheStorageCacheTestP, OpsFailOnClosedBackend) {
// Create the backend and put something in it.
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
EXPECT_TRUE(Close());
VerifyAllOpsFail();
}
TEST_P(CacheStorageCacheTestP, BlobReferenceDelaysClose) {
// Create the backend and put something in it.
- EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Put(body_request_, CreateBlobBodyResponse()));
// Get a reference to the response in the cache.
EXPECT_TRUE(Match(body_request_));
- blink::mojom::BlobPtr blob = callback_response_->blob->TakeBlobPtr();
+ blink::mojom::BlobPtr blob(std::move(callback_response_->blob->blob));
callback_response_ = nullptr;
base::RunLoop loop;
@@ -1891,13 +1934,13 @@ TEST_P(CacheStorageCacheTestP, VerifySerialScheduling) {
blink::mojom::BatchOperation::New();
operation1->operation_type = blink::mojom::OperationType::kPut;
operation1->request = body_request_;
- operation1->response = body_response_;
+ operation1->response = CreateBlobBodyResponse();
std::unique_ptr<base::RunLoop> close_loop1(new base::RunLoop());
std::vector<blink::mojom::BatchOperationPtr> operations1;
operations1.emplace_back(std::move(operation1));
cache_->BatchOperation(
- std::move(operations1),
+ std::move(operations1), true /* fail_on_duplicate */,
base::BindOnce(&CacheStorageCacheTest::SequenceCallback,
base::Unretained(this), 1, &sequence_out,
close_loop1.get()),
@@ -1910,14 +1953,14 @@ TEST_P(CacheStorageCacheTestP, VerifySerialScheduling) {
blink::mojom::BatchOperation::New();
operation2->operation_type = blink::mojom::OperationType::kPut;
operation2->request = body_request_;
- operation2->response = body_response_;
+ operation2->response = CreateBlobBodyResponse();
delayable_backend->set_delay_open_entry(false);
std::unique_ptr<base::RunLoop> close_loop2(new base::RunLoop());
std::vector<blink::mojom::BatchOperationPtr> operations2;
operations2.emplace_back(std::move(operation2));
cache_->BatchOperation(
- std::move(operations2),
+ std::move(operations2), true /* fail_on_duplicate */,
base::BindOnce(&CacheStorageCacheTest::SequenceCallback,
base::Unretained(this), 2, &sequence_out,
close_loop2.get()),
diff --git a/chromium/content/browser/cache_storage/cache_storage_context_impl.cc b/chromium/content/browser/cache_storage/cache_storage_context_impl.cc
index 87c836e3f98..c61cf8c1d81 100644
--- a/chromium/content/browser/cache_storage/cache_storage_context_impl.cc
+++ b/chromium/content/browser/cache_storage/cache_storage_context_impl.cc
@@ -7,7 +7,7 @@
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/sequenced_task_runner.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "content/browser/blob_storage/chrome_blob_storage_context.h"
#include "content/browser/cache_storage/cache_storage_manager.h"
#include "content/public/browser/browser_context.h"
@@ -36,7 +36,7 @@ void CacheStorageContextImpl::Init(
is_incognito_ = user_data_directory.empty();
scoped_refptr<base::SequencedTaskRunner> cache_task_runner =
base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::BACKGROUND,
+ {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
// This thread-hopping antipattern is needed here for some unit tests, where
diff --git a/chromium/content/browser/cache_storage/cache_storage_dispatcher_host.cc b/chromium/content/browser/cache_storage/cache_storage_dispatcher_host.cc
index 60669ac676e..5f50ea600d4 100644
--- a/chromium/content/browser/cache_storage/cache_storage_dispatcher_host.cc
+++ b/chromium/content/browser/cache_storage/cache_storage_dispatcher_host.cc
@@ -34,6 +34,7 @@ namespace content {
namespace {
using blink::mojom::CacheStorageError;
+using blink::mojom::CacheStorageVerboseError;
const int32_t kCachePreservationSeconds = 5;
@@ -84,13 +85,14 @@ class CacheStorageDispatcherHost::CacheImpl
void OnCacheMatchCallback(
blink::mojom::CacheStorageCache::MatchCallback callback,
blink::mojom::CacheStorageError error,
- std::unique_ptr<ServiceWorkerResponse> response) {
+ blink::mojom::FetchAPIResponsePtr response) {
if (error != CacheStorageError::kSuccess) {
std::move(callback).Run(blink::mojom::MatchResult::NewStatus(error));
return;
}
- std::move(callback).Run(blink::mojom::MatchResult::NewResponse(*response));
+ std::move(callback).Run(
+ blink::mojom::MatchResult::NewResponse(std::move(response)));
}
void MatchAll(const base::Optional<ServiceWorkerFetchRequest>& request,
@@ -120,7 +122,7 @@ class CacheStorageDispatcherHost::CacheImpl
void OnCacheMatchAllCallback(
blink::mojom::CacheStorageCache::MatchAllCallback callback,
blink::mojom::CacheStorageError error,
- std::vector<ServiceWorkerResponse> responses) {
+ std::vector<blink::mojom::FetchAPIResponsePtr> responses) {
if (error != CacheStorageError::kSuccess &&
error != CacheStorageError::kErrorNotFound) {
std::move(callback).Run(blink::mojom::MatchAllResult::NewStatus(error));
@@ -167,14 +169,16 @@ class CacheStorageDispatcherHost::CacheImpl
}
void Batch(std::vector<blink::mojom::BatchOperationPtr> batch_operations,
+ bool fail_on_duplicates,
BatchCallback callback) override {
content::CacheStorageCache* cache = cache_handle_.value();
if (!cache) {
- std::move(callback).Run(CacheStorageError::kErrorNotFound);
+ std::move(callback).Run(CacheStorageVerboseError::New(
+ CacheStorageError::kErrorNotFound, base::nullopt));
return;
}
cache->BatchOperation(
- std::move(batch_operations),
+ std::move(batch_operations), fail_on_duplicates,
base::BindOnce(&CacheImpl::OnCacheBatchCallback,
weak_factory_.GetWeakPtr(), std::move(callback)),
base::BindOnce(&CacheImpl::OnBadMessage, weak_factory_.GetWeakPtr(),
@@ -183,8 +187,8 @@ class CacheStorageDispatcherHost::CacheImpl
void OnCacheBatchCallback(
blink::mojom::CacheStorageCache::BatchCallback callback,
- blink::mojom::CacheStorageError error) {
- std::move(callback).Run(error);
+ blink::mojom::CacheStorageVerboseErrorPtr error) {
+ std::move(callback).Run(std::move(error));
}
void OnBadMessage(mojo::ReportBadMessageCallback bad_message_callback) {
@@ -371,14 +375,14 @@ void CacheStorageDispatcherHost::OnKeysCallback(
void CacheStorageDispatcherHost::OnMatchCallback(
blink::mojom::CacheStorage::MatchCallback callback,
CacheStorageError error,
- std::unique_ptr<ServiceWorkerResponse> response) {
+ blink::mojom::FetchAPIResponsePtr response) {
if (error != CacheStorageError::kSuccess) {
std::move(callback).Run(blink::mojom::MatchResult::NewStatus(error));
return;
}
std::move(callback).Run(
- blink::mojom::MatchResult::NewResponse(std::move(*response)));
+ blink::mojom::MatchResult::NewResponse(std::move(response)));
}
void CacheStorageDispatcherHost::AddBinding(
diff --git a/chromium/content/browser/cache_storage/cache_storage_dispatcher_host.h b/chromium/content/browser/cache_storage/cache_storage_dispatcher_host.h
index f4f99042e39..ade31c52d76 100644
--- a/chromium/content/browser/cache_storage/cache_storage_dispatcher_host.h
+++ b/chromium/content/browser/cache_storage/cache_storage_dispatcher_host.h
@@ -83,7 +83,7 @@ class CONTENT_EXPORT CacheStorageDispatcherHost
blink::mojom::CacheStorageError error);
void OnMatchCallback(blink::mojom::CacheStorage::MatchCallback callback,
blink::mojom::CacheStorageError error,
- std::unique_ptr<ServiceWorkerResponse> response);
+ blink::mojom::FetchAPIResponsePtr response);
void OnOpenCallback(url::Origin origin,
blink::mojom::CacheStorage::OpenCallback callback,
CacheStorageCacheHandle cache_handle,
diff --git a/chromium/content/browser/cache_storage/cache_storage_manager.cc b/chromium/content/browser/cache_storage/cache_storage_manager.cc
index be479cf1d69..6eab90f4d1e 100644
--- a/chromium/content/browser/cache_storage/cache_storage_manager.cc
+++ b/chromium/content/browser/cache_storage/cache_storage_manager.cc
@@ -255,7 +255,7 @@ void CacheStorageManager::WriteToCache(
CacheStorageOwner owner,
const std::string& cache_name,
std::unique_ptr<ServiceWorkerFetchRequest> request,
- std::unique_ptr<ServiceWorkerResponse> response,
+ blink::mojom::FetchAPIResponsePtr response,
CacheStorage::ErrorCallback callback) {
// Cache API should write through the dispatcher.
DCHECK_NE(owner, CacheStorageOwner::kCacheAPI);
diff --git a/chromium/content/browser/cache_storage/cache_storage_manager.h b/chromium/content/browser/cache_storage/cache_storage_manager.h
index e7460ce34f8..d08b84a5e3e 100644
--- a/chromium/content/browser/cache_storage/cache_storage_manager.h
+++ b/chromium/content/browser/cache_storage/cache_storage_manager.h
@@ -110,7 +110,7 @@ class CONTENT_EXPORT CacheStorageManager
CacheStorageOwner owner,
const std::string& cache_name,
std::unique_ptr<ServiceWorkerFetchRequest> request,
- std::unique_ptr<ServiceWorkerResponse> response,
+ blink::mojom::FetchAPIResponsePtr response,
CacheStorage::ErrorCallback callback);
// This must be called before creating any of the public *Cache functions
@@ -204,7 +204,7 @@ class CONTENT_EXPORT CacheStorageManager
// |cache_task_runner_|.
CacheStorageMap cache_storage_map_;
- base::ObserverList<CacheStorageContextImpl::Observer> observers_;
+ base::ObserverList<CacheStorageContextImpl::Observer>::Unchecked observers_;
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
base::WeakPtr<storage::BlobStorageContext> blob_context_;
diff --git a/chromium/content/browser/cache_storage/cache_storage_manager_unittest.cc b/chromium/content/browser/cache_storage/cache_storage_manager_unittest.cc
index d62569b7672..c9aa9486f41 100644
--- a/chromium/content/browser/cache_storage/cache_storage_manager_unittest.cc
+++ b/chromium/content/browser/cache_storage/cache_storage_manager_unittest.cc
@@ -11,6 +11,7 @@
#include <set>
#include <utility>
+#include "base/containers/flat_map.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
@@ -56,12 +57,14 @@
#include "url/origin.h"
using blink::mojom::CacheStorageError;
+using blink::mojom::CacheStorageVerboseErrorPtr;
using network::mojom::FetchResponseType;
namespace content {
namespace cache_storage_manager_unittest {
using blink::mojom::StorageType;
+using ResponseHeaderMap = base::flat_map<std::string, std::string>;
class MockCacheStorageQuotaManagerProxy : public MockQuotaManagerProxy {
public:
@@ -210,19 +213,21 @@ class CacheStorageManagerTest : public testing::Test {
return cache_names;
}
- void CachePutCallback(base::RunLoop* run_loop, CacheStorageError error) {
- callback_error_ = error;
+ void CachePutCallback(base::RunLoop* run_loop,
+ CacheStorageVerboseErrorPtr error) {
+ callback_error_ = error->value;
run_loop->Quit();
}
- void CacheDeleteCallback(base::RunLoop* run_loop, CacheStorageError error) {
- callback_error_ = error;
+ void CacheDeleteCallback(base::RunLoop* run_loop,
+ CacheStorageVerboseErrorPtr error) {
+ callback_error_ = error->value;
run_loop->Quit();
}
void CacheMatchCallback(base::RunLoop* run_loop,
CacheStorageError error,
- std::unique_ptr<ServiceWorkerResponse> response) {
+ blink::mojom::FetchAPIResponsePtr response) {
callback_error_ = error;
callback_cache_handle_response_ = std::move(response);
run_loop->Quit();
@@ -424,11 +429,10 @@ class CacheStorageManagerTest : public testing::Test {
auto request = std::make_unique<ServiceWorkerFetchRequest>();
request->url = GURL(request_url);
- auto response = std::make_unique<ServiceWorkerResponse>();
-
base::RunLoop loop;
cache_manager_->WriteToCache(
- origin, owner, cache_name, std::move(request), std::move(response),
+ origin, owner, cache_name, std::move(request),
+ blink::mojom::FetchAPIResponse::New(),
base::BindOnce(&CacheStorageManagerTest::ErrorCallback,
base::Unretained(this), base::Unretained(&loop)));
loop.Run();
@@ -447,10 +451,10 @@ class CacheStorageManagerTest : public testing::Test {
bool CachePutWithRequestAndHeaders(
CacheStorageCache* cache,
const ServiceWorkerFetchRequest& request,
- const ServiceWorkerHeaderMap& response_headers,
+ ResponseHeaderMap response_headers,
FetchResponseType response_type = FetchResponseType::kDefault) {
return CachePutWithStatusCode(cache, request, 200, response_type,
- response_headers);
+ std::move(response_headers));
}
bool CachePutWithStatusCode(
@@ -458,8 +462,7 @@ class CacheStorageManagerTest : public testing::Test {
const ServiceWorkerFetchRequest& request,
int status_code,
FetchResponseType response_type = FetchResponseType::kDefault,
- const ServiceWorkerHeaderMap& response_headers =
- ServiceWorkerHeaderMap()) {
+ ResponseHeaderMap response_headers = ResponseHeaderMap()) {
std::string blob_uuid = base::GenerateGUID();
std::unique_ptr<storage::BlobDataBuilder> blob_data(
new storage::BlobDataBuilder(blob_uuid));
@@ -468,35 +471,34 @@ class CacheStorageManagerTest : public testing::Test {
std::unique_ptr<storage::BlobDataHandle> blob_data_handle =
blob_storage_context_->AddFinishedBlob(std::move(blob_data));
- scoped_refptr<storage::BlobHandle> blob_handle;
- blink::mojom::BlobPtr blob;
- storage::BlobImpl::Create(std::move(blob_data_handle), MakeRequest(&blob));
- blob_handle = base::MakeRefCounted<storage::BlobHandle>(std::move(blob));
-
- std::unique_ptr<std::vector<GURL>> url_list =
- std::make_unique<std::vector<GURL>>();
- url_list->push_back(request.url);
- ServiceWorkerResponse response(
- std::move(url_list), status_code, "OK", response_type,
- std::make_unique<ServiceWorkerHeaderMap>(response_headers), blob_uuid,
- request.url.spec().size(), blob_handle,
+ blink::mojom::BlobPtrInfo blob_ptr_info;
+ storage::BlobImpl::Create(std::move(blob_data_handle),
+ MakeRequest(&blob_ptr_info));
+
+ auto blob = blink::mojom::SerializedBlob::New();
+ blob->uuid = blob_uuid;
+ blob->size = request.url.spec().size();
+ blob->blob = std::move(blob_ptr_info);
+
+ auto response = blink::mojom::FetchAPIResponse::New(
+ std::vector<GURL>({request.url}), status_code, "OK", response_type,
+ response_headers, std::move(blob),
blink::mojom::ServiceWorkerResponseError::kUnknown, base::Time(),
- false /* is_in_cache_storage */,
std::string() /* cache_storage_cache_name */,
- std::make_unique<
- ServiceWorkerHeaderList>() /* cors_exposed_header_names */);
+ std::vector<std::string>() /* cors_exposed_header_names */,
+ false /* is_in_cache_storage */, nullptr /* side_data_blob */);
blink::mojom::BatchOperationPtr operation =
blink::mojom::BatchOperation::New();
operation->operation_type = blink::mojom::OperationType::kPut;
operation->request = request;
- operation->response = response;
+ operation->response = std::move(response);
std::vector<blink::mojom::BatchOperationPtr> operations;
operations.emplace_back(std::move(operation));
base::RunLoop loop;
cache->BatchOperation(
- std::move(operations),
+ std::move(operations), true /* fail_on_duplicate */,
base::BindOnce(&CacheStorageManagerTest::CachePutCallback,
base::Unretained(this), base::Unretained(&loop)),
CacheStorageCache::BadMessageCallback());
@@ -508,19 +510,18 @@ class CacheStorageManagerTest : public testing::Test {
bool CacheDelete(CacheStorageCache* cache, const GURL& url) {
ServiceWorkerFetchRequest request;
request.url = url;
- ServiceWorkerResponse response;
blink::mojom::BatchOperationPtr operation =
blink::mojom::BatchOperation::New();
operation->operation_type = blink::mojom::OperationType::kDelete;
operation->request = request;
- operation->response = response;
+ operation->response = blink::mojom::FetchAPIResponse::New();
std::vector<blink::mojom::BatchOperationPtr> operations;
operations.emplace_back(std::move(operation));
base::RunLoop loop;
cache->BatchOperation(
- std::move(operations),
+ std::move(operations), true /* fail_on_duplicate */,
base::BindOnce(&CacheStorageManagerTest::CacheDeleteCallback,
base::Unretained(this), base::Unretained(&loop)),
CacheStorageCache::BadMessageCallback());
@@ -641,7 +642,7 @@ class CacheStorageManagerTest : public testing::Test {
CacheStorageCacheHandle callback_cache_handle_;
int callback_bool_;
CacheStorageError callback_error_;
- std::unique_ptr<ServiceWorkerResponse> callback_cache_handle_response_;
+ blink::mojom::FetchAPIResponsePtr callback_cache_handle_response_;
std::unique_ptr<storage::BlobDataHandle> callback_data_handle_;
CacheStorageIndex callback_cache_index_;
@@ -1794,11 +1795,11 @@ TEST_P(CacheStorageManagerTestP, StorageMatch_IgnoreVary) {
request.url = url;
request.headers["vary_foo"] = "foo";
- ServiceWorkerHeaderMap response_headers;
+ ResponseHeaderMap response_headers;
response_headers["vary"] = "vary_foo";
- EXPECT_TRUE(CachePutWithRequestAndHeaders(callback_cache_handle_.value(),
- request, response_headers));
+ EXPECT_TRUE(CachePutWithRequestAndHeaders(
+ callback_cache_handle_.value(), request, std::move(response_headers)));
EXPECT_TRUE(StorageMatchWithRequest(origin1_, "foo", request));
request.headers["vary_foo"] = "bar";
@@ -1847,7 +1848,7 @@ TEST_P(CacheStorageManagerTestP, StorageMatchAll_IgnoreVary) {
request.url = url;
request.headers["vary_foo"] = "foo";
- ServiceWorkerHeaderMap response_headers;
+ ResponseHeaderMap response_headers;
response_headers["vary"] = "vary_foo";
EXPECT_TRUE(CachePutWithRequestAndHeaders(callback_cache_handle_.value(),
diff --git a/chromium/content/browser/child_process_launcher.cc b/chromium/content/browser/child_process_launcher.cc
index f071c1d5c05..bd16e1b1080 100644
--- a/chromium/content/browser/child_process_launcher.cc
+++ b/chromium/content/browser/child_process_launcher.cc
@@ -175,6 +175,7 @@ bool ChildProcessLauncherPriority::operator==(
return visible == other.visible &&
has_media_stream == other.has_media_stream &&
frame_depth == other.frame_depth &&
+ intersects_viewport == other.intersects_viewport &&
boost_for_pending_views == other.boost_for_pending_views
#if defined(OS_ANDROID)
&& importance == other.importance
diff --git a/chromium/content/browser/child_process_launcher.h b/chromium/content/browser/child_process_launcher.h
index 190ee370186..26f1376d45c 100644
--- a/chromium/content/browser/child_process_launcher.h
+++ b/chromium/content/browser/child_process_launcher.h
@@ -59,6 +59,7 @@ struct ChildProcessLauncherPriority {
ChildProcessLauncherPriority(bool visible,
bool has_media_stream,
unsigned int frame_depth,
+ bool intersects_viewport,
bool boost_for_pending_views,
bool should_boost_for_pending_views
#if defined(OS_ANDROID)
@@ -69,6 +70,7 @@ struct ChildProcessLauncherPriority {
: visible(visible),
has_media_stream(has_media_stream),
frame_depth(frame_depth),
+ intersects_viewport(intersects_viewport),
boost_for_pending_views(boost_for_pending_views),
should_boost_for_pending_views(should_boost_for_pending_views)
#if defined(OS_ANDROID)
@@ -108,6 +110,12 @@ struct ChildProcessLauncherPriority {
// matching |visible| properties.
unsigned int frame_depth;
+ // |intersects_viewport| is true if this process is responsible for a frame
+ // which intersects a viewport which has |visible| visibility. It only makes
+ // sense to compare this property for two ChildProcessLauncherPriority
+ // instances with matching |visible| properties.
+ bool intersects_viewport;
+
// |boost_for_pending_views| is true if this process is responsible for a
// pending view (this is used to boost priority of a process responsible for
// foreground content which hasn't yet been added as a visible widget -- i.e.
diff --git a/chromium/content/browser/child_process_launcher_helper.cc b/chromium/content/browser/child_process_launcher_helper.cc
index d4272efe0e4..6e0eebe2361 100644
--- a/chromium/content/browser/child_process_launcher_helper.cc
+++ b/chromium/content/browser/child_process_launcher_helper.cc
@@ -8,10 +8,10 @@
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/single_thread_task_runner.h"
-#include "base/task_scheduler/lazy_task_runner.h"
-#include "base/task_scheduler/post_task.h"
-#include "base/task_scheduler/single_thread_task_runner_thread_mode.h"
-#include "base/task_scheduler/task_traits.h"
+#include "base/task/lazy_task_runner.h"
+#include "base/task/post_task.h"
+#include "base/task/single_thread_task_runner_thread_mode.h"
+#include "base/task/task_traits.h"
#include "content/browser/child_process_launcher.h"
#include "content/public/browser/child_process_launcher_utils.h"
#include "content/public/common/content_switches.h"
diff --git a/chromium/content/browser/child_process_launcher_helper_android.cc b/chromium/content/browser/child_process_launcher_helper_android.cc
index 2115d7f830c..83be7e6bbb4 100644
--- a/chromium/content/browser/child_process_launcher_helper_android.cc
+++ b/chromium/content/browser/child_process_launcher_helper_android.cc
@@ -223,7 +223,8 @@ void ChildProcessLauncherHelper::SetProcessPriorityOnLauncherThread(
return Java_ChildProcessLauncherHelperImpl_setPriority(
env, java_peer_, process.Handle(), priority.visible,
priority.has_media_stream, priority.frame_depth,
- priority.boost_for_pending_views, static_cast<jint>(priority.importance));
+ priority.intersects_viewport, priority.boost_for_pending_views,
+ static_cast<jint>(priority.importance));
}
// static
diff --git a/chromium/content/browser/child_process_launcher_helper_mac.cc b/chromium/content/browser/child_process_launcher_helper_mac.cc
index 3fd28bf7589..c1b02ef4855 100644
--- a/chromium/content/browser/child_process_launcher_helper_mac.cc
+++ b/chromium/content/browser/child_process_launcher_helper_mac.cc
@@ -22,6 +22,7 @@
#include "content/public/common/sandboxed_process_launcher_delegate.h"
#include "sandbox/mac/seatbelt_exec.h"
#include "services/service_manager/embedder/result_codes.h"
+#include "services/service_manager/sandbox/mac/audio.sb.h"
#include "services/service_manager/sandbox/mac/cdm.sb.h"
#include "services/service_manager/sandbox/mac/common_v2.sb.h"
#include "services/service_manager/sandbox/mac/gpu_v2.sb.h"
@@ -73,7 +74,8 @@ bool ChildProcessLauncherHelper::BeforeLaunchOnLauncherThread(
service_manager::IsUnsandboxedSandboxType(sandbox_type);
// TODO(kerrnel): Delete this switch once the V2 sandbox is always enabled.
- bool v2_process = false;
+ bool use_v2 = base::FeatureList::IsEnabled(features::kMacV2Sandbox);
+
switch (sandbox_type) {
case service_manager::SANDBOX_TYPE_NO_SANDBOX:
break;
@@ -84,18 +86,22 @@ bool ChildProcessLauncherHelper::BeforeLaunchOnLauncherThread(
case service_manager::SANDBOX_TYPE_NACL_LOADER:
case service_manager::SANDBOX_TYPE_PDF_COMPOSITOR:
case service_manager::SANDBOX_TYPE_PROFILING:
- v2_process = true;
+ // If the feature experiment is enabled and this process type supports
+ // the v2 sandbox, use it.
+ use_v2 &= true;
+ break;
+ case service_manager::SANDBOX_TYPE_AUDIO:
+ // The audio service only exists with the v2 sandbox.
+ use_v2 |= true;
break;
default:
// This is a 'break' because the V2 sandbox is not enabled for all
// processes yet, and so there are sandbox types like NETWORK that
// should not be run under the V2 sandbox.
+ use_v2 = false;
break;
}
- bool use_v2 =
- v2_process && base::FeatureList::IsEnabled(features::kMacV2Sandbox);
-
if (use_v2 && !no_sandbox) {
// Generate the profile string.
std::string profile =
@@ -120,6 +126,9 @@ bool ChildProcessLauncherHelper::BeforeLaunchOnLauncherThread(
case service_manager::SANDBOX_TYPE_PDF_COMPOSITOR:
profile += service_manager::kSeatbeltPolicyString_pdf_compositor;
break;
+ case service_manager::SANDBOX_TYPE_AUDIO:
+ profile += service_manager::kSeatbeltPolicyString_audio;
+ break;
case service_manager::SANDBOX_TYPE_UTILITY:
case service_manager::SANDBOX_TYPE_PROFILING:
profile += service_manager::kSeatbeltPolicyString_utility;
@@ -143,6 +152,7 @@ bool ChildProcessLauncherHelper::BeforeLaunchOnLauncherThread(
case service_manager::SANDBOX_TYPE_NACL_LOADER:
case service_manager::SANDBOX_TYPE_RENDERER:
case service_manager::SANDBOX_TYPE_PDF_COMPOSITOR:
+ case service_manager::SANDBOX_TYPE_AUDIO:
SetupCommonSandboxParameters(seatbelt_exec_client_.get());
break;
case service_manager::SANDBOX_TYPE_PPAPI:
diff --git a/chromium/content/browser/child_process_security_policy_impl.cc b/chromium/content/browser/child_process_security_policy_impl.cc
index 1272be30040..bd757e4fdef 100644
--- a/chromium/content/browser/child_process_security_policy_impl.cc
+++ b/chromium/content/browser/child_process_security_policy_impl.cc
@@ -1120,7 +1120,7 @@ bool ChildProcessSecurityPolicyImpl::CanAccessDataForOrigin(int child_id,
// TODO(creis): We must pass the valid browser_context to convert hosted apps
// URLs. Currently, hosted apps cannot set cookies in this mode. See
// http://crbug.com/160576.
- GURL site_url = SiteInstanceImpl::GetSiteForURL(nullptr, url);
+ GURL site_url = SiteInstance::GetSiteForURL(nullptr, url);
base::AutoLock lock(lock_);
SecurityStateMap::iterator state = security_state_.find(child_id);
@@ -1153,7 +1153,7 @@ void ChildProcessSecurityPolicyImpl::LockToOrigin(int child_id,
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// "gurl" can be currently empty in some cases, such as file://blah.
- DCHECK(SiteInstanceImpl::GetSiteForURL(nullptr, gurl) == gurl);
+ DCHECK_EQ(SiteInstanceImpl::DetermineProcessLockURL(nullptr, gurl), gurl);
base::AutoLock lock(lock_);
SecurityStateMap::iterator state = security_state_.find(child_id);
DCHECK(state != security_state_.end());
diff --git a/chromium/content/browser/cocoa/system_hotkey_helper_mac.mm b/chromium/content/browser/cocoa/system_hotkey_helper_mac.mm
index 36a0ee2f3bc..0a26a48fd62 100644
--- a/chromium/content/browser/cocoa/system_hotkey_helper_mac.mm
+++ b/chromium/content/browser/cocoa/system_hotkey_helper_mac.mm
@@ -8,9 +8,9 @@
#include "base/files/file_path.h"
#include "base/mac/foundation_util.h"
#include "base/metrics/histogram_macros.h"
-#include "base/task_scheduler/post_task.h"
-#include "base/task_scheduler/task_traits.h"
-#include "base/threading/thread_restrictions.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
+#include "base/threading/scoped_blocking_call.h"
#include "content/browser/cocoa/system_hotkey_map.h"
#include "content/public/browser/browser_thread.h"
@@ -48,7 +48,7 @@ SystemHotkeyHelperMac::~SystemHotkeyHelperMac() {
}
void SystemHotkeyHelperMac::LoadSystemHotkeys() {
- base::AssertBlockingAllowed();
+ base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
std::string library_path(base::mac::GetUserLibraryPath().value());
NSString* expanded_file_path =
diff --git a/chromium/content/browser/code_cache/generated_code_cache.cc b/chromium/content/browser/code_cache/generated_code_cache.cc
index c74c9a32d40..f1f3ec32393 100644
--- a/chromium/content/browser/code_cache/generated_code_cache.cc
+++ b/chromium/content/browser/code_cache/generated_code_cache.cc
@@ -58,66 +58,103 @@ std::string GetCacheKey(const GURL& resource_url,
// being initialized.
class GeneratedCodeCache::PendingOperation {
public:
- PendingOperation(Operation op,
- std::string key,
- scoped_refptr<net::IOBufferWithSize>);
- PendingOperation(Operation op, std::string key, const ReadDataCallback&);
- PendingOperation(Operation op, std::string key);
+ static std::unique_ptr<PendingOperation> CreateWritePendingOp(
+ std::string key,
+ scoped_refptr<net::IOBufferWithSize>);
+ static std::unique_ptr<PendingOperation> CreateFetchPendingOp(
+ std::string key,
+ const ReadDataCallback&);
+ static std::unique_ptr<PendingOperation> CreateDeletePendingOp(
+ std::string key);
+ static std::unique_ptr<PendingOperation> CreateClearCachePendingOp(
+ net::CompletionCallback callback);
~PendingOperation();
Operation operation() const { return op_; }
const std::string& key() const { return key_; }
const scoped_refptr<net::IOBufferWithSize> data() const { return data_; }
- const ReadDataCallback& callback() const { return callback_; }
+ ReadDataCallback ReleaseReadCallback() { return std::move(read_callback_); }
+ net::CompletionCallback ReleaseCallback() { return std::move(callback_); }
private:
+ PendingOperation(Operation op,
+ std::string key,
+ scoped_refptr<net::IOBufferWithSize>,
+ const ReadDataCallback&,
+ net::CompletionCallback);
+
const Operation op_;
const std::string key_;
const scoped_refptr<net::IOBufferWithSize> data_;
- const ReadDataCallback callback_;
+ ReadDataCallback read_callback_;
+ net::CompletionCallback callback_;
};
-GeneratedCodeCache::PendingOperation::PendingOperation(
- Operation op,
+std::unique_ptr<GeneratedCodeCache::PendingOperation>
+GeneratedCodeCache::PendingOperation::CreateWritePendingOp(
std::string key,
- scoped_refptr<net::IOBufferWithSize> buffer)
- : op_(op),
- key_(std::move(key)),
- data_(buffer),
- callback_(ReadDataCallback()) {}
+ scoped_refptr<net::IOBufferWithSize> buffer) {
+ return base::WrapUnique(
+ new PendingOperation(Operation::kWrite, std::move(key), buffer,
+ ReadDataCallback(), net::CompletionCallback()));
+}
+
+std::unique_ptr<GeneratedCodeCache::PendingOperation>
+GeneratedCodeCache::PendingOperation::CreateFetchPendingOp(
+ std::string key,
+ const ReadDataCallback& read_callback) {
+ return base::WrapUnique(new PendingOperation(
+ Operation::kFetch, std::move(key), scoped_refptr<net::IOBufferWithSize>(),
+ read_callback, net::CompletionCallback()));
+}
+
+std::unique_ptr<GeneratedCodeCache::PendingOperation>
+GeneratedCodeCache::PendingOperation::CreateDeletePendingOp(std::string key) {
+ return base::WrapUnique(
+ new PendingOperation(Operation::kDelete, std::move(key),
+ scoped_refptr<net::IOBufferWithSize>(),
+ ReadDataCallback(), net::CompletionCallback()));
+}
+
+std::unique_ptr<GeneratedCodeCache::PendingOperation>
+GeneratedCodeCache::PendingOperation::CreateClearCachePendingOp(
+ net::CompletionCallback callback) {
+ return base::WrapUnique(
+ new PendingOperation(Operation::kClearCache, std::string(),
+ scoped_refptr<net::IOBufferWithSize>(),
+ ReadDataCallback(), std::move(callback)));
+}
GeneratedCodeCache::PendingOperation::PendingOperation(
Operation op,
std::string key,
- const ReadDataCallback& callback)
- : op_(op),
- key_(std::move(key)),
- data_(scoped_refptr<net::IOBufferWithSize>()),
- callback_(callback) {}
-
-GeneratedCodeCache::PendingOperation::PendingOperation(Operation op,
- std::string key)
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const ReadDataCallback& read_callback,
+ net::CompletionCallback callback)
: op_(op),
key_(std::move(key)),
- data_(scoped_refptr<net::IOBufferWithSize>()),
- callback_(ReadDataCallback()) {}
+ data_(buffer),
+ read_callback_(read_callback),
+ callback_(std::move(callback)) {}
GeneratedCodeCache::PendingOperation::~PendingOperation() = default;
-// Static factory method.
-std::unique_ptr<GeneratedCodeCache> GeneratedCodeCache::Create(
- const base::FilePath& path,
- int max_size_bytes) {
- return base::WrapUnique(new GeneratedCodeCache(path, max_size_bytes));
+GeneratedCodeCache::GeneratedCodeCache(const base::FilePath& path,
+ int max_size_bytes)
+ : backend_state_(kUnInitialized),
+ path_(path),
+ max_size_bytes_(max_size_bytes),
+ weak_ptr_factory_(this) {
+ CreateBackend();
}
GeneratedCodeCache::~GeneratedCodeCache() = default;
-void GeneratedCodeCache::WriteData(
- const GURL& url,
- const url::Origin& origin,
- scoped_refptr<net::IOBufferWithSize> buffer) {
+void GeneratedCodeCache::WriteData(const GURL& url,
+ const url::Origin& origin,
+ const base::Time& response_time,
+ const std::vector<uint8_t>& data) {
// Silently ignore the requests.
if (backend_state_ == kFailed)
return;
@@ -127,12 +164,24 @@ void GeneratedCodeCache::WriteData(
if (!IsAllowedToCache(url, origin))
return;
+ // Append the response time to the metadata. Code caches store
+ // response_time + generated code as a single entry.
+ scoped_refptr<net::IOBufferWithSize> buffer(
+ new net::IOBufferWithSize(data.size() + kResponseTimeSizeInBytes));
+ int64_t serialized_time =
+ response_time.ToDeltaSinceWindowsEpoch().InMicroseconds();
+ memcpy(buffer->data(), &serialized_time, kResponseTimeSizeInBytes);
+ if (!data.empty())
+ memcpy(buffer->data() + kResponseTimeSizeInBytes, &data.front(),
+ data.size());
+
std::string key = GetCacheKey(url, origin);
if (backend_state_ != kInitialized) {
// Insert it into the list of pending operations while the backend is
// still being opened.
- pending_ops_.push_back(std::make_unique<PendingOperation>(
- Operation::kWrite, std::move(key), buffer));
+ pending_ops_.push_back(
+ GeneratedCodeCache::PendingOperation::CreateWritePendingOp(
+ std::move(key), buffer));
return;
}
@@ -144,14 +193,14 @@ void GeneratedCodeCache::FetchEntry(const GURL& url,
ReadDataCallback read_data_callback) {
if (backend_state_ == kFailed) {
// Silently ignore the requests.
- std::move(read_data_callback).Run(scoped_refptr<net::IOBufferWithSize>());
+ std::move(read_data_callback).Run(base::Time(), std::vector<uint8_t>());
return;
}
// If the url is invalid or if it is from a unique origin, we should not
// cache the code.
if (!IsAllowedToCache(url, origin)) {
- std::move(read_data_callback).Run(scoped_refptr<net::IOBufferWithSize>());
+ std::move(read_data_callback).Run(base::Time(), std::vector<uint8_t>());
return;
}
@@ -159,8 +208,9 @@ void GeneratedCodeCache::FetchEntry(const GURL& url,
if (backend_state_ != kInitialized) {
// Insert it into the list of pending operations while the backend is
// still being opened.
- pending_ops_.push_back(std::make_unique<PendingOperation>(
- Operation::kFetch, std::move(key), read_data_callback));
+ pending_ops_.push_back(
+ GeneratedCodeCache::PendingOperation::CreateFetchPendingOp(
+ std::move(key), read_data_callback));
return;
}
@@ -183,20 +233,27 @@ void GeneratedCodeCache::DeleteEntry(const GURL& url,
// Insert it into the list of pending operations while the backend is
// still being opened.
pending_ops_.push_back(
- std::make_unique<PendingOperation>(Operation::kDelete, std::move(key)));
+ GeneratedCodeCache::PendingOperation::CreateDeletePendingOp(
+ std::move(key)));
return;
}
DeleteEntryImpl(key);
}
-GeneratedCodeCache::GeneratedCodeCache(const base::FilePath& path,
- int max_size_bytes)
- : backend_state_(kUnInitialized),
- path_(path),
- max_size_bytes_(max_size_bytes),
- weak_ptr_factory_(this) {
- CreateBackend();
+int GeneratedCodeCache::ClearCache(net::CompletionCallback callback) {
+ if (backend_state_ == kFailed) {
+ return net::ERR_FAILED;
+ }
+
+ if (backend_state_ != kInitialized) {
+ pending_ops_.push_back(
+ GeneratedCodeCache::PendingOperation::CreateClearCachePendingOp(
+ std::move(callback)));
+ return net::ERR_IO_PENDING;
+ }
+
+ return backend_->DoomAllEntries(std::move(callback));
}
void GeneratedCodeCache::CreateBackend() {
@@ -242,7 +299,7 @@ void GeneratedCodeCache::IssuePendingOperations() {
for (auto const& op : pending_ops_) {
switch (op->operation()) {
case kFetch:
- FetchEntryImpl(op->key(), op->callback());
+ FetchEntryImpl(op->key(), op->ReleaseReadCallback());
break;
case kWrite:
WriteDataImpl(op->key(), op->data());
@@ -250,6 +307,9 @@ void GeneratedCodeCache::IssuePendingOperations() {
case kDelete:
DeleteEntryImpl(op->key());
break;
+ case kClearCache:
+ DoPendingClearCache(op->ReleaseCallback());
+ break;
}
}
pending_ops_.clear();
@@ -318,7 +378,7 @@ void GeneratedCodeCache::CreateCompleteForWriteData(
void GeneratedCodeCache::FetchEntryImpl(const std::string& key,
ReadDataCallback read_data_callback) {
if (backend_state_ != kInitialized) {
- std::move(read_data_callback).Run(scoped_refptr<net::IOBufferWithSize>());
+ std::move(read_data_callback).Run(base::Time(), std::vector<uint8_t>());
return;
}
@@ -342,7 +402,7 @@ void GeneratedCodeCache::OpenCompleteForReadData(
scoped_refptr<base::RefCountedData<disk_cache::Entry*>> entry,
int rv) {
if (rv != net::OK) {
- std::move(read_data_callback).Run(scoped_refptr<net::IOBufferWithSize>());
+ std::move(read_data_callback).Run(base::Time(), std::vector<uint8_t>());
return;
}
@@ -367,9 +427,14 @@ void GeneratedCodeCache::ReadDataComplete(
scoped_refptr<net::IOBufferWithSize> buffer,
int rv) {
if (rv != buffer->size()) {
- std::move(callback).Run(scoped_refptr<net::IOBufferWithSize>());
+ std::move(callback).Run(base::Time(), std::vector<uint8_t>());
} else {
- std::move(callback).Run(buffer);
+ int64_t raw_response_time = *(reinterpret_cast<int64_t*>(buffer->data()));
+ base::Time response_time = base::Time::FromDeltaSinceWindowsEpoch(
+ base::TimeDelta::FromMicroseconds(raw_response_time));
+ std::vector<uint8_t> data(buffer->data() + kResponseTimeSizeInBytes,
+ buffer->data() + buffer->size());
+ std::move(callback).Run(response_time, data);
}
}
@@ -380,4 +445,14 @@ void GeneratedCodeCache::DeleteEntryImpl(const std::string& key) {
backend_->DoomEntry(key, net::LOWEST, net::CompletionOnceCallback());
}
+void GeneratedCodeCache::DoPendingClearCache(
+ net::CompletionCallback user_callback) {
+ int result = backend_->DoomAllEntries(user_callback);
+ if (result != net::ERR_IO_PENDING) {
+ // Call the callback here because we returned ERR_IO_PENDING for initial
+ // request.
+ std::move(user_callback).Run(result);
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/code_cache/generated_code_cache.h b/chromium/content/browser/code_cache/generated_code_cache.h
index 57e92b76946..58e735b447d 100644
--- a/chromium/content/browser/code_cache/generated_code_cache.h
+++ b/chromium/content/browser/code_cache/generated_code_cache.h
@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "content/common/content_export.h"
+#include "net/base/completion_callback.h"
#include "net/base/io_buffer.h"
#include "net/disk_cache/disk_cache.h"
#include "url/origin.h"
@@ -31,11 +32,14 @@ namespace content {
class CONTENT_EXPORT GeneratedCodeCache {
public:
using ReadDataCallback =
- base::RepeatingCallback<void(scoped_refptr<net::IOBufferWithSize>)>;
+ base::RepeatingCallback<void(const base::Time&,
+ const std::vector<uint8_t>&)>;
+ static const int kResponseTimeSizeInBytes = sizeof(int64_t);
// Creates a GeneratedCodeCache with the specified path and the maximum size.
- static std::unique_ptr<GeneratedCodeCache> Create(const base::FilePath& path,
- int max_size);
+ // If |max_size_bytes| is 0, then disk_cache picks a default size based on
+ // some heuristics.
+ GeneratedCodeCache(const base::FilePath& path, int max_size_bytes);
~GeneratedCodeCache();
@@ -44,7 +48,8 @@ class CONTENT_EXPORT GeneratedCodeCache {
// it creates a new one.
void WriteData(const GURL& url,
const url::Origin& origin,
- scoped_refptr<net::IOBufferWithSize>);
+ const base::Time& response_time,
+ const std::vector<uint8_t>& data);
// Fetch entry corresponding to <url, origin> from the cache and pass
// it using the ReadDataCallback.
@@ -53,6 +58,13 @@ class CONTENT_EXPORT GeneratedCodeCache {
// Delete the entry corresponding to <url, origin>
void DeleteEntry(const GURL& url, const url::Origin& origin);
+ // Clear code cache.
+ // TODO(mythria): Add support to conditional clearing based on URL
+ // and time range.
+ // TODO(mythria): Also check if we can avoid retruning an error code and
+ // always call the callback to be consistent with other methods.
+ int ClearCache(net::CompletionCallback callback);
+
const base::FilePath& path() const { return path_; }
private:
@@ -63,13 +75,11 @@ class CONTENT_EXPORT GeneratedCodeCache {
enum BackendState { kUnInitialized, kInitializing, kInitialized, kFailed };
// The operation requested.
- enum Operation { kFetch, kWrite, kDelete };
+ enum Operation { kFetch, kWrite, kDelete, kClearCache };
// Data streams corresponding to each entry.
enum { kDataIndex = 1 };
- GeneratedCodeCache(const base::FilePath& path, int max_size_bytes);
-
// Creates a simple_disk_cache backend.
void CreateBackend();
void DidCreateBackend(
@@ -107,6 +117,9 @@ class CONTENT_EXPORT GeneratedCodeCache {
// Delete entry from cache
void DeleteEntryImpl(const std::string& key);
+ void DoPendingClearCache(net::CompletionCallback callback);
+ void PendingClearComplete(net::CompletionCallback callback, int rv);
+
std::unique_ptr<disk_cache::Backend> backend_;
BackendState backend_state_;
diff --git a/chromium/content/browser/code_cache/generated_code_cache_context.cc b/chromium/content/browser/code_cache/generated_code_cache_context.cc
new file mode 100644
index 00000000000..9aa1621fce3
--- /dev/null
+++ b/chromium/content/browser/code_cache/generated_code_cache_context.cc
@@ -0,0 +1,37 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "content/browser/code_cache/generated_code_cache_context.h"
+#include "base/files/file_path.h"
+#include "content/browser/code_cache/generated_code_cache.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+
+GeneratedCodeCacheContext::GeneratedCodeCacheContext() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+}
+
+void GeneratedCodeCacheContext::Initialize(const base::FilePath& path,
+ int max_bytes) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&GeneratedCodeCacheContext::InitializeOnIO, this, path,
+ max_bytes));
+}
+
+void GeneratedCodeCacheContext::InitializeOnIO(const base::FilePath& path,
+ int max_bytes) {
+ generated_code_cache_.reset(new GeneratedCodeCache(path, max_bytes));
+}
+
+GeneratedCodeCache* GeneratedCodeCacheContext::generated_code_cache() const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ return generated_code_cache_.get();
+}
+
+GeneratedCodeCacheContext::~GeneratedCodeCacheContext() = default;
+
+} // namespace content
diff --git a/chromium/content/browser/code_cache/generated_code_cache_context.h b/chromium/content/browser/code_cache/generated_code_cache_context.h
new file mode 100644
index 00000000000..4a42bebef7b
--- /dev/null
+++ b/chromium/content/browser/code_cache/generated_code_cache_context.h
@@ -0,0 +1,51 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_CODE_CACHE_GENERATED_CODE_CACHE_CONTEXT_H_
+#define CONTENT_BROWSER_CODE_CACHE_GENERATED_CODE_CACHE_CONTEXT_H_
+
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+
+class GeneratedCodeCache;
+
+// One instance exists per disk-backed (non in-memory) storage contexts. This
+// owns the instance of GeneratedCodeCache that is used to store the data
+// generated by the renderer (for ex: code caches for script resources). This
+// initializes and closes the code cache on the I/O thread. The instance of
+// this class (|this|) itself is constructed on the UI thread.
+class CONTENT_EXPORT GeneratedCodeCacheContext
+ : public base::RefCountedThreadSafe<GeneratedCodeCacheContext> {
+ public:
+ REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE();
+
+ GeneratedCodeCacheContext();
+
+ // Initialize is called on the UI thread when the StoragePartition is
+ // being setup.
+ void Initialize(const base::FilePath& path, int max_bytes);
+
+ // Call on the IO thread to get the code cache instance.
+ GeneratedCodeCache* generated_code_cache() const;
+
+ private:
+ friend class base::RefCountedThreadSafe<GeneratedCodeCacheContext>;
+ ~GeneratedCodeCacheContext();
+
+ void InitializeOnIO(const base::FilePath& path, int max_bytes);
+
+ // Created, used and deleted on the IO thread.
+ std::unique_ptr<GeneratedCodeCache, BrowserThread::DeleteOnIOThread>
+ generated_code_cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(GeneratedCodeCacheContext);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_CODE_CACHE_GENERATED_CACHE_CONTEXT_H_
diff --git a/chromium/content/browser/code_cache/generated_code_cache_unittest.cc b/chromium/content/browser/code_cache/generated_code_cache_unittest.cc
index 45ea2246f85..4f005c89c9a 100644
--- a/chromium/content/browser/code_cache/generated_code_cache_unittest.cc
+++ b/chromium/content/browser/code_cache/generated_code_cache_unittest.cc
@@ -26,7 +26,7 @@ class GeneratedCodeCacheTest : public testing::Test {
ASSERT_TRUE(cache_dir_.CreateUniqueTempDir());
cache_path_ = cache_dir_.GetPath();
generated_code_cache_ =
- GeneratedCodeCache::Create(cache_path_, kMaxSizeInBytes);
+ std::make_unique<GeneratedCodeCache>(cache_path_, kMaxSizeInBytes);
}
void TearDown() override {
@@ -39,7 +39,7 @@ class GeneratedCodeCacheTest : public testing::Test {
void InitializeCache() {
GURL url(kInitialUrl);
url::Origin origin = url::Origin::Create(GURL(kInitialOrigin));
- WriteToCache(url, origin, kInitialData);
+ WriteToCache(url, origin, kInitialData, base::Time::Now());
scoped_task_environment_.RunUntilIdle();
}
@@ -48,18 +48,16 @@ class GeneratedCodeCacheTest : public testing::Test {
// to test the pending operaions path.
void InitializeCacheAndReOpen() {
InitializeCache();
- generated_code_cache_.reset();
- generated_code_cache_ =
- GeneratedCodeCache::Create(cache_path_, kMaxSizeInBytes);
+ generated_code_cache_.reset(
+ new GeneratedCodeCache(cache_path_, kMaxSizeInBytes));
}
void WriteToCache(const GURL& url,
const url::Origin& origin,
- const std::string& data) {
- scoped_refptr<net::IOBufferWithSize> buffer(
- new net::IOBufferWithSize(data.length()));
- memcpy(buffer->data(), data.c_str(), data.length());
- generated_code_cache_->WriteData(url, origin, buffer);
+ const std::string& data,
+ base::Time response_time) {
+ std::vector<uint8_t> vector_data(data.begin(), data.end());
+ generated_code_cache_->WriteData(url, origin, response_time, vector_data);
}
void DeleteFromCache(const GURL& url, const url::Origin& origin) {
@@ -73,16 +71,26 @@ class GeneratedCodeCacheTest : public testing::Test {
generated_code_cache_->FetchEntry(url, origin, callback);
}
- void FetchEntryCallback(scoped_refptr<net::IOBufferWithSize> buffer) {
- if (!buffer || !buffer->data()) {
+ void ClearCache() {
+ generated_code_cache_->ClearCache(base::BindRepeating(
+ &GeneratedCodeCacheTest::ClearCacheComplete, base::Unretained(this)));
+ }
+
+ void ClearCacheComplete(int rv) {}
+
+ void FetchEntryCallback(const base::Time& response_time,
+ const std::vector<uint8_t>& data) {
+ if (data.size() == 0) {
received_ = true;
received_null_ = true;
+ received_response_time_ = response_time;
return;
}
- std::string str(buffer->data(), buffer->size());
+ std::string str(data.begin(), data.end());
received_ = true;
received_null_ = false;
received_data_ = str;
+ received_response_time_ = response_time;
}
protected:
@@ -90,6 +98,7 @@ class GeneratedCodeCacheTest : public testing::Test {
std::unique_ptr<GeneratedCodeCache> generated_code_cache_;
base::ScopedTempDir cache_dir_;
std::string received_data_;
+ base::Time received_response_time_;
bool received_;
bool received_null_;
base::FilePath cache_path_;
@@ -98,6 +107,23 @@ class GeneratedCodeCacheTest : public testing::Test {
constexpr char GeneratedCodeCacheTest::kInitialUrl[];
constexpr char GeneratedCodeCacheTest::kInitialOrigin[];
constexpr char GeneratedCodeCacheTest::kInitialData[];
+const int GeneratedCodeCacheTest::kMaxSizeInBytes;
+
+TEST_F(GeneratedCodeCacheTest, CheckResponseTime) {
+ GURL url(kInitialUrl);
+ url::Origin origin = url::Origin::Create(GURL(kInitialOrigin));
+
+ std::string data = "SerializedCodeForScript";
+ base::Time response_time = base::Time::Now();
+ WriteToCache(url, origin, data, response_time);
+ scoped_task_environment_.RunUntilIdle();
+ FetchFromCache(url, origin);
+ scoped_task_environment_.RunUntilIdle();
+
+ ASSERT_TRUE(received_);
+ EXPECT_EQ(data, received_data_);
+ EXPECT_EQ(response_time, received_response_time_);
+}
TEST_F(GeneratedCodeCacheTest, FetchEntry) {
GURL url(kInitialUrl);
@@ -117,12 +143,15 @@ TEST_F(GeneratedCodeCacheTest, WriteEntry) {
InitializeCache();
std::string data = "SerializedCodeForScript";
- WriteToCache(new_url, origin, data);
+ base::Time response_time = base::Time::Now();
+ WriteToCache(new_url, origin, data, response_time);
+ scoped_task_environment_.RunUntilIdle();
FetchFromCache(new_url, origin);
scoped_task_environment_.RunUntilIdle();
ASSERT_TRUE(received_);
EXPECT_EQ(data, received_data_);
+ EXPECT_EQ(response_time, received_response_time_);
}
TEST_F(GeneratedCodeCacheTest, DeleteEntry) {
@@ -156,13 +185,15 @@ TEST_F(GeneratedCodeCacheTest, WriteEntryPendingOp) {
InitializeCache();
std::string data = "SerializedCodeForScript";
- WriteToCache(new_url, origin, data);
+ base::Time response_time = base::Time::Now();
+ WriteToCache(new_url, origin, data, response_time);
scoped_task_environment_.RunUntilIdle();
FetchFromCache(new_url, origin);
scoped_task_environment_.RunUntilIdle();
ASSERT_TRUE(received_);
EXPECT_EQ(data, received_data_);
+ EXPECT_EQ(response_time, received_response_time_);
}
TEST_F(GeneratedCodeCacheTest, DeleteEntryPendingOp) {
@@ -184,12 +215,15 @@ TEST_F(GeneratedCodeCacheTest, UpdateDataOfExistingEntry) {
InitializeCache();
std::string new_data = "SerializedCodeForScriptOverwrite";
- WriteToCache(url, origin, new_data);
+ base::Time response_time = base::Time::Now();
+ WriteToCache(url, origin, new_data, response_time);
+ scoped_task_environment_.RunUntilIdle();
FetchFromCache(url, origin);
scoped_task_environment_.RunUntilIdle();
ASSERT_TRUE(received_);
EXPECT_EQ(new_data, received_data_);
+ EXPECT_EQ(response_time, received_response_time_);
}
TEST_F(GeneratedCodeCacheTest, FetchFailsForNonexistingOrigin) {
@@ -208,10 +242,10 @@ TEST_F(GeneratedCodeCacheTest, FetchEntriesFromSameOrigin) {
url::Origin origin = url::Origin::Create(GURL(kInitialOrigin));
std::string data_first_resource = "SerializedCodeForFirstResource";
- WriteToCache(url, origin, data_first_resource);
+ WriteToCache(url, origin, data_first_resource, base::Time());
std::string data_second_resource = "SerializedCodeForSecondResource";
- WriteToCache(second_url, origin, data_second_resource);
+ WriteToCache(second_url, origin, data_second_resource, base::Time());
scoped_task_environment_.RunUntilIdle();
FetchFromCache(url, origin);
@@ -231,10 +265,10 @@ TEST_F(GeneratedCodeCacheTest, FetchSucceedsFromDifferentOrigins) {
url::Origin origin1 = url::Origin::Create(GURL("http://example1.com"));
std::string data_origin = "SerializedCodeForFirstOrigin";
- WriteToCache(url, origin, data_origin);
+ WriteToCache(url, origin, data_origin, base::Time());
std::string data_origin1 = "SerializedCodeForSecondOrigin";
- WriteToCache(url, origin1, data_origin1);
+ WriteToCache(url, origin1, data_origin1, base::Time());
scoped_task_environment_.RunUntilIdle();
FetchFromCache(url, origin);
@@ -254,7 +288,7 @@ TEST_F(GeneratedCodeCacheTest, FetchFailsForUniqueOrigin) {
url::Origin::Create(GURL("data:text/html,<script></script>"));
std::string data = "SerializedCodeForUniqueOrigin";
- WriteToCache(url, origin, data);
+ WriteToCache(url, origin, data, base::Time());
scoped_task_environment_.RunUntilIdle();
FetchFromCache(url, origin);
@@ -268,11 +302,12 @@ TEST_F(GeneratedCodeCacheTest, FetchFailsForInvalidOrigin) {
url::Origin origin = url::Origin::Create(GURL("invalidURL"));
std::string data = "SerializedCodeForInvalidOrigin";
- WriteToCache(url, origin, data);
+ WriteToCache(url, origin, data, base::Time());
scoped_task_environment_.RunUntilIdle();
FetchFromCache(url, origin);
scoped_task_environment_.RunUntilIdle();
+
ASSERT_TRUE(received_);
ASSERT_TRUE(received_null_);
}
@@ -282,7 +317,7 @@ TEST_F(GeneratedCodeCacheTest, FetchFailsForInvalidURL) {
url::Origin origin = url::Origin::Create(GURL("http://example.com"));
std::string data = "SerializedCodeForInvalidURL";
- WriteToCache(url, origin, data);
+ WriteToCache(url, origin, data, base::Time());
scoped_task_environment_.RunUntilIdle();
FetchFromCache(url, origin);
@@ -290,4 +325,18 @@ TEST_F(GeneratedCodeCacheTest, FetchFailsForInvalidURL) {
ASSERT_TRUE(received_);
ASSERT_TRUE(received_null_);
}
+
+TEST_F(GeneratedCodeCacheTest, ClearCache) {
+ GURL url("http://example.com/script.js");
+ url::Origin origin = url::Origin::Create(GURL("http://example.com"));
+
+ InitializeCache();
+ ClearCache();
+ scoped_task_environment_.RunUntilIdle();
+ FetchFromCache(url, origin);
+ scoped_task_environment_.RunUntilIdle();
+
+ ASSERT_TRUE(received_);
+ ASSERT_TRUE(received_null_);
+}
} // namespace content
diff --git a/chromium/content/browser/compositor/DEPS b/chromium/content/browser/compositor/DEPS
index 1b482fbe5b9..91404304090 100644
--- a/chromium/content/browser/compositor/DEPS
+++ b/chromium/content/browser/compositor/DEPS
@@ -2,7 +2,7 @@ include_rules = [
"+components/viz/common",
"+components/viz/host",
"+components/viz/service",
- "+services/ui/public/cpp",
+ "+services/ws/public/cpp",
"+ui/platform_window",
]
diff --git a/chromium/content/browser/compositor/browser_compositor_output_surface.cc b/chromium/content/browser/compositor/browser_compositor_output_surface.cc
index 924e82dadab..d96efe91eea 100644
--- a/chromium/content/browser/compositor/browser_compositor_output_surface.cc
+++ b/chromium/content/browser/compositor/browser_compositor_output_surface.cc
@@ -14,7 +14,7 @@
#include "components/viz/service/display/output_surface_client.h"
#include "components/viz/service/display_embedder/compositor_overlay_candidate_validator.h"
#include "content/browser/compositor/reflector_impl.h"
-#include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
+#include "services/ws/public/cpp/gpu/context_provider_command_buffer.h"
namespace content {
diff --git a/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.cc b/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.cc
index 15226b0f4d7..d6bcbc3b922 100644
--- a/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.cc
+++ b/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.cc
@@ -18,13 +18,13 @@
#include "gpu/command_buffer/common/swap_buffers_complete_params.h"
#include "gpu/command_buffer/common/swap_buffers_flags.h"
#include "gpu/ipc/client/command_buffer_proxy_impl.h"
-#include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
+#include "services/ws/public/cpp/gpu/context_provider_command_buffer.h"
#include "ui/gl/gl_utils.h"
namespace content {
GpuBrowserCompositorOutputSurface::GpuBrowserCompositorOutputSurface(
- scoped_refptr<ui::ContextProviderCommandBuffer> context,
+ scoped_refptr<ws::ContextProviderCommandBuffer> context,
const UpdateVSyncParametersCallback& update_vsync_parameters_callback,
std::unique_ptr<viz::CompositorOverlayCandidateValidator>
overlay_candidate_validator)
@@ -147,7 +147,7 @@ void GpuBrowserCompositorOutputSurface::SwapBuffers(
}
uint32_t GpuBrowserCompositorOutputSurface::GetFramebufferCopyTextureFormat() {
- auto* gl = static_cast<ui::ContextProviderCommandBuffer*>(context_provider());
+ auto* gl = static_cast<ws::ContextProviderCommandBuffer*>(context_provider());
return gl->GetCopyTextureInternalFormat();
}
@@ -192,8 +192,8 @@ void GpuBrowserCompositorOutputSurface::OnUpdateVSyncParameters(
gpu::CommandBufferProxyImpl*
GpuBrowserCompositorOutputSurface::GetCommandBufferProxy() {
- ui::ContextProviderCommandBuffer* provider_command_buffer =
- static_cast<ui::ContextProviderCommandBuffer*>(context_provider_.get());
+ ws::ContextProviderCommandBuffer* provider_command_buffer =
+ static_cast<ws::ContextProviderCommandBuffer*>(context_provider_.get());
gpu::CommandBufferProxyImpl* command_buffer_proxy =
provider_command_buffer->GetCommandBufferProxy();
DCHECK(command_buffer_proxy);
diff --git a/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.h b/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.h
index 67ef5d40f1c..a7153104e1c 100644
--- a/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.h
+++ b/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.h
@@ -27,7 +27,7 @@ class CommandBufferProxyImpl;
struct SwapBuffersCompleteParams;
}
-namespace ui {
+namespace ws {
class ContextProviderCommandBuffer;
}
@@ -41,7 +41,7 @@ class GpuBrowserCompositorOutputSurface
: public BrowserCompositorOutputSurface {
public:
GpuBrowserCompositorOutputSurface(
- scoped_refptr<ui::ContextProviderCommandBuffer> context,
+ scoped_refptr<ws::ContextProviderCommandBuffer> context,
const UpdateVSyncParametersCallback& update_vsync_parameters_callback,
std::unique_ptr<viz::CompositorOverlayCandidateValidator>
overlay_candidate_validator);
diff --git a/chromium/content/browser/compositor/gpu_output_surface_mac.cc b/chromium/content/browser/compositor/gpu_output_surface_mac.cc
index 7c5b22d9df7..1a8833894fd 100644
--- a/chromium/content/browser/compositor/gpu_output_surface_mac.cc
+++ b/chromium/content/browser/compositor/gpu_output_surface_mac.cc
@@ -8,12 +8,12 @@
#include "components/viz/service/display/output_surface_frame.h"
#include "components/viz/service/display_embedder/compositor_overlay_candidate_validator.h"
#include "gpu/GLES2/gl2extchromium.h"
-#include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
+#include "services/ws/public/cpp/gpu/context_provider_command_buffer.h"
namespace content {
GpuOutputSurfaceMac::GpuOutputSurfaceMac(
- scoped_refptr<ui::ContextProviderCommandBuffer> context,
+ scoped_refptr<ws::ContextProviderCommandBuffer> context,
gpu::SurfaceHandle surface_handle,
const UpdateVSyncParametersCallback& update_vsync_parameters_callback,
std::unique_ptr<viz::CompositorOverlayCandidateValidator>
diff --git a/chromium/content/browser/compositor/gpu_output_surface_mac.h b/chromium/content/browser/compositor/gpu_output_surface_mac.h
index 73ad778a50a..0fe8986a17b 100644
--- a/chromium/content/browser/compositor/gpu_output_surface_mac.h
+++ b/chromium/content/browser/compositor/gpu_output_surface_mac.h
@@ -15,7 +15,7 @@ class GpuOutputSurfaceMac
: public GpuSurfacelessBrowserCompositorOutputSurface {
public:
GpuOutputSurfaceMac(
- scoped_refptr<ui::ContextProviderCommandBuffer> context,
+ scoped_refptr<ws::ContextProviderCommandBuffer> context,
gpu::SurfaceHandle surface_handle,
const UpdateVSyncParametersCallback& update_vsync_parameters_callback,
std::unique_ptr<viz::CompositorOverlayCandidateValidator>
diff --git a/chromium/content/browser/compositor/gpu_process_transport_factory.cc b/chromium/content/browser/compositor/gpu_process_transport_factory.cc
index 511d805187b..642fff3b436 100644
--- a/chromium/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/chromium/content/browser/compositor/gpu_process_transport_factory.cc
@@ -26,7 +26,6 @@
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/frame_sinks/delay_based_time_source.h"
-#include "components/viz/common/gl_helper.h"
#include "components/viz/common/switches.h"
#include "components/viz/host/host_display_client.h"
#include "components/viz/host/host_frame_sink_manager.h"
@@ -63,7 +62,7 @@
#include "gpu/ipc/host/gpu_memory_buffer_support.h"
#include "gpu/vulkan/buildflags.h"
#include "services/service_manager/runner/common/client_util.h"
-#include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
+#include "services/ws/public/cpp/gpu/context_provider_command_buffer.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "ui/base/ui_base_features.h"
#include "ui/base/ui_base_switches_util.h"
@@ -218,7 +217,7 @@ GpuProcessTransportFactory::CreateSoftwareOutputDevice(
return base::WrapUnique(new viz::SoftwareOutputDevice);
#if defined(USE_AURA)
- if (!features::IsAshInBrowserProcess()) {
+ if (features::IsUsingWindowService()) {
NOTREACHED();
return nullptr;
}
@@ -266,7 +265,7 @@ CreateOverlayCandidateValidator(
ozone_platform->GetOverlayManager();
if (!command_line->HasSwitch(switches::kEnableHardwareOverlays) &&
overlay_manager->SupportsOverlays()) {
- enable_overlay_flag = "single-fullscreen,single-on-top";
+ enable_overlay_flag = "single-fullscreen,single-on-top,underlay";
}
if (!enable_overlay_flag.empty()) {
std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates =
@@ -375,7 +374,7 @@ void GpuProcessTransportFactory::EstablishedGpuChannel(
#else
bool use_vulkan = false;
#endif
- scoped_refptr<ui::ContextProviderCommandBuffer> context_provider;
+ scoped_refptr<ws::ContextProviderCommandBuffer> context_provider;
if (!use_gpu_compositing || use_vulkan) {
// If not using GL compositing, don't keep the old shared worker context.
@@ -401,7 +400,7 @@ void GpuProcessTransportFactory::EstablishedGpuChannel(
gpu_channel_host, gpu::kNullSurfaceHandle, need_alpha_channel,
false /* support_stencil */, support_locking, support_gles2_interface,
support_raster_interface, support_grcontext,
- ui::command_buffer_metrics::ContextType::BROWSER_WORKER);
+ ws::command_buffer_metrics::ContextType::BROWSER_WORKER);
auto result = shared_worker_context_provider_->BindToCurrentThread();
if (result != gpu::ContextResult::kSuccess) {
shared_worker_context_provider_ = nullptr;
@@ -428,7 +427,7 @@ void GpuProcessTransportFactory::EstablishedGpuChannel(
std::move(gpu_channel_host), surface_handle, need_alpha_channel,
support_stencil, support_locking, support_gles2_interface,
support_raster_interface, support_grcontext,
- ui::command_buffer_metrics::ContextType::BROWSER_COMPOSITOR);
+ ws::command_buffer_metrics::ContextType::BROWSER_COMPOSITOR);
// On Mac, GpuCommandBufferMsg_SwapBuffersCompleted must be handled in
// a nested run loop during resize.
context_provider->SetDefaultTaskRunner(resize_task_runner_);
@@ -569,7 +568,8 @@ void GpuProcessTransportFactory::EstablishedGpuChannel(
external_begin_frame_source_mojo =
std::make_unique<viz::ExternalBeginFrameSourceMojo>(
std::move(request),
- external_begin_frame_controller_client->GetBoundPtr());
+ external_begin_frame_controller_client->GetBoundPtr(),
+ viz::BeginFrameSource::kNotRestartableId);
begin_frame_source = external_begin_frame_source_mojo.get();
} else if (disable_frame_rate_limit_) {
synthetic_begin_frame_source =
@@ -586,10 +586,6 @@ void GpuProcessTransportFactory::EstablishedGpuChannel(
begin_frame_source = synthetic_begin_frame_source.get();
}
-#if defined(OS_WIN)
- gfx::RenderingWindowManager::GetInstance()->DoSetParentOnChild(
- compositor->widget());
-#endif
if (data->synthetic_begin_frame_source) {
GetFrameSinkManager()->UnregisterBeginFrameSource(
data->synthetic_begin_frame_source.get());
@@ -731,21 +727,10 @@ void GpuProcessTransportFactory::RemoveCompositor(ui::Compositor* compositor) {
}
per_compositor_data_.erase(it);
if (per_compositor_data_.empty()) {
- // Destroying the GLHelper may cause some async actions to be cancelled,
- // causing things to request a new GLHelper. Due to crbug.com/176091 the
- // GLHelper created in this case would be lost/leaked if we just reset()
- // on the |gl_helper_| variable directly. So instead we call reset() on a
- // local std::unique_ptr.
- std::unique_ptr<viz::GLHelper> helper = std::move(gl_helper_);
-
- // If there are any observer left at this point, make sure they clean up
- // before we destroy the GLHelper.
+ // If there are any observers left at this point, notify them that the
+ // context has been lost.
for (auto& observer : observer_list_)
observer.OnLostSharedContext();
-
- helper.reset();
- DCHECK(!gl_helper_) << "Destroying the GLHelper should not cause a new "
- "GLHelper to be created.";
}
#if defined(OS_WIN)
gfx::RenderingWindowManager::GetInstance()->UnregisterParent(
@@ -927,16 +912,6 @@ viz::FrameSinkManagerImpl* GpuProcessTransportFactory::GetFrameSinkManager() {
return BrowserMainLoop::GetInstance()->GetFrameSinkManager();
}
-viz::GLHelper* GpuProcessTransportFactory::GetGLHelper() {
- if (!gl_helper_ && !per_compositor_data_.empty()) {
- scoped_refptr<ContextProvider> provider = SharedMainThreadContextProvider();
- if (provider.get())
- gl_helper_.reset(
- new viz::GLHelper(provider->ContextGL(), provider->ContextSupport()));
- }
- return gl_helper_.get();
-}
-
scoped_refptr<ContextProvider>
GpuProcessTransportFactory::SharedMainThreadContextProvider() {
if (is_gpu_compositing_disabled_)
@@ -957,8 +932,6 @@ GpuProcessTransportFactory::SharedMainThreadContextProvider() {
return nullptr;
}
- // We need a separate context from the compositor's so that skia and gl_helper
- // don't step on each other.
bool need_alpha_channel = false;
bool support_locking = false;
bool support_gles2_interface = true;
@@ -968,7 +941,7 @@ GpuProcessTransportFactory::SharedMainThreadContextProvider() {
std::move(gpu_channel_host), gpu::kNullSurfaceHandle, need_alpha_channel,
false, support_locking, support_gles2_interface, support_raster_interface,
support_grcontext,
- ui::command_buffer_metrics::ContextType::BROWSER_MAIN_THREAD);
+ ws::command_buffer_metrics::ContextType::BROWSER_MAIN_THREAD);
shared_main_thread_contexts_->AddObserver(this);
auto result = shared_main_thread_contexts_->BindToCurrentThread();
if (result != gpu::ContextResult::kSuccess) {
@@ -1016,13 +989,10 @@ void GpuProcessTransportFactory::OnLostMainThreadSharedContext() {
shared_main_thread_contexts_;
shared_main_thread_contexts_ = nullptr;
- std::unique_ptr<viz::GLHelper> lost_gl_helper = std::move(gl_helper_);
-
for (auto& observer : observer_list_)
observer.OnLostSharedContext();
// Kill things that use the shared context before killing the shared context.
- lost_gl_helper.reset();
lost_shared_main_thread_contexts = nullptr;
}
@@ -1057,7 +1027,7 @@ void GpuProcessTransportFactory::OnContextLost() {
callback_factory_.GetWeakPtr()));
}
-scoped_refptr<ui::ContextProviderCommandBuffer>
+scoped_refptr<ws::ContextProviderCommandBuffer>
GpuProcessTransportFactory::CreateContextCommon(
scoped_refptr<gpu::GpuChannelHost> gpu_channel_host,
gpu::SurfaceHandle surface_handle,
@@ -1067,7 +1037,7 @@ GpuProcessTransportFactory::CreateContextCommon(
bool support_gles2_interface,
bool support_raster_interface,
bool support_grcontext,
- ui::command_buffer_metrics::ContextType type) {
+ ws::command_buffer_metrics::ContextType type) {
DCHECK(gpu_channel_host);
DCHECK(!is_gpu_compositing_disabled_);
@@ -1104,7 +1074,7 @@ GpuProcessTransportFactory::CreateContextCommon(
constexpr bool automatic_flushes = false;
GURL url("chrome://gpu/GpuProcessTransportFactory::CreateContextCommon");
- return base::MakeRefCounted<ui::ContextProviderCommandBuffer>(
+ return base::MakeRefCounted<ws::ContextProviderCommandBuffer>(
std::move(gpu_channel_host), GetGpuMemoryBufferManager(), stream_id,
stream_priority, surface_handle, url, automatic_flushes, support_locking,
support_grcontext, gpu::SharedMemoryLimits(), attributes, type);
diff --git a/chromium/content/browser/compositor/gpu_process_transport_factory.h b/chromium/content/browser/compositor/gpu_process_transport_factory.h
index 6704fa4bb4c..08384de8696 100644
--- a/chromium/content/browser/compositor/gpu_process_transport_factory.h
+++ b/chromium/content/browser/compositor/gpu_process_transport_factory.h
@@ -23,7 +23,7 @@
#include "content/browser/compositor/image_transport_factory.h"
#include "gpu/ipc/client/gpu_channel_host.h"
#include "gpu/vulkan/buildflags.h"
-#include "services/ui/public/cpp/gpu/command_buffer_metrics.h"
+#include "services/ws/public/cpp/gpu/command_buffer_metrics.h"
#include "ui/compositor/compositor.h"
namespace base {
@@ -40,10 +40,6 @@ class GpuChannelEstablishFactory;
class VulkanImplementation;
}
-namespace ui {
-class ContextProviderCommandBuffer;
-}
-
namespace viz {
class CompositingModeReporterImpl;
class OutputDeviceBacking;
@@ -53,6 +49,10 @@ class VulkanInProcessContextProvider;
class RasterContextProvider;
}
+namespace ws {
+class ContextProviderCommandBuffer;
+}
+
namespace content {
class GpuProcessTransportFactory : public ui::ContextFactory,
@@ -111,7 +111,6 @@ class GpuProcessTransportFactory : public ui::ContextFactory,
ui::ContextFactory* GetContextFactory() override;
ui::ContextFactoryPrivate* GetContextFactoryPrivate() override;
viz::FrameSinkManagerImpl* GetFrameSinkManager() override;
- viz::GLHelper* GetGLHelper() override;
private:
struct PerCompositorData;
@@ -137,7 +136,7 @@ class GpuProcessTransportFactory : public ui::ContextFactory,
// viz::ContextLostObserver implementation.
void OnContextLost() override;
- scoped_refptr<ui::ContextProviderCommandBuffer> CreateContextCommon(
+ scoped_refptr<ws::ContextProviderCommandBuffer> CreateContextCommon(
scoped_refptr<gpu::GpuChannelHost> gpu_channel_host,
gpu::SurfaceHandle surface_handle,
bool need_alpha_channel,
@@ -146,7 +145,7 @@ class GpuProcessTransportFactory : public ui::ContextFactory,
bool support_gles2_interface,
bool support_raster_interface,
bool support_grcontext,
- ui::command_buffer_metrics::ContextType type);
+ ws::command_buffer_metrics::ContextType type);
viz::FrameSinkIdAllocator frame_sink_id_allocator_;
@@ -165,9 +164,8 @@ class GpuProcessTransportFactory : public ui::ContextFactory,
PerCompositorDataMap per_compositor_data_;
const viz::RendererSettings renderer_settings_;
- scoped_refptr<ui::ContextProviderCommandBuffer> shared_main_thread_contexts_;
- std::unique_ptr<viz::GLHelper> gl_helper_;
- base::ObserverList<ui::ContextFactoryObserver> observer_list_;
+ scoped_refptr<ws::ContextProviderCommandBuffer> shared_main_thread_contexts_;
+ base::ObserverList<ui::ContextFactoryObserver>::Unchecked observer_list_;
scoped_refptr<base::SingleThreadTaskRunner> resize_task_runner_;
std::unique_ptr<cc::SingleThreadTaskGraphRunner> task_graph_runner_;
scoped_refptr<viz::RasterContextProvider> shared_worker_context_provider_;
diff --git a/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc b/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc
index c2a3a8d7b5e..dda311477dc 100644
--- a/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc
+++ b/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc
@@ -6,7 +6,6 @@
#include <utility>
-#include "components/viz/common/gl_helper.h"
#include "components/viz/service/display/output_surface_client.h"
#include "components/viz/service/display/output_surface_frame.h"
#include "components/viz/service/display_embedder/buffer_queue.h"
@@ -15,13 +14,13 @@
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/common/swap_buffers_complete_params.h"
-#include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
+#include "services/ws/public/cpp/gpu/context_provider_command_buffer.h"
namespace content {
GpuSurfacelessBrowserCompositorOutputSurface::
GpuSurfacelessBrowserCompositorOutputSurface(
- scoped_refptr<ui::ContextProviderCommandBuffer> context,
+ scoped_refptr<ws::ContextProviderCommandBuffer> context,
gpu::SurfaceHandle surface_handle,
const UpdateVSyncParametersCallback& update_vsync_parameters_callback,
std::unique_ptr<viz::CompositorOverlayCandidateValidator>
@@ -50,11 +49,9 @@ GpuSurfacelessBrowserCompositorOutputSurface::
// implementation.
capabilities_.max_frames_pending = 2;
- gl_helper_.reset(new viz::GLHelper(context_provider_->ContextGL(),
- context_provider_->ContextSupport()));
buffer_queue_.reset(new viz::BufferQueue(
context_provider_->ContextGL(), target, internalformat, format,
- gl_helper_.get(), gpu_memory_buffer_manager_, surface_handle));
+ gpu_memory_buffer_manager_, surface_handle));
buffer_queue_->Initialize();
}
diff --git a/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h b/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h
index 439c8553ab1..a457be1d4af 100644
--- a/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h
+++ b/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h
@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_COMPOSITOR_GPU_SURFACELESS_BROWSER_COMPOSITOR_OUTPUT_SURFACE_H_
#include <memory>
+#include <vector>
#include "content/browser/compositor/gpu_browser_compositor_output_surface.h"
#include "gpu/ipc/common/surface_handle.h"
@@ -16,7 +17,6 @@ class GpuMemoryBufferManager;
namespace viz {
class BufferQueue;
-class GLHelper;
}
namespace content {
@@ -25,7 +25,7 @@ class GpuSurfacelessBrowserCompositorOutputSurface
: public GpuBrowserCompositorOutputSurface {
public:
GpuSurfacelessBrowserCompositorOutputSurface(
- scoped_refptr<ui::ContextProviderCommandBuffer> context,
+ scoped_refptr<ws::ContextProviderCommandBuffer> context,
gpu::SurfaceHandle surface_handle,
const UpdateVSyncParametersCallback& update_vsync_parameters_callback,
std::unique_ptr<viz::CompositorOverlayCandidateValidator>
@@ -61,7 +61,6 @@ class GpuSurfacelessBrowserCompositorOutputSurface
bool use_gpu_fence_;
unsigned gpu_fence_id_;
- std::unique_ptr<viz::GLHelper> gl_helper_;
std::unique_ptr<viz::BufferQueue> buffer_queue_;
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
};
diff --git a/chromium/content/browser/compositor/image_transport_factory.h b/chromium/content/browser/compositor/image_transport_factory.h
index 9dba97fe029..2d093e64347 100644
--- a/chromium/content/browser/compositor/image_transport_factory.h
+++ b/chromium/content/browser/compositor/image_transport_factory.h
@@ -15,10 +15,6 @@ class ContextFactory;
class ContextFactoryPrivate;
}
-namespace viz {
-class GLHelper;
-}
-
namespace content {
// This class provides the interface for creating the support for the
@@ -54,11 +50,6 @@ class CONTENT_EXPORT ImageTransportFactory {
// compositor. TODO(fsamuel): This interface should eventually go away once
// Mus subsumes this functionality.
virtual ui::ContextFactoryPrivate* GetContextFactoryPrivate() = 0;
-
- // Gets a GLHelper instance, associated with the shared context. This
- // GLHelper will get destroyed whenever the shared context is lost
- // (ImageTransportFactoryObserver::OnLostResources is called).
- virtual viz::GLHelper* GetGLHelper() = 0;
};
} // namespace content
diff --git a/chromium/content/browser/compositor/image_transport_factory_browsertest.cc b/chromium/content/browser/compositor/image_transport_factory_browsertest.cc
index 659533c687d..95f86bfa8c9 100644
--- a/chromium/content/browser/compositor/image_transport_factory_browsertest.cc
+++ b/chromium/content/browser/compositor/image_transport_factory_browsertest.cc
@@ -6,9 +6,7 @@
#include "base/run_loop.h"
#include "build/build_config.h"
-#include "components/viz/common/features.h"
#include "components/viz/common/gpu/context_provider.h"
-#include "content/browser/compositor/owned_mailbox.h"
#include "content/public/test/content_browser_test.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/gles2_interface.h"
@@ -63,41 +61,5 @@ IN_PROC_BROWSER_TEST_F(ImageTransportFactoryBrowserTest,
factory->GetContextFactory()->RemoveObserver(&observer);
}
-class ImageTransportFactoryTearDownBrowserTest : public ContentBrowserTest {
- public:
- void TearDown() override {
- // Mailbox is null if the test exited early.
- if (mailbox_.get())
- EXPECT_TRUE(mailbox_->mailbox().IsZero());
- ContentBrowserTest::TearDown();
- }
-
- protected:
- scoped_refptr<OwnedMailbox> mailbox_;
-};
-
-// Checks that upon destruction of the ImageTransportFactory, the observer is
-// called and the created resources are reset.
-IN_PROC_BROWSER_TEST_F(ImageTransportFactoryTearDownBrowserTest,
- LoseOnTearDown) {
- ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
-
- // TODO(crbug.com/844469): Delete after OOP-D is launched because GLHelper
- // and OwnedMailbox aren't used.
- if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor))
- return;
-
- // This test doesn't make sense in software compositing mode.
- if (factory->IsGpuCompositingDisabled())
- return;
-
- viz::GLHelper* helper = factory->GetGLHelper();
- ASSERT_TRUE(helper);
- mailbox_ = base::MakeRefCounted<OwnedMailbox>(helper);
- EXPECT_FALSE(mailbox_->mailbox().IsZero());
-
- // See TearDown() for the test expectation that |mailbox_| has been reset.
-}
-
} // anonymous namespace
} // namespace content
diff --git a/chromium/content/browser/compositor/offscreen_browser_compositor_output_surface.cc b/chromium/content/browser/compositor/offscreen_browser_compositor_output_surface.cc
index 3b3dc6943a6..b5f5874e8fa 100644
--- a/chromium/content/browser/compositor/offscreen_browser_compositor_output_surface.cc
+++ b/chromium/content/browser/compositor/offscreen_browser_compositor_output_surface.cc
@@ -18,7 +18,7 @@
#include "content/public/browser/browser_thread.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
-#include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
+#include "services/ws/public/cpp/gpu/context_provider_command_buffer.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
@@ -30,7 +30,7 @@ static viz::ResourceFormat kFboTextureFormat = viz::RGBA_8888;
OffscreenBrowserCompositorOutputSurface::
OffscreenBrowserCompositorOutputSurface(
- scoped_refptr<ui::ContextProviderCommandBuffer> context,
+ scoped_refptr<ws::ContextProviderCommandBuffer> context,
const UpdateVSyncParametersCallback& update_vsync_parameters_callback,
std::unique_ptr<viz::CompositorOverlayCandidateValidator>
overlay_candidate_validator)
diff --git a/chromium/content/browser/compositor/offscreen_browser_compositor_output_surface.h b/chromium/content/browser/compositor/offscreen_browser_compositor_output_surface.h
index f123692aebb..582388dd576 100644
--- a/chromium/content/browser/compositor/offscreen_browser_compositor_output_surface.h
+++ b/chromium/content/browser/compositor/offscreen_browser_compositor_output_surface.h
@@ -18,7 +18,7 @@
#include "ui/latency/latency_info.h"
#include "ui/latency/latency_tracker.h"
-namespace ui {
+namespace ws {
class ContextProviderCommandBuffer;
}
@@ -29,7 +29,7 @@ class OffscreenBrowserCompositorOutputSurface
: public BrowserCompositorOutputSurface {
public:
OffscreenBrowserCompositorOutputSurface(
- scoped_refptr<ui::ContextProviderCommandBuffer> context,
+ scoped_refptr<ws::ContextProviderCommandBuffer> context,
const UpdateVSyncParametersCallback& update_vsync_parameters_callback,
std::unique_ptr<viz::CompositorOverlayCandidateValidator>
overlay_candidate_validator);
diff --git a/chromium/content/browser/compositor/owned_mailbox.cc b/chromium/content/browser/compositor/owned_mailbox.cc
index f1eddad0fbc..0969ecaad96 100644
--- a/chromium/content/browser/compositor/owned_mailbox.cc
+++ b/chromium/content/browser/compositor/owned_mailbox.cc
@@ -4,48 +4,47 @@
#include "content/browser/compositor/owned_mailbox.h"
-#include "base/logging.h"
-#include "components/viz/common/gl_helper.h"
-#include "content/browser/compositor/image_transport_factory.h"
+#include "base/bind.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
namespace content {
-OwnedMailbox::OwnedMailbox(viz::GLHelper* gl_helper)
- : texture_id_(0), gl_helper_(gl_helper) {
- texture_id_ = gl_helper_->CreateTexture();
- mailbox_holder_ = gl_helper_->ProduceMailboxHolderFromTexture(texture_id_);
- // The texture target is not exposed on this class, as GLHelper assumes
- // GL_TEXTURE_2D.
- DCHECK_EQ(mailbox_holder_.texture_target,
- static_cast<uint32_t>(GL_TEXTURE_2D));
- ImageTransportFactory::GetInstance()->GetContextFactory()->AddObserver(this);
+OwnedMailbox::OwnedMailbox(gpu::gles2::GLES2Interface* gl)
+ : gl_(gl), texture_id_(0), weak_ptr_factory_(this) {
+ DCHECK(gl_);
+
+ // Create the texture.
+ static_assert(sizeof(texture_id_) == sizeof(GLuint),
+ "need to adjust type of texture_id_ in its declaration");
+ gl_->GenTextures(1, &texture_id_);
+ gl_->BindTexture(GL_TEXTURE_2D, texture_id_);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ gl_->BindTexture(GL_TEXTURE_2D, 0);
+
+ // Initialize the MailboxHolder for the texture.
+ gl_->ProduceTextureDirectCHROMIUM(texture_id_, mailbox_holder_.mailbox.name);
+ gl_->GenSyncTokenCHROMIUM(mailbox_holder_.sync_token.GetData());
+ mailbox_holder_.texture_target = GL_TEXTURE_2D;
}
OwnedMailbox::~OwnedMailbox() {
- if (gl_helper_)
- Destroy();
+ gl_->WaitSyncTokenCHROMIUM(mailbox_holder_.sync_token.GetConstData());
+ gl_->DeleteTextures(1, &texture_id_);
}
-void OwnedMailbox::UpdateSyncToken(const gpu::SyncToken& sync_token) {
- if (sync_token.HasData())
- mailbox_holder_.sync_token = sync_token;
-}
-
-void OwnedMailbox::Destroy() {
- ImageTransportFactory::GetInstance()->GetContextFactory()->RemoveObserver(
- this);
- gl_helper_->WaitSyncToken(mailbox_holder_.sync_token);
- gl_helper_->DeleteTexture(texture_id_);
- texture_id_ = 0;
- mailbox_holder_ = gpu::MailboxHolder();
- gl_helper_ = nullptr;
+std::unique_ptr<viz::SingleReleaseCallback>
+OwnedMailbox::GetSingleReleaseCallback() {
+ return viz::SingleReleaseCallback::Create(base::BindOnce(
+ &OwnedMailbox::UpdateSyncToken, weak_ptr_factory_.GetWeakPtr()));
}
-void OwnedMailbox::OnLostSharedContext() {
- if (gl_helper_)
- Destroy();
+void OwnedMailbox::UpdateSyncToken(const gpu::SyncToken& sync_token,
+ bool is_lost) {
+ if (sync_token.HasData())
+ mailbox_holder_.sync_token = sync_token;
}
-void OwnedMailbox::OnLostVizProcess() {}
-
} // namespace content
diff --git a/chromium/content/browser/compositor/owned_mailbox.h b/chromium/content/browser/compositor/owned_mailbox.h
index 9880759f4c6..084e28f4653 100644
--- a/chromium/content/browser/compositor/owned_mailbox.h
+++ b/chromium/content/browser/compositor/owned_mailbox.h
@@ -7,26 +7,28 @@
#include <stdint.h>
+#include <memory>
+
#include "base/memory/ref_counted.h"
-#include "content/browser/compositor/image_transport_factory.h"
+#include "base/memory/weak_ptr.h"
+#include "components/viz/common/resources/single_release_callback.h"
#include "content/common/content_export.h"
#include "gpu/command_buffer/common/mailbox_holder.h"
#include "ui/compositor/compositor.h"
-namespace viz {
-class GLHelper;
+namespace gpu {
+namespace gles2 {
+class GLES2Interface;
+}
}
namespace content {
-
// This class holds a texture id and gpu::Mailbox, and deletes the texture
-// id when the object itself is destroyed. Should only be created if a GLHelper
-// exists on the ImageTransportFactory.
-class CONTENT_EXPORT OwnedMailbox : public base::RefCounted<OwnedMailbox>,
- public ui::ContextFactoryObserver {
+// id when the object itself is destroyed.
+class CONTENT_EXPORT OwnedMailbox : public base::RefCounted<OwnedMailbox> {
public:
- explicit OwnedMailbox(viz::GLHelper* gl_helper);
+ explicit OwnedMailbox(gpu::gles2::GLES2Interface* gl);
const gpu::MailboxHolder& holder() const { return mailbox_holder_; }
const gpu::Mailbox& mailbox() const { return mailbox_holder_.mailbox; }
@@ -34,22 +36,21 @@ class CONTENT_EXPORT OwnedMailbox : public base::RefCounted<OwnedMailbox>,
return mailbox_holder_.sync_token;
}
uint32_t texture_id() const { return texture_id_; }
- void UpdateSyncToken(const gpu::SyncToken& sync_token);
- void Destroy();
- protected:
- ~OwnedMailbox() override;
-
- // ImageTransportFactoryObserver implementation.
- void OnLostSharedContext() override;
- void OnLostVizProcess() override;
+ // Returns a SingleReleaseCallback for TextureLayer.
+ std::unique_ptr<viz::SingleReleaseCallback> GetSingleReleaseCallback();
private:
friend class base::RefCounted<OwnedMailbox>;
+ ~OwnedMailbox();
+
+ void UpdateSyncToken(const gpu::SyncToken& sync_token, bool is_lost);
+
+ gpu::gles2::GLES2Interface* const gl_;
uint32_t texture_id_;
gpu::MailboxHolder mailbox_holder_;
- viz::GLHelper* gl_helper_;
+ base::WeakPtrFactory<OwnedMailbox> weak_ptr_factory_;
};
} // namespace content
diff --git a/chromium/content/browser/compositor/reflector_impl.cc b/chromium/content/browser/compositor/reflector_impl.cc
index a0a54c0d450..b41cb5b429a 100644
--- a/chromium/content/browser/compositor/reflector_impl.cc
+++ b/chromium/content/browser/compositor/reflector_impl.cc
@@ -4,7 +4,6 @@
#include "content/browser/compositor/reflector_impl.h"
-#include "base/bind.h"
#include "base/location.h"
#include "components/viz/common/resources/transferable_resource.h"
#include "content/browser/compositor/browser_compositor_output_surface.h"
@@ -30,8 +29,7 @@ ReflectorImpl::ReflectorImpl(ui::Compositor* mirrored_compositor,
AddMirroringLayer(mirroring_layer);
}
-ReflectorImpl::~ReflectorImpl() {
-}
+ReflectorImpl::~ReflectorImpl() = default;
void ReflectorImpl::Shutdown() {
if (output_surface_)
@@ -43,8 +41,8 @@ void ReflectorImpl::Shutdown() {
void ReflectorImpl::DetachFromOutputSurface() {
DCHECK(output_surface_);
output_surface_->SetReflector(nullptr);
- DCHECK(mailbox_.get());
- mailbox_ = nullptr;
+ DCHECK(mailbox_);
+ mailbox_.reset();
output_surface_ = nullptr;
for (const auto& layer_data : mirroring_layers_)
layer_data->layer->SetShowSolidColorContent();
@@ -140,12 +138,6 @@ void ReflectorImpl::OnSourcePostSubBuffer(const gfx::Rect& swap_rect,
UpdateTexture(layer_data.get(), surface_size, mirroring_rect);
}
-static void ReleaseMailbox(scoped_refptr<OwnedMailbox> mailbox,
- const gpu::SyncToken& sync_token,
- bool is_lost) {
- mailbox->UpdateSyncToken(sync_token);
-}
-
std::vector<std::unique_ptr<ReflectorImpl::LayerData>>::iterator
ReflectorImpl::FindLayerData(ui::Layer* layer) {
return std::find_if(mirroring_layers_.begin(), mirroring_layers_.end(),
@@ -162,9 +154,7 @@ void ReflectorImpl::UpdateTexture(ReflectorImpl::LayerData* layer_data,
viz::TransferableResource::MakeGL(mailbox_->holder().mailbox, GL_LINEAR,
mailbox_->holder().texture_target,
mailbox_->holder().sync_token),
- viz::SingleReleaseCallback::Create(
- base::BindOnce(ReleaseMailbox, mailbox_)),
- source_size);
+ mailbox_->GetSingleReleaseCallback(), source_size);
layer_data->needs_set_mailbox = false;
} else {
layer_data->layer->SetTextureSize(source_size);
diff --git a/chromium/content/browser/compositor/reflector_impl_unittest.cc b/chromium/content/browser/compositor/reflector_impl_unittest.cc
index fd673e054bd..40a83a865a1 100644
--- a/chromium/content/browser/compositor/reflector_impl_unittest.cc
+++ b/chromium/content/browser/compositor/reflector_impl_unittest.cc
@@ -5,10 +5,12 @@
#include "content/browser/compositor/reflector_impl.h"
#include "base/callback.h"
+#include "base/feature_list.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "build/build_config.h"
+#include "components/viz/common/features.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/frame_sinks/delay_based_time_source.h"
#include "components/viz/service/display/output_surface_frame.h"
@@ -202,6 +204,10 @@ class ReflectorImplTest : public testing::Test {
namespace {
TEST_F(ReflectorImplTest, CheckNormalOutputSurface) {
+ // TODO(jonross): Re-enable once Reflector is re-written to work with
+ // VizDisplayCompositor. https://crbug.com/601869
+ if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor))
+ return;
output_surface_->SetFlip(false);
SetUpReflector();
UpdateTexture();
@@ -212,6 +218,10 @@ TEST_F(ReflectorImplTest, CheckNormalOutputSurface) {
}
TEST_F(ReflectorImplTest, CheckInvertedOutputSurface) {
+ // TODO(jonross): Re-enable once Reflector is re-written to work with
+ // VizDisplayCompositor. https://crbug.com/601869
+ if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor))
+ return;
output_surface_->SetFlip(true);
SetUpReflector();
UpdateTexture();
@@ -221,6 +231,10 @@ TEST_F(ReflectorImplTest, CheckInvertedOutputSurface) {
#if defined(USE_OZONE)
TEST_F(ReflectorImplTest, CheckOverlayNoReflector) {
+ // TODO(jonross): Re-enable once Reflector is re-written to work with
+ // VizDisplayCompositor. https://crbug.com/601869
+ if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor))
+ return;
viz::OverlayCandidateList list;
viz::OverlayCandidate plane_1, plane_2;
plane_1.plane_z_order = 0;
@@ -232,6 +246,10 @@ TEST_F(ReflectorImplTest, CheckOverlayNoReflector) {
}
TEST_F(ReflectorImplTest, CheckOverlaySWMirroring) {
+ // TODO(jonross): Re-enable once Reflector is re-written to work with
+ // VizDisplayCompositor. https://crbug.com/601869
+ if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor))
+ return;
SetUpReflector();
viz::OverlayCandidateList list;
viz::OverlayCandidate plane_1, plane_2;
diff --git a/chromium/content/browser/compositor/reflector_texture.cc b/chromium/content/browser/compositor/reflector_texture.cc
index 35dcfffbb68..cc6de8be58d 100644
--- a/chromium/content/browser/compositor/reflector_texture.cc
+++ b/chromium/content/browser/compositor/reflector_texture.cc
@@ -4,45 +4,51 @@
#include "content/browser/compositor/reflector_texture.h"
-#include "components/viz/common/gl_helper.h"
#include "content/browser/compositor/owned_mailbox.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
-#include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
+#include "services/ws/public/cpp/gpu/context_provider_command_buffer.h"
namespace content {
ReflectorTexture::ReflectorTexture(viz::ContextProvider* context_provider)
- : texture_id_(0) {
- viz::GLHelper* shared_helper =
- ImageTransportFactory::GetInstance()->GetGLHelper();
- mailbox_ = new OwnedMailbox(shared_helper);
- gpu::gles2::GLES2Interface* gl = context_provider->ContextGL();
-
- gl_helper_.reset(new viz::GLHelper(gl, context_provider->ContextSupport()));
-
- texture_id_ = gl_helper_->ConsumeMailboxToTexture(mailbox_->mailbox(),
- mailbox_->sync_token());
+ : gl_(context_provider->ContextGL()), texture_id_(0) {
+ mailbox_ = new OwnedMailbox(gl_);
+
+ if (!mailbox_->mailbox().IsZero()) {
+ if (mailbox_->sync_token().HasData())
+ gl_->WaitSyncTokenCHROMIUM(mailbox_->sync_token().GetConstData());
+ texture_id_ =
+ gl_->CreateAndConsumeTextureCHROMIUM(mailbox_->mailbox().name);
+ }
}
ReflectorTexture::~ReflectorTexture() {
- gl_helper_->DeleteTexture(texture_id_);
+ if (texture_id_ != 0)
+ gl_->DeleteTextures(1, &texture_id_);
}
void ReflectorTexture::CopyTextureFullImage(const gfx::Size& size) {
- gl_helper_->CopyTextureFullImage(texture_id_, size);
+ gl_->BindTexture(GL_TEXTURE_2D, texture_id_);
+ gl_->CopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, size.width(),
+ size.height(), 0);
+ gl_->BindTexture(GL_TEXTURE_2D, 0);
+
// Insert a barrier to make the copy show up in the mirroring compositor's
- // mailbox. Since the the compositor contexts and the
- // ImageTransportFactory's
- // GLHelper are all on the same GPU channel, this is sufficient instead of
+ // mailbox. Since the the compositor contexts and the ImageTransportFactory's
+ // GL context are all on the same GPU channel, this is sufficient instead of
// plumbing through a sync point.
- gl_helper_->InsertOrderingBarrier();
+ gl_->OrderingBarrierCHROMIUM();
}
void ReflectorTexture::CopyTextureSubImage(const gfx::Rect& rect) {
- gl_helper_->CopyTextureSubImage(texture_id_, rect);
+ gl_->BindTexture(GL_TEXTURE_2D, texture_id_);
+ gl_->CopyTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.x(),
+ rect.y(), rect.width(), rect.height());
+ gl_->BindTexture(GL_TEXTURE_2D, 0);
+
// Insert a barrier for the same reason above.
- gl_helper_->InsertOrderingBarrier();
+ gl_->OrderingBarrierCHROMIUM();
}
} // namespace content
diff --git a/chromium/content/browser/compositor/reflector_texture.h b/chromium/content/browser/compositor/reflector_texture.h
index d5531a362b3..ae1a3d7f08c 100644
--- a/chromium/content/browser/compositor/reflector_texture.h
+++ b/chromium/content/browser/compositor/reflector_texture.h
@@ -19,9 +19,14 @@ class Rect;
class Size;
}
+namespace gpu {
+namespace gles2 {
+class GLES2Interface;
+}
+} // namespace gpu
+
namespace viz {
class ContextProvider;
-class GLHelper;
}
namespace content {
@@ -39,8 +44,8 @@ class CONTENT_EXPORT ReflectorTexture {
scoped_refptr<OwnedMailbox> mailbox() { return mailbox_; }
private:
+ gpu::gles2::GLES2Interface* const gl_;
scoped_refptr<OwnedMailbox> mailbox_;
- std::unique_ptr<viz::GLHelper> gl_helper_;
uint32_t texture_id_;
DISALLOW_COPY_AND_ASSIGN(ReflectorTexture);
@@ -48,4 +53,4 @@ class CONTENT_EXPORT ReflectorTexture {
} // namespace content
-#endif
+#endif // CONTENT_BROWSER_COMPOSITOR_REFLECTOR_TEXTURE_H_
diff --git a/chromium/content/browser/compositor/viz_process_transport_factory.cc b/chromium/content/browser/compositor/viz_process_transport_factory.cc
index af692aeb080..07fe6eeaf90 100644
--- a/chromium/content/browser/compositor/viz_process_transport_factory.cc
+++ b/chromium/content/browser/compositor/viz_process_transport_factory.cc
@@ -17,6 +17,7 @@
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/common/gpu/raster_context_provider.h"
#include "components/viz/common/switches.h"
+#include "components/viz/host/gpu_host_impl.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "components/viz/service/display_embedder/compositing_mode_reporter_impl.h"
#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
@@ -31,7 +32,7 @@
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/client/raster_interface.h"
#include "gpu/ipc/client/gpu_channel_host.h"
-#include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
+#include "services/ws/public/cpp/gpu/context_provider_command_buffer.h"
#include "ui/base/ui_base_features.h"
#include "ui/compositor/reflector.h"
@@ -46,14 +47,14 @@ namespace {
// child process client id.
constexpr uint32_t kBrowserClientId = 0u;
-scoped_refptr<ui::ContextProviderCommandBuffer> CreateContextProviderImpl(
+scoped_refptr<ws::ContextProviderCommandBuffer> CreateContextProviderImpl(
scoped_refptr<gpu::GpuChannelHost> gpu_channel_host,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
bool support_locking,
bool support_gles2_interface,
bool support_raster_interface,
bool support_grcontext,
- ui::command_buffer_metrics::ContextType type) {
+ ws::command_buffer_metrics::ContextType type) {
constexpr bool kAutomaticFlushes = false;
gpu::ContextCreationAttribs attributes;
@@ -69,7 +70,7 @@ scoped_refptr<ui::ContextProviderCommandBuffer> CreateContextProviderImpl(
attributes.enable_raster_interface = support_raster_interface;
GURL url("chrome://gpu/VizProcessTransportFactory::CreateContextProvider");
- return base::MakeRefCounted<ui::ContextProviderCommandBuffer>(
+ return base::MakeRefCounted<ws::ContextProviderCommandBuffer>(
std::move(gpu_channel_host), gpu_memory_buffer_manager,
kGpuStreamIdDefault, kGpuStreamPriorityUI, gpu::kNullSurfaceHandle,
std::move(url), kAutomaticFlushes, support_locking, support_grcontext,
@@ -165,8 +166,8 @@ void VizProcessTransportFactory::ConnectHostFrameSinkManager() {
// return null.
auto* gpu_process_host = GpuProcessHost::Get();
if (gpu_process_host) {
- gpu_process_host->ConnectFrameSinkManager(std::move(request),
- std::move(client));
+ gpu_process_host->gpu_host()->ConnectFrameSinkManager(
+ std::move(request), std::move(client));
}
};
BrowserThread::PostTask(
@@ -285,12 +286,9 @@ VizProcessTransportFactory::GetContextFactoryPrivate() {
return this;
}
-viz::GLHelper* VizProcessTransportFactory::GetGLHelper() {
- NOTREACHED(); // Readback happens in the GPU process and this isn't used.
- return nullptr;
-}
-
void VizProcessTransportFactory::OnContextLost() {
+ // PostTask to avoid destroying |main_context_provider_| while it's still
+ // informing observers about the context loss.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&VizProcessTransportFactory::OnLostMainThreadSharedContext,
@@ -306,19 +304,18 @@ void VizProcessTransportFactory::DisableGpuCompositing(
compositing_mode_reporter_->SetUsingSoftwareCompositing();
- // Consumers of the shared main thread context aren't CompositingModeWatchers,
- // so inform them about the compositing mode switch by acting like the context
- // was lost. This also destroys the contexts since they aren't created when
- // gpu compositing isn't being used.
- OnLostMainThreadSharedContext();
-
// Drop our reference on the gpu contexts for the compositors.
- worker_context_provider_ = nullptr;
+ worker_context_provider_.reset();
if (main_context_provider_) {
main_context_provider_->RemoveObserver(this);
- main_context_provider_ = nullptr;
+ main_context_provider_.reset();
}
+ // Consumers of the shared main thread context aren't CompositingModeWatchers,
+ // so inform them about the context loss due to switching to software
+ // compositing.
+ OnLostMainThreadSharedContext();
+
// Reemove the FrameSink from every compositor that needs to fall back to
// software compositing.
for (ui::Compositor* compositor : GetAllCompositors()) {
@@ -405,7 +402,7 @@ VizProcessTransportFactory::TryCreateContextsForGpuCompositing(
if (worker_context_provider_ &&
IsWorkerContextLost(worker_context_provider_.get()))
- worker_context_provider_ = nullptr;
+ worker_context_provider_.reset();
if (!worker_context_provider_) {
constexpr bool kSharedWorkerContextSupportsLocking = true;
@@ -420,21 +417,21 @@ VizProcessTransportFactory::TryCreateContextsForGpuCompositing(
kSharedWorkerContextSupportsLocking, kSharedWorkerContextSupportsGLES2,
kSharedWorkerContextSupportsRaster,
kSharedWorkerContextSupportsGrContext,
- ui::command_buffer_metrics::ContextType::BROWSER_WORKER);
+ ws::command_buffer_metrics::ContextType::BROWSER_WORKER);
// Don't observer context loss on |worker_context_provider_| here, that is
// already observered by LayerTreeFrameSink. The lost context will be caught
// when recreating LayerTreeFrameSink(s).
auto context_result = worker_context_provider_->BindToCurrentThread();
if (context_result != gpu::ContextResult::kSuccess) {
- worker_context_provider_ = nullptr;
+ worker_context_provider_.reset();
return context_result;
}
}
if (main_context_provider_ && IsContextLost(main_context_provider_.get())) {
main_context_provider_->RemoveObserver(this);
- main_context_provider_ = nullptr;
+ main_context_provider_.reset();
}
if (!main_context_provider_) {
@@ -447,13 +444,12 @@ VizProcessTransportFactory::TryCreateContextsForGpuCompositing(
std::move(gpu_channel_host), GetGpuMemoryBufferManager(),
kCompositorContextSupportsLocking, kCompositorContextSupportsGLES2,
kCompositorContextSupportsRaster, kCompositorContextSupportsGrContext,
- ui::command_buffer_metrics::ContextType::BROWSER_MAIN_THREAD);
+ ws::command_buffer_metrics::ContextType::BROWSER_MAIN_THREAD);
main_context_provider_->SetDefaultTaskRunner(resize_task_runner());
auto context_result = main_context_provider_->BindToCurrentThread();
if (context_result != gpu::ContextResult::kSuccess) {
- worker_context_provider_ = nullptr;
- main_context_provider_ = nullptr;
+ main_context_provider_.reset();
return context_result;
}
@@ -468,7 +464,7 @@ void VizProcessTransportFactory::OnLostMainThreadSharedContext() {
// OnEstablishedGpuChannel(), so check if it's lost before resetting here.
if (main_context_provider_ && IsContextLost(main_context_provider_.get())) {
main_context_provider_->RemoveObserver(this);
- main_context_provider_ = nullptr;
+ main_context_provider_.reset();
}
for (auto& observer : observer_list_)
diff --git a/chromium/content/browser/compositor/viz_process_transport_factory.h b/chromium/content/browser/compositor/viz_process_transport_factory.h
index 731a309d53a..41619afe58d 100644
--- a/chromium/content/browser/compositor/viz_process_transport_factory.h
+++ b/chromium/content/browser/compositor/viz_process_transport_factory.h
@@ -31,15 +31,15 @@ namespace gpu {
class GpuChannelEstablishFactory;
}
-namespace ui {
-class ContextProviderCommandBuffer;
-}
-
namespace viz {
class CompositingModeReporterImpl;
class RasterContextProvider;
}
+namespace ws {
+class ContextProviderCommandBuffer;
+}
+
namespace content {
// A replacement for GpuProcessTransportFactory to be used when running viz. In
@@ -78,7 +78,6 @@ class VizProcessTransportFactory : public ui::ContextFactory,
bool IsGpuCompositingDisabled() override;
ui::ContextFactory* GetContextFactory() override;
ui::ContextFactoryPrivate* GetContextFactoryPrivate() override;
- viz::GLHelper* GetGLHelper() override;
// viz::ContextLostObserver implementation.
void OnContextLost() override;
@@ -118,14 +117,14 @@ class VizProcessTransportFactory : public ui::ContextFactory,
// are using.
viz::CompositingModeReporterImpl* const compositing_mode_reporter_;
- base::ObserverList<ui::ContextFactoryObserver> observer_list_;
+ base::ObserverList<ui::ContextFactoryObserver>::Unchecked observer_list_;
// ContextProvider used on worker threads for rasterization.
scoped_refptr<viz::RasterContextProvider> worker_context_provider_;
// ContextProvider used on the main thread. Shared by ui::Compositors and also
// returned from GetSharedMainThreadContextProvider().
- scoped_refptr<ui::ContextProviderCommandBuffer> main_context_provider_;
+ scoped_refptr<ws::ContextProviderCommandBuffer> main_context_provider_;
std::unique_ptr<cc::SingleThreadTaskGraphRunner> task_graph_runner_;
diff --git a/chromium/content/browser/compositor/vulkan_browser_compositor_output_surface.cc b/chromium/content/browser/compositor/vulkan_browser_compositor_output_surface.cc
index 8637358c8e2..7d4b39a2e2f 100644
--- a/chromium/content/browser/compositor/vulkan_browser_compositor_output_surface.cc
+++ b/chromium/content/browser/compositor/vulkan_browser_compositor_output_surface.cc
@@ -86,7 +86,7 @@ void VulkanBrowserCompositorOutputSurface::Reshape(
const gfx::ColorSpace& color_space,
bool has_alpha,
bool use_stencil) {
- NOTIMPLEMENTED();
+ surface_->SetSize(size);
}
void VulkanBrowserCompositorOutputSurface::SetDrawRectangle(
diff --git a/chromium/content/browser/cross_site_transfer_browsertest.cc b/chromium/content/browser/cross_site_transfer_browsertest.cc
index bc1b974fb45..28626c314a7 100644
--- a/chromium/content/browser/cross_site_transfer_browsertest.cc
+++ b/chromium/content/browser/cross_site_transfer_browsertest.cc
@@ -288,7 +288,7 @@ IN_PROC_BROWSER_TEST_F(CrossSiteTransferTest, PostWithFileData) {
EXPECT_TRUE(NavigateToURL(shell(), form_url));
// Prepare a file to upload.
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_temp_dir;
+ base::ScopedAllowBlockingForTesting allow_blocking;
base::ScopedTempDir temp_dir;
base::FilePath file_path;
std::string file_content("test-file-content");
@@ -381,7 +381,7 @@ IN_PROC_BROWSER_TEST_F(CrossSiteTransferTest, MaliciousPostWithFileData) {
form_contents->GetMainFrame()->GetProcess()->GetID());
// Prepare a file to upload.
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_temp_dir;
+ base::ScopedAllowBlockingForTesting allow_blocking;
base::ScopedTempDir temp_dir;
base::FilePath file_path;
std::string file_content("test-file-content");
@@ -472,24 +472,4 @@ IN_PROC_BROWSER_TEST_F(CrossSiteTransferTest, NoDeliveryToDetachedFrame) {
<< "Request should have been cancelled before reaching the renderer.";
}
-// Ensure that we don't send a referrer if a site tries to trigger the forking
-// heuristic, even if we would have forked anyways.
-IN_PROC_BROWSER_TEST_F(CrossSiteTransferTest, NoReferrerOnFork) {
- base::CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kContentShellAlwaysFork);
-
- GURL start_url(embedded_test_server()->GetURL("a.com", "/fork-popup.html"));
- EXPECT_TRUE(NavigateToURL(shell(), start_url));
- EXPECT_EQ(2u, shell()->windows().size());
- Shell* popup = shell()->windows().back();
- EXPECT_NE(popup, shell());
-
- base::string16 expected_title = base::ASCIIToUTF16("Referrer = ''");
- base::string16 failed_title = base::ASCIIToUTF16(
- base::StringPrintf("Referrer = '%s'", start_url.spec().c_str()));
- TitleWatcher watcher(popup->web_contents(), expected_title);
- watcher.AlsoWaitForTitle(failed_title);
- EXPECT_EQ(expected_title, watcher.WaitAndGetTitle());
-}
-
} // namespace content
diff --git a/chromium/content/browser/dedicated_worker/dedicated_worker_host.cc b/chromium/content/browser/dedicated_worker/dedicated_worker_host.cc
index 7eccbe6db70..9c9271b5631 100644
--- a/chromium/content/browser/dedicated_worker/dedicated_worker_host.cc
+++ b/chromium/content/browser/dedicated_worker/dedicated_worker_host.cc
@@ -17,6 +17,7 @@
#include "mojo/public/cpp/system/message_pipe.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/mojom/interface_provider.mojom.h"
+#include "third_party/blink/public/mojom/usb/web_usb_service.mojom.h"
#include "url/origin.h"
namespace content {
@@ -57,16 +58,16 @@ class DedicatedWorkerHost : public service_manager::mojom::InterfaceProvider {
registry_.AddInterface(base::BindRepeating(
&DedicatedWorkerHost::CreateWebSocket, base::Unretained(this)));
registry_.AddInterface(base::BindRepeating(
- &DedicatedWorkerHost::CreateUsbDeviceManager, base::Unretained(this)));
+ &DedicatedWorkerHost::CreateWebUsbService, base::Unretained(this)));
registry_.AddInterface(base::BindRepeating(
&DedicatedWorkerHost::CreateDedicatedWorker, base::Unretained(this)));
}
- void CreateUsbDeviceManager(device::mojom::UsbDeviceManagerRequest request) {
+ void CreateWebUsbService(blink::mojom::WebUsbServiceRequest request) {
auto* host =
RenderFrameHostImpl::FromID(process_id_, ancestor_render_frame_id_);
- GetContentClient()->browser()->CreateUsbDeviceManager(host,
- std::move(request));
+ GetContentClient()->browser()->CreateWebUsbService(host,
+ std::move(request));
}
void CreateWebSocket(network::mojom::WebSocketRequest request) {
diff --git a/chromium/content/browser/devtools/DEPS b/chromium/content/browser/devtools/DEPS
index 28ece8ad732..93bf7150a33 100644
--- a/chromium/content/browser/devtools/DEPS
+++ b/chromium/content/browser/devtools/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+third_party/brotli", # For compressed protocol.json.
+ "+content/shell/browser/shell.h", # for access to web contents from devtools_protocol_test_support.cc
# V8 version info
"+v8/include/v8-version-string.h",
]
diff --git a/chromium/content/browser/devtools/browser_devtools_agent_host.cc b/chromium/content/browser/devtools/browser_devtools_agent_host.cc
index 5bdec4f820f..a83315a158b 100644
--- a/chromium/content/browser/devtools/browser_devtools_agent_host.cc
+++ b/chromium/content/browser/devtools/browser_devtools_agent_host.cc
@@ -111,14 +111,15 @@ void BrowserDevToolsAgentHost::Reload() {
bool BrowserDevToolsAgentHost::DispatchProtocolMessage(
DevToolsAgentHostClient* client,
const std::string& message,
- base::DictionaryValue* parsed_message) {
+ std::unique_ptr<base::DictionaryValue> parsed_message) {
auto it = target_registries_.find(client);
if (it != target_registries_.end() &&
- it->second->DispatchMessageOnAgentHost(message, parsed_message)) {
+ it->second->CanDispatchMessageOnAgentHost(parsed_message.get())) {
+ it->second->DispatchMessageOnAgentHost(message, std::move(parsed_message));
return true;
}
- return DevToolsAgentHostImpl::DispatchProtocolMessage(client, message,
- parsed_message);
+ return DevToolsAgentHostImpl::DispatchProtocolMessage(
+ client, message, std::move(parsed_message));
}
} // content
diff --git a/chromium/content/browser/devtools/browser_devtools_agent_host.h b/chromium/content/browser/devtools/browser_devtools_agent_host.h
index 29963484035..0bdd0bc36f1 100644
--- a/chromium/content/browser/devtools/browser_devtools_agent_host.h
+++ b/chromium/content/browser/devtools/browser_devtools_agent_host.h
@@ -25,9 +25,10 @@ class BrowserDevToolsAgentHost : public DevToolsAgentHostImpl {
bool AttachSession(DevToolsSession* session,
TargetRegistry* registry) override;
void DetachSession(DevToolsSession* session) override;
- bool DispatchProtocolMessage(DevToolsAgentHostClient* client,
- const std::string& message,
- base::DictionaryValue* parsed_message) override;
+ bool DispatchProtocolMessage(
+ DevToolsAgentHostClient* client,
+ const std::string& message,
+ std::unique_ptr<base::DictionaryValue> parsed_message) override;
// DevToolsAgentHost implementation.
std::string GetType() override;
diff --git a/chromium/content/browser/devtools/devtools_agent_host_impl.cc b/chromium/content/browser/devtools/devtools_agent_host_impl.cc
index 273ca40034c..d32bd45d916 100644
--- a/chromium/content/browser/devtools/devtools_agent_host_impl.cc
+++ b/chromium/content/browser/devtools/devtools_agent_host_impl.cc
@@ -35,8 +35,8 @@ typedef std::map<std::string, DevToolsAgentHostImpl*> DevToolsMap;
base::LazyInstance<DevToolsMap>::Leaky g_devtools_instances =
LAZY_INSTANCE_INITIALIZER;
-base::LazyInstance<base::ObserverList<DevToolsAgentHostObserver>>::Leaky
- g_devtools_observers = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<base::ObserverList<DevToolsAgentHostObserver>::Unchecked>::
+ Leaky g_devtools_observers = LAZY_INSTANCE_INITIALIZER;
// Returns a list of all active hosts on browser targets.
DevToolsAgentHost::List GetBrowserAgentHosts() {
@@ -231,20 +231,18 @@ bool DevToolsAgentHostImpl::DispatchProtocolMessage(
DevToolsAgentHostClient* client,
const std::string& message) {
std::unique_ptr<base::Value> value = base::JSONReader::Read(message);
- if (value && !value->is_dict())
- value.reset();
- return DispatchProtocolMessage(
- client, message, static_cast<base::DictionaryValue*>(value.get()));
+ return DispatchProtocolMessage(client, message,
+ base::DictionaryValue::From(std::move(value)));
}
bool DevToolsAgentHostImpl::DispatchProtocolMessage(
DevToolsAgentHostClient* client,
const std::string& message,
- base::DictionaryValue* parsed_message) {
+ std::unique_ptr<base::DictionaryValue> parsed_message) {
DevToolsSession* session = SessionByClient(client);
if (!session)
return false;
- session->DispatchProtocolMessage(message, parsed_message);
+ session->DispatchProtocolMessage(message, std::move(parsed_message));
return true;
}
diff --git a/chromium/content/browser/devtools/devtools_agent_host_impl.h b/chromium/content/browser/devtools/devtools_agent_host_impl.h
index b258f840c9b..0910548167e 100644
--- a/chromium/content/browser/devtools/devtools_agent_host_impl.h
+++ b/chromium/content/browser/devtools/devtools_agent_host_impl.h
@@ -70,9 +70,10 @@ class CONTENT_EXPORT DevToolsAgentHostImpl : public DevToolsAgentHost {
TargetRegistry* registry);
virtual void DetachSession(DevToolsSession* session);
- virtual bool DispatchProtocolMessage(DevToolsAgentHostClient* client,
- const std::string& message,
- base::DictionaryValue* parsed_message);
+ virtual bool DispatchProtocolMessage(
+ DevToolsAgentHostClient* client,
+ const std::string& message,
+ std::unique_ptr<base::DictionaryValue> parsed_message);
void NotifyCreated();
void NotifyNavigated();
diff --git a/chromium/content/browser/devtools/devtools_frame_trace_recorder.cc b/chromium/content/browser/devtools/devtools_frame_trace_recorder.cc
index 9f8da6cf237..4c8f6b249c3 100644
--- a/chromium/content/browser/devtools/devtools_frame_trace_recorder.cc
+++ b/chromium/content/browser/devtools/devtools_frame_trace_recorder.cc
@@ -80,14 +80,6 @@ DevToolsFrameTraceRecorder::DevToolsFrameTraceRecorder() { }
DevToolsFrameTraceRecorder::~DevToolsFrameTraceRecorder() { }
-void DevToolsFrameTraceRecorder::OnSwapCompositorFrame(
- RenderFrameHostImpl* host,
- const viz::CompositorFrameMetadata& frame_metadata) {
- if (!host || !ScreenshotCategoryEnabled())
- return;
- CaptureFrame(host, frame_metadata);
-}
-
void DevToolsFrameTraceRecorder::OnSynchronousSwapCompositorFrame(
RenderFrameHostImpl* host,
const viz::CompositorFrameMetadata& frame_metadata) {
diff --git a/chromium/content/browser/devtools/devtools_frame_trace_recorder.h b/chromium/content/browser/devtools/devtools_frame_trace_recorder.h
index a80afc02a26..ed1d52f1152 100644
--- a/chromium/content/browser/devtools/devtools_frame_trace_recorder.h
+++ b/chromium/content/browser/devtools/devtools_frame_trace_recorder.h
@@ -24,10 +24,6 @@ class DevToolsFrameTraceRecorder {
DevToolsFrameTraceRecorder();
~DevToolsFrameTraceRecorder();
- void OnSwapCompositorFrame(
- RenderFrameHostImpl* host,
- const viz::CompositorFrameMetadata& frame_metadata);
-
void OnSynchronousSwapCompositorFrame(
RenderFrameHostImpl* host,
const viz::CompositorFrameMetadata& frame_metadata);
diff --git a/chromium/content/browser/devtools/devtools_http_handler.cc b/chromium/content/browser/devtools/devtools_http_handler.cc
index eaf44246e9e..a0ce6d621d8 100644
--- a/chromium/content/browser/devtools/devtools_http_handler.cc
+++ b/chromium/content/browser/devtools/devtools_http_handler.cc
@@ -22,7 +22,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/threading/thread.h"
#include "base/values.h"
#include "build/build_config.h"
@@ -222,7 +222,7 @@ void TerminateOnUI(std::unique_ptr<base::Thread> thread,
thread->task_runner()->DeleteSoon(FROM_HERE, std::move(socket_factory));
if (thread) {
base::PostTaskWithTraits(
- FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
BindOnce([](std::unique_ptr<base::Thread>) {}, std::move(thread)));
}
}
diff --git a/chromium/content/browser/devtools/devtools_http_handler_unittest.cc b/chromium/content/browser/devtools/devtools_http_handler_unittest.cc
index 3222803c84e..97ac6d57e1d 100644
--- a/chromium/content/browser/devtools/devtools_http_handler_unittest.cc
+++ b/chromium/content/browser/devtools/devtools_http_handler_unittest.cc
@@ -24,6 +24,7 @@
#include "content/public/browser/devtools_socket_factory.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_utils.h"
+#include "net/base/completion_once_callback.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
@@ -52,7 +53,7 @@ class DummyServerSocket : public net::ServerSocket {
}
int Accept(std::unique_ptr<net::StreamSocket>* socket,
- const net::CompletionCallback& callback) override {
+ net::CompletionOnceCallback callback) override {
return net::ERR_IO_PENDING;
}
};
diff --git a/chromium/content/browser/devtools/devtools_pipe_handler.cc b/chromium/content/browser/devtools/devtools_pipe_handler.cc
index dcdce1fe0ef..8552cf21711 100644
--- a/chromium/content/browser/devtools/devtools_pipe_handler.cc
+++ b/chromium/content/browser/devtools/devtools_pipe_handler.cc
@@ -20,7 +20,7 @@
#include "base/message_loop/message_loop.h"
#include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/threading/thread.h"
#include "build/build_config.h"
#include "content/public/browser/browser_thread.h"
@@ -209,7 +209,7 @@ void DevToolsPipeHandler::Shutdown() {
// If there is no write thread, only take care of the read thread.
if (!write_thread_) {
base::PostTaskWithTraits(
- FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
base::BindOnce([](base::Thread* rthread) { delete rthread; },
read_thread_.release()));
return;
@@ -236,7 +236,7 @@ void DevToolsPipeHandler::Shutdown() {
// Post background task that would join and destroy the threads.
base::PostTaskWithTraits(
- FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
base::BindOnce(
[](base::Thread* rthread, base::Thread* wthread) {
delete rthread;
diff --git a/chromium/content/browser/devtools/devtools_session.cc b/chromium/content/browser/devtools/devtools_session.cc
index a82213afc24..0d91850d5e7 100644
--- a/chromium/content/browser/devtools/devtools_session.cc
+++ b/chromium/content/browser/devtools/devtools_session.cc
@@ -42,7 +42,6 @@ DevToolsSession::DevToolsSession(DevToolsAgentHostImpl* agent_host,
host_(nullptr),
dispatcher_(new protocol::UberDispatcher(this)),
weak_factory_(this) {
- dispatcher_->setFallThroughForNotFound(true);
}
DevToolsSession::~DevToolsSession() {
@@ -76,7 +75,6 @@ void DevToolsSession::SetRenderer(int process_host_id,
void DevToolsSession::SetBrowserOnly(bool browser_only) {
browser_only_ = browser_only;
- dispatcher_->setFallThroughForNotFound(!browser_only);
}
void DevToolsSession::AttachToAgent(
@@ -85,7 +83,7 @@ void DevToolsSession::AttachToAgent(
binding_.Bind(mojo::MakeRequest(&host_ptr_info));
agent->AttachDevToolsSession(
std::move(host_ptr_info), mojo::MakeRequest(&session_ptr_),
- mojo::MakeRequest(&io_session_ptr_), state_cookie_);
+ mojo::MakeRequest(&io_session_ptr_), session_state_cookie_.Clone());
session_ptr_.set_connection_error_handler(base::BindOnce(
&DevToolsSession::MojoConnectionDestroyed, base::Unretained(this)));
@@ -104,9 +102,9 @@ void DevToolsSession::AttachToAgent(
waiting_for_response_messages_.clear();
}
- // Set cookie to an empty string to reattach next time instead of attaching.
- if (!state_cookie_.has_value())
- state_cookie_ = std::string();
+ // Set cookie to an empty struct to reattach next time instead of attaching.
+ if (!session_state_cookie_)
+ session_state_cookie_ = blink::mojom::DevToolsSessionState::New();
}
void DevToolsSession::SendResponse(
@@ -125,22 +123,39 @@ void DevToolsSession::MojoConnectionDestroyed() {
void DevToolsSession::DispatchProtocolMessage(
const std::string& message,
- base::DictionaryValue* parsed_message) {
+ std::unique_ptr<base::DictionaryValue> parsed_message) {
DevToolsManagerDelegate* delegate =
DevToolsManager::GetInstance()->delegate();
- if (delegate && parsed_message &&
- delegate->HandleCommand(agent_host_, client_, parsed_message)) {
- return;
+ if (delegate && parsed_message) {
+ delegate->HandleCommand(agent_host_, client_, std::move(parsed_message),
+ message,
+ base::BindOnce(&DevToolsSession::HandleCommand,
+ weak_factory_.GetWeakPtr()));
+ } else {
+ HandleCommand(std::move(parsed_message), message);
}
+}
+void DevToolsSession::HandleCommand(
+ std::unique_ptr<base::DictionaryValue> parsed_message,
+ const std::string& message) {
+ std::unique_ptr<protocol::Value> protocol_command =
+ protocol::toProtocolValue(parsed_message.get(), 1000);
int call_id;
std::string method;
- if (dispatcher_->dispatch(protocol::toProtocolValue(parsed_message, 1000),
- &call_id,
- &method) != protocol::Response::kFallThrough) {
+ if (!dispatcher_->parseCommand(protocol_command.get(), &call_id, &method))
return;
+ if (browser_only_ || dispatcher_->canDispatch(method)) {
+ dispatcher_->dispatch(call_id, method, std::move(protocol_command),
+ message);
+ } else {
+ fallThrough(call_id, method, message);
}
+}
+void DevToolsSession::fallThrough(int call_id,
+ const std::string& method,
+ const std::string& message) {
// In browser-only mode, we should've handled everything in dispatcher.
DCHECK(!browser_only_);
@@ -203,9 +218,8 @@ void DevToolsSession::flushProtocolNotifications() {
void DevToolsSession::DispatchProtocolResponse(
const std::string& message,
int call_id,
- const base::Optional<std::string>& state) {
- if (state.has_value())
- state_cookie_ = state.value();
+ blink::mojom::DevToolsSessionStatePtr updates) {
+ ApplySessionStateUpdates(std::move(updates));
waiting_for_response_messages_.erase(call_id);
client_->DispatchProtocolMessage(agent_host_, message);
// |this| may be deleted at this point.
@@ -213,11 +227,23 @@ void DevToolsSession::DispatchProtocolResponse(
void DevToolsSession::DispatchProtocolNotification(
const std::string& message,
- const base::Optional<std::string>& state) {
- if (state.has_value())
- state_cookie_ = state.value();
+ blink::mojom::DevToolsSessionStatePtr updates) {
+ ApplySessionStateUpdates(std::move(updates));
client_->DispatchProtocolMessage(agent_host_, message);
// |this| may be deleted at this point.
}
+void DevToolsSession::ApplySessionStateUpdates(
+ blink::mojom::DevToolsSessionStatePtr updates) {
+ if (!updates)
+ return;
+ if (!session_state_cookie_)
+ session_state_cookie_ = blink::mojom::DevToolsSessionState::New();
+ for (auto& entry : updates->entries) {
+ if (entry.second.has_value())
+ session_state_cookie_->entries[entry.first] = std::move(entry.second);
+ else
+ session_state_cookie_->entries.erase(entry.first);
+ }
+}
} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_session.h b/chromium/content/browser/devtools/devtools_session.h
index 2b2bccf785b..467edb43869 100644
--- a/chromium/content/browser/devtools/devtools_session.h
+++ b/chromium/content/browser/devtools/devtools_session.h
@@ -43,8 +43,9 @@ class DevToolsSession : public protocol::FrontendChannel,
void SetRenderer(int process_host_id, RenderFrameHostImpl* frame_host);
void AttachToAgent(const blink::mojom::DevToolsAgentAssociatedPtr& agent);
- void DispatchProtocolMessage(const std::string& message,
- base::DictionaryValue* parsed_message);
+ void DispatchProtocolMessage(
+ const std::string& message,
+ std::unique_ptr<base::DictionaryValue> parsed_message);
void SuspendSendingMessagesToAgent();
void ResumeSendingMessagesToAgent();
@@ -69,6 +70,8 @@ class DevToolsSession : public protocol::FrontendChannel,
void DispatchProtocolMessageToAgent(int call_id,
const std::string& method,
const std::string& message);
+ void HandleCommand(std::unique_ptr<base::DictionaryValue> parsed_message,
+ const std::string& message);
// protocol::FrontendChannel implementation.
void sendProtocolResponse(
@@ -77,15 +80,21 @@ class DevToolsSession : public protocol::FrontendChannel,
void sendProtocolNotification(
std::unique_ptr<protocol::Serializable> message) override;
void flushProtocolNotifications() override;
+ void fallThrough(int call_id,
+ const std::string& method,
+ const std::string& message) override;
// blink::mojom::DevToolsSessionHost implementation.
void DispatchProtocolResponse(
const std::string& message,
int call_id,
- const base::Optional<std::string>& state) override;
+ blink::mojom::DevToolsSessionStatePtr updates) override;
void DispatchProtocolNotification(
const std::string& message,
- const base::Optional<std::string>& state) override;
+ blink::mojom::DevToolsSessionStatePtr updates) override;
+
+ // Merges the |updates| received from the renderer into session_state_cookie_.
+ void ApplySessionStateUpdates(blink::mojom::DevToolsSessionStatePtr updates);
mojo::AssociatedBinding<blink::mojom::DevToolsSessionHost> binding_;
blink::mojom::DevToolsSessionAssociatedPtr session_ptr_;
@@ -117,10 +126,10 @@ class DevToolsSession : public protocol::FrontendChannel,
};
std::map<int, WaitingMessage> waiting_for_response_messages_;
- // |state_cookie_| always corresponds to a state before
+ // |session_state_cookie_| always corresponds to a state before
// any of the waiting for response messages have been handled.
- // Note that |state_cookie_| is not present only before first attach.
- base::Optional<std::string> state_cookie_;
+ // |session_state_cookie_| is nullptr before first attach.
+ blink::mojom::DevToolsSessionStatePtr session_state_cookie_;
base::WeakPtrFactory<DevToolsSession> weak_factory_;
};
diff --git a/chromium/content/browser/devtools/devtools_stream_file.cc b/chromium/content/browser/devtools/devtools_stream_file.cc
index c32261e092a..1e0aa6b6bd3 100644
--- a/chromium/content/browser/devtools/devtools_stream_file.cc
+++ b/chromium/content/browser/devtools/devtools_stream_file.cc
@@ -9,8 +9,8 @@
#include "base/files/file_util.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/string_util.h"
-#include "base/task_scheduler/lazy_task_runner.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/lazy_task_runner.h"
+#include "base/task/post_task.h"
#include "base/third_party/icu/icu_utf.h"
#include "base/threading/thread_restrictions.h"
#include "content/public/browser/browser_thread.h"
@@ -19,8 +19,8 @@
namespace content {
scoped_refptr<base::SequencedTaskRunner> impl_task_runner() {
- constexpr base::TaskTraits kBlockingTraits = {base::MayBlock(),
- base::TaskPriority::BACKGROUND};
+ constexpr base::TaskTraits kBlockingTraits = {
+ base::MayBlock(), base::TaskPriority::BEST_EFFORT};
static base::LazySequencedTaskRunner s_sequenced_task_unner =
LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER(kBlockingTraits);
return s_sequenced_task_unner.Get();
diff --git a/chromium/content/browser/devtools/devtools_url_interceptor_request_job.cc b/chromium/content/browser/devtools/devtools_url_interceptor_request_job.cc
index 65329798837..d07eca5061f 100644
--- a/chromium/content/browser/devtools/devtools_url_interceptor_request_job.cc
+++ b/chromium/content/browser/devtools/devtools_url_interceptor_request_job.cc
@@ -566,7 +566,6 @@ DevToolsURLInterceptorRequestJob::DevToolsURLInterceptorRequestJob(
net::NetworkDelegate* original_network_delegate,
const base::UnguessableToken& devtools_token,
DevToolsNetworkInterceptor::RequestInterceptedCallback callback,
- bool is_redirect,
ResourceType resource_type,
InterceptionStage stage_to_intercept)
: net::URLRequestJob(original_request, original_network_delegate),
@@ -584,7 +583,6 @@ DevToolsURLInterceptorRequestJob::DevToolsURLInterceptorRequestJob(
owning_entry_id_(owning_entry_id),
devtools_token_(devtools_token),
callback_(callback),
- is_redirect_(is_redirect),
resource_type_(resource_type),
stage_to_intercept_(stage_to_intercept),
weak_ptr_factory_(this) {
@@ -635,26 +633,6 @@ void DevToolsURLInterceptorRequestJob::StartWithCookies(
return;
}
- if (is_redirect_) {
- if (stage_to_intercept_ == InterceptionStage::REQUEST) {
- // If we are a redirect and we do not plan on grabbing the response we are
- // done. If we are here this means we must have already sent an
- // intercepted event to front-end for this redirect and the front-end
- // allowed it. Since we have already allowed the redirect and we are only
- // intercepting the request, we only need to catch it again if it's
- // another redirect, which SubRequest will send the
- // OnSubRequestRedirectReceived event.
- sub_request_.reset(new SubRequest(request_details_, this, interceptor_));
- } else {
- // Otherwise we have already issued the request interception and had a
- // continue and now we must issue a response interception for the
- // redirect.
- sub_request_.reset(
- new InterceptedRequest(request_details_, this, interceptor_));
- }
- return;
- }
-
if (stage_to_intercept_ == InterceptionStage::RESPONSE) {
// We are only a response interception, we go right to dispatching the
// request.
@@ -821,8 +799,7 @@ void DevToolsURLInterceptorRequestJob::OnSubRequestRedirectReceived(
// If we're not intercepting results or are a response then cancel this
// redirect and tell the parent request it was redirected through |redirect_|.
- if (stage_to_intercept_ == InterceptionStage::DONT_INTERCEPT ||
- stage_to_intercept_ == InterceptionStage::RESPONSE) {
+ if (!(stage_to_intercept_ & InterceptionStage::RESPONSE)) {
*defer_redirect = false;
ProcessRedirect(redirectinfo.status_code, redirectinfo.new_url.spec());
redirect_.reset();
@@ -1045,7 +1022,6 @@ void DevToolsURLInterceptorRequestJob::ProcessRedirect(
base::MakeRefCounted<net::HttpResponseHeaders>(raw_headers), "", 0,
base::TimeTicks::Now()));
- interceptor_->ExpectRequestAfterRedirect(request(), interception_id_);
NotifyHeadersComplete();
}
@@ -1124,11 +1100,6 @@ void DevToolsURLInterceptorRequestJob::ProcessInterceptionResponse(
mock_response_details_.reset(new MockResponseDetails(
std::move(*modifications->raw_response), base::TimeTicks::Now()));
- std::string value;
- if (mock_response_details_->response_headers()->IsRedirect(&value)) {
- interceptor_->ExpectRequestAfterRedirect(request(), interception_id_);
- }
-
// Set cookies in the network stack.
net::CookieOptions options;
options.set_include_httponly();
diff --git a/chromium/content/browser/devtools/devtools_url_interceptor_request_job.h b/chromium/content/browser/devtools/devtools_url_interceptor_request_job.h
index e7531a1d79d..ac37f7204ff 100644
--- a/chromium/content/browser/devtools/devtools_url_interceptor_request_job.h
+++ b/chromium/content/browser/devtools/devtools_url_interceptor_request_job.h
@@ -37,7 +37,6 @@ class DevToolsURLInterceptorRequestJob : public net::URLRequestJob {
net::NetworkDelegate* original_network_delegate,
const base::UnguessableToken& devtools_token,
DevToolsNetworkInterceptor::RequestInterceptedCallback callback,
- bool is_redirect,
ResourceType resource_type,
DevToolsNetworkInterceptor::InterceptionStage stage_to_intercept);
@@ -157,7 +156,6 @@ class DevToolsURLInterceptorRequestJob : public net::URLRequestJob {
const intptr_t owning_entry_id_;
const base::UnguessableToken devtools_token_;
DevToolsNetworkInterceptor::RequestInterceptedCallback callback_;
- const bool is_redirect_;
const ResourceType resource_type_;
InterceptionStage stage_to_intercept_;
std::vector<std::unique_ptr<GetResponseBodyForInterceptionCallback>>
diff --git a/chromium/content/browser/devtools/devtools_url_loader_interceptor.cc b/chromium/content/browser/devtools/devtools_url_loader_interceptor.cc
index 6d4201baf6d..99e8fd164e5 100644
--- a/chromium/content/browser/devtools/devtools_url_loader_interceptor.cc
+++ b/chromium/content/browser/devtools/devtools_url_loader_interceptor.cc
@@ -252,8 +252,9 @@ class InterceptionJob : public network::mojom::URLLoaderClient,
void OnComplete(const network::URLLoaderCompletionStatus& status) override;
bool CanGetResponseBody(std::string* error_reason);
+ void UpdateIdAndRegister();
- const std::string id_;
+ const std::string id_prefix_;
const GlobalRequestId global_req_id_;
const base::UnguessableToken frame_token_;
const base::TimeTicks start_ticks_;
@@ -277,6 +278,7 @@ class InterceptionJob : public network::mojom::URLLoaderClient,
kNotStarted,
kRequestSent,
kRedirectReceived,
+ kFollowRedirect,
kAuthRequired,
kResponseReceived,
kResponseTaken,
@@ -284,6 +286,8 @@ class InterceptionJob : public network::mojom::URLLoaderClient,
State state_;
bool waiting_for_resolution_;
+ int redirect_count_;
+ std::string current_id_;
std::unique_ptr<BodyReader> body_reader_;
std::unique_ptr<ResponseMetadata> response_metadata_;
@@ -320,11 +324,11 @@ class DevToolsURLLoaderInterceptor::Impl
static int last_id = 0;
std::string id = base::StringPrintf("interception-job-%d", ++last_id);
- InterceptionJob* job = new InterceptionJob(
- this, id, frame_token, process_id, std::move(create_params),
- is_download, std::move(loader_request), std::move(client),
- std::move(target_factory));
- jobs_.emplace(std::move(id), job);
+ // This class will manage its own life time to match the loader client.
+ new InterceptionJob(this, std::move(id), frame_token, process_id,
+ std::move(create_params), is_download,
+ std::move(loader_request), std::move(client),
+ std::move(target_factory));
}
void SetPatterns(std::vector<DevToolsNetworkInterceptor::Pattern> patterns) {
@@ -392,6 +396,9 @@ class DevToolsURLLoaderInterceptor::Impl
}
void RemoveJob(const std::string& id) { jobs_.erase(id); }
+ void AddJob(const std::string& id, InterceptionJob* job) {
+ jobs_.emplace(id, job);
+ }
std::map<std::string, InterceptionJob*> jobs_;
RequestInterceptedCallback request_intercepted_callback_;
@@ -627,7 +634,7 @@ InterceptionJob::InterceptionJob(
network::mojom::URLLoaderRequest loader_request,
network::mojom::URLLoaderClientPtr client,
network::mojom::URLLoaderFactoryPtr target_factory)
- : id_(std::move(id)),
+ : id_prefix_(id),
global_req_id_(
std::make_tuple(process_id,
create_loader_params->request.render_frame_id,
@@ -644,7 +651,9 @@ InterceptionJob::InterceptionJob(
client_(std::move(client)),
target_factory_(std::move(target_factory)),
state_(kNotStarted),
- waiting_for_resolution_(false) {
+ waiting_for_resolution_(false),
+ redirect_count_(0) {
+ UpdateIdAndRegister();
const network::ResourceRequest& request = create_loader_params_->request;
stage_ = interceptor_->GetInterceptionStage(
request.url, static_cast<ResourceType>(request.resource_type));
@@ -665,6 +674,11 @@ InterceptionJob::InterceptionJob(
StartRequest();
}
+void InterceptionJob::UpdateIdAndRegister() {
+ current_id_ = id_prefix_ + base::StringPrintf(".%d", redirect_count_);
+ interceptor_->AddJob(current_id_, this);
+}
+
bool InterceptionJob::CanGetResponseBody(std::string* error_reason) {
if (!(stage_ & InterceptionStage::RESPONSE)) {
*error_reason =
@@ -786,6 +800,18 @@ Response InterceptionJob::InnerContinueRequest(
if (modifications->raw_response)
return ProcessResponseOverride(*modifications->raw_response);
+ if (state_ == State::kFollowRedirect) {
+ if (modifications->modified_url.isJust()) {
+ CancelRequest();
+ // Fall through to the generic logic of re-starting the request
+ // at the bottom of the method.
+ } else {
+ // TODO(caseq): report error if other modifications are present.
+ state_ = State::kRequestSent;
+ loader_->FollowRedirect(base::nullopt, base::nullopt);
+ return Response::OK();
+ }
+ }
if (state_ == State::kRedirectReceived) {
// TODO(caseq): report error if other modifications are present.
if (modifications->modified_url.isJust()) {
@@ -918,6 +944,7 @@ Response InterceptionJob::ProcessResponseOverride(const std::string& response) {
create_loader_params_->request.url, "",
net::ForceSniffFileUrlsForHtml::kDisabled,
&head->mime_type);
+ head->did_mime_sniff = true;
}
head->content_length = body_size;
head->encoded_data_length = header_size;
@@ -1037,7 +1064,7 @@ void InterceptionJob::CancelRequest() {
std::unique_ptr<InterceptedRequestInfo> InterceptionJob::BuildRequestInfo(
const network::ResourceResponseHead* head) {
auto result = std::make_unique<InterceptedRequestInfo>();
- result->interception_id = id_;
+ result->interception_id = current_id_;
result->network_request =
protocol::NetworkHandler::CreateRequestFromResourceRequest(
create_loader_params_->request);
@@ -1078,7 +1105,7 @@ void InterceptionJob::NotifyClient(
void InterceptionJob::Shutdown() {
if (interceptor_)
- interceptor_->RemoveJob(id_);
+ interceptor_->RemoveJob(current_id_);
delete this;
}
@@ -1100,9 +1127,24 @@ void InterceptionJob::FollowRedirect(
request->referrer_policy = info.new_referrer_policy;
request->referrer = GURL(info.new_referrer);
response_metadata_.reset();
+
if (interceptor_) {
+ // Pretend that each redirect hop is a new request -- this is for
+ // compatibilty with URLRequestJob-based interception implementation.
+ interceptor_->RemoveJob(current_id_);
+ redirect_count_++;
+ UpdateIdAndRegister();
+
stage_ = interceptor_->GetInterceptionStage(
request->url, static_cast<ResourceType>(request->resource_type));
+ if (stage_ & InterceptionStage::REQUEST) {
+ if (state_ == State::kRedirectReceived)
+ state_ = State::kFollowRedirect;
+ else
+ DCHECK_EQ(State::kNotStarted, state_);
+ NotifyClient(BuildRequestInfo(nullptr));
+ return;
+ }
}
if (state_ == State::kRedirectReceived) {
state_ = State::kRequestSent;
@@ -1168,7 +1210,7 @@ void InterceptionJob::OnReceiveRedirect(
response_metadata_->redirect_info =
std::make_unique<net::RedirectInfo>(redirect_info);
- if (!(stage_ & InterceptionStage::REQUEST)) {
+ if (!(stage_ & InterceptionStage::RESPONSE)) {
client_->OnReceiveRedirect(redirect_info, head);
return;
}
diff --git a/chromium/content/browser/devtools/devtools_url_request_interceptor.cc b/chromium/content/browser/devtools/devtools_url_request_interceptor.cc
index 0a02236d4dc..e6bf677b05b 100644
--- a/chromium/content/browser/devtools/devtools_url_request_interceptor.cc
+++ b/chromium/content/browser/devtools/devtools_url_request_interceptor.cc
@@ -141,8 +141,7 @@ net::URLRequestJob* DevToolsURLRequestInterceptor::InnerMaybeInterceptRequest(
return nullptr;
DCHECK(interception_stage != DONT_INTERCEPT);
- bool is_redirect;
- std::string interception_id = GetIdForRequest(request, &is_redirect);
+ std::string interception_id = base::StringPrintf("id-%zu", ++next_id_);
if (IsNavigationRequest(resource_type)) {
BrowserThread::PostTask(
@@ -155,8 +154,7 @@ net::URLRequestJob* DevToolsURLRequestInterceptor::InnerMaybeInterceptRequest(
DevToolsURLInterceptorRequestJob* job = new DevToolsURLInterceptorRequestJob(
this, interception_id, reinterpret_cast<intptr_t>(entry), request,
network_delegate, target_info->devtools_token, entry->callback,
- is_redirect, resource_request_info->GetResourceType(),
- interception_stage);
+ resource_request_info->GetResourceType(), interception_stage);
interception_id_to_job_map_[interception_id] = job;
return job;
}
@@ -261,28 +259,6 @@ void DevToolsURLRequestInterceptor::UnregisterSubRequest(
sub_requests_.erase(sub_request);
}
-void DevToolsURLRequestInterceptor::ExpectRequestAfterRedirect(
- const net::URLRequest* request,
- std::string id) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- expected_redirects_[request] = id;
-}
-
-std::string DevToolsURLRequestInterceptor::GetIdForRequest(
- const net::URLRequest* request,
- bool* is_redirect) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- auto find_it = expected_redirects_.find(request);
- if (find_it == expected_redirects_.end()) {
- *is_redirect = false;
- return base::StringPrintf("id-%zu", ++next_id_);
- }
- *is_redirect = true;
- std::string id = find_it->second;
- expected_redirects_.erase(find_it);
- return id;
-}
-
DevToolsURLInterceptorRequestJob* DevToolsURLRequestInterceptor::GetJob(
const std::string& interception_id) const {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
diff --git a/chromium/content/browser/devtools/devtools_url_request_interceptor.h b/chromium/content/browser/devtools/devtools_url_request_interceptor.h
index 96bb378be41..397dd660883 100644
--- a/chromium/content/browser/devtools/devtools_url_request_interceptor.h
+++ b/chromium/content/browser/devtools/devtools_url_request_interceptor.h
@@ -66,10 +66,6 @@ class DevToolsURLRequestInterceptor : public net::URLRequestInterceptor,
// Registers a |sub_request| that should not be intercepted.
void RegisterSubRequest(const net::URLRequest* sub_request);
void UnregisterSubRequest(const net::URLRequest* sub_request);
- // To make the user's life easier we make sure requests in a redirect chain
- // all have the same id.
- void ExpectRequestAfterRedirect(const net::URLRequest* request,
- std::string id);
void JobFinished(const std::string& interception_id, bool is_navigation);
private:
@@ -85,8 +81,6 @@ class DevToolsURLRequestInterceptor : public net::URLRequestInterceptor,
const DevToolsTargetRegistry::TargetInfo* TargetInfoForRequestInfo(
const ResourceRequestInfo* request_info) const;
- std::string GetIdForRequest(const net::URLRequest* request,
- bool* is_redirect);
// Returns a WeakPtr to the DevToolsURLInterceptorRequestJob corresponding
// to |interception_id|.
DevToolsURLInterceptorRequestJob* GetJob(
@@ -107,9 +101,6 @@ class DevToolsURLRequestInterceptor : public net::URLRequestInterceptor,
// requests.
base::flat_set<const net::URLRequest*> sub_requests_;
- // To simplify handling of redirect chains for the end user, we arrange for
- // all requests in the chain to have the same interception id.
- base::flat_map<const net::URLRequest*, std::string> expected_redirects_;
size_t next_id_;
base::WeakPtrFactory<DevToolsURLRequestInterceptor> weak_factory_;
diff --git a/chromium/content/browser/devtools/devtools_video_consumer.cc b/chromium/content/browser/devtools/devtools_video_consumer.cc
index 2b185d09f79..e6316a8681c 100644
--- a/chromium/content/browser/devtools/devtools_video_consumer.cc
+++ b/chromium/content/browser/devtools/devtools_video_consumer.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "base/memory/shared_memory_mapping.h"
#include "cc/paint/skia_paint_canvas.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h"
@@ -129,31 +130,46 @@ bool DevToolsVideoConsumer::IsValidMinAndMaxFrameSize(
}
void DevToolsVideoConsumer::OnFrameCaptured(
- mojo::ScopedSharedBufferHandle buffer,
- uint32_t buffer_size,
+ base::ReadOnlySharedMemoryRegion data,
::media::mojom::VideoFrameInfoPtr info,
const gfx::Rect& update_rect,
const gfx::Rect& content_rect,
viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) {
- if (!buffer.is_valid())
+ if (!data.IsValid())
return;
- mojo::ScopedSharedBufferMapping mapping = buffer->Map(buffer_size);
- if (!mapping) {
+ base::ReadOnlySharedMemoryMapping mapping = data.Map();
+ if (!mapping.IsValid()) {
DLOG(ERROR) << "Shared memory mapping failed.";
return;
}
+ if (mapping.size() <
+ media::VideoFrame::AllocationSize(info->pixel_format, info->coded_size)) {
+ DLOG(ERROR) << "Shared memory size was less than expected.";
+ return;
+ }
- scoped_refptr<media::VideoFrame> frame;
+ // Create a media::VideoFrame that wraps the read-only shared memory data.
+ // Unfortunately, a deep web of not-const-correct code exists in
+ // media::VideoFrame and media::PaintCanvasVideoRenderer (see
+ // GetSkBitmapFromFrame() above). So, the pointer's const attribute must be
+ // casted away. This is safe since the operating system will page fault if
+ // there is any attempt downstream to mutate the data.
+ //
// Setting |frame|'s visible rect equal to |content_rect| so that only the
- // portion of the frame that contain content are used.
- frame = media::VideoFrame::WrapExternalData(
+ // portion of the frame that contains content is used.
+ scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapExternalData(
info->pixel_format, info->coded_size, content_rect, content_rect.size(),
- static_cast<uint8_t*>(mapping.get()), buffer_size, info->timestamp);
- if (!frame)
+ const_cast<uint8_t*>(static_cast<const uint8_t*>(mapping.memory())),
+ mapping.size(), info->timestamp);
+ if (!frame) {
+ DLOG(ERROR) << "Unable to create VideoFrame wrapper around the shmem.";
return;
+ }
frame->AddDestructionObserver(base::BindOnce(
- [](mojo::ScopedSharedBufferMapping mapping) {}, std::move(mapping)));
+ [](base::ReadOnlySharedMemoryMapping mapping,
+ viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) {},
+ std::move(mapping), std::move(callbacks)));
frame->metadata()->MergeInternalValuesFrom(info->metadata);
callback_.Run(std::move(frame));
diff --git a/chromium/content/browser/devtools/devtools_video_consumer.h b/chromium/content/browser/devtools/devtools_video_consumer.h
index dd17f36abdd..2634849d6c2 100644
--- a/chromium/content/browser/devtools/devtools_video_consumer.h
+++ b/chromium/content/browser/devtools/devtools_video_consumer.h
@@ -10,7 +10,6 @@
#include "base/time/time.h"
#include "components/viz/host/client_frame_sink_video_capturer.h"
#include "content/common/content_export.h"
-#include "mojo/public/cpp/bindings/binding.h"
#include "ui/gfx/geometry/size.h"
class SkBitmap;
@@ -64,8 +63,7 @@ class CONTENT_EXPORT DevToolsVideoConsumer
// viz::mojom::FrameSinkVideoConsumer:
void OnFrameCaptured(
- mojo::ScopedSharedBufferHandle buffer,
- uint32_t buffer_size,
+ base::ReadOnlySharedMemoryRegion data,
::media::mojom::VideoFrameInfoPtr info,
const gfx::Rect& update_rect,
const gfx::Rect& content_rect,
diff --git a/chromium/content/browser/devtools/devtools_video_consumer_unittest.cc b/chromium/content/browser/devtools/devtools_video_consumer_unittest.cc
index 826ab906e49..6aefd60ca68 100644
--- a/chromium/content/browser/devtools/devtools_video_consumer_unittest.cc
+++ b/chromium/content/browser/devtools/devtools_video_consumer_unittest.cc
@@ -5,10 +5,13 @@
#include <utility>
#include <vector>
+#include "base/memory/read_only_shared_memory_region.h"
#include "base/message_loop/message_loop.h"
#include "content/browser/devtools/devtools_video_consumer.h"
#include "content/public/test/test_utils.h"
#include "media/base/limits.h"
+#include "mojo/public/cpp/base/shared_memory_utils.h"
+#include "mojo/public/cpp/bindings/binding.h"
#include "testing/gmock/include/gmock/gmock.h"
using testing::_;
@@ -91,6 +94,9 @@ class MockFrameSinkVideoCapturer : public viz::mojom::FrameSinkVideoCapturer {
}
MOCK_METHOD0(MockStop, void());
MOCK_METHOD0(RequestRefreshFrame, void());
+ MOCK_METHOD2(CreateOverlay,
+ void(int32_t stacking_index,
+ viz::mojom::FrameSinkVideoCaptureOverlayRequest request));
// Const accessors to get the cached variables.
base::TimeDelta min_capture_period() const { return min_capture_period_; }
@@ -169,8 +175,7 @@ class DevToolsVideoConsumerTest : public testing::Test {
consumer_->SetFrameSinkId(kInitialFrameSinkId);
}
- void SimulateFrameCapture(mojo::ScopedSharedBufferHandle buffer,
- uint32_t buffer_size) {
+ void SimulateFrameCapture(base::ReadOnlySharedMemoryRegion data) {
viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks_ptr;
callbacks.Bind(mojo::MakeRequest(&callbacks_ptr));
@@ -178,7 +183,7 @@ class DevToolsVideoConsumerTest : public testing::Test {
base::TimeDelta(), base::Value(base::Value::Type::DICTIONARY), kFormat,
kResolution, gfx::Rect(kResolution));
- consumer_->OnFrameCaptured(std::move(buffer), buffer_size, std::move(info),
+ consumer_->OnFrameCaptured(std::move(data), std::move(info),
gfx::Rect(kResolution), gfx::Rect(kResolution),
std::move(callbacks_ptr));
}
@@ -232,48 +237,40 @@ class DevToolsVideoConsumerTest : public testing::Test {
// Tests that the OnFrameFromVideoConsumer callbacks is called when
// OnFrameCaptured is passed a valid buffer with valid mapping.
TEST_F(DevToolsVideoConsumerTest, CallbacksAreCalledWhenBufferValid) {
- // Create a valid buffer.
- const size_t buffer_size =
- media::VideoFrame::AllocationSize(kFormat, kResolution);
- mojo::ScopedSharedBufferHandle buffer =
- mojo::SharedBufferHandle::Create(buffer_size);
-
// On valid buffer the |receiver_| gets a frame via OnFrameFromVideoConsumer.
EXPECT_CALL(receiver_, OnFrameFromVideoConsumerMock(_)).Times(1);
- SimulateFrameCapture(std::move(buffer), buffer_size);
+ auto region = mojo::CreateReadOnlySharedMemoryRegion(
+ media::VideoFrame::AllocationSize(kFormat, kResolution))
+ .region;
+ ASSERT_TRUE(region.IsValid());
+ SimulateFrameCapture(std::move(region));
base::RunLoop().RunUntilIdle();
}
// Tests that only the OnFrameFromVideoConsumer callback is not called when
// OnFrameCaptured is passed an invalid buffer.
-TEST_F(DevToolsVideoConsumerTest, OnFrameCapturedExitEarlyOnInvalidBuffer) {
- // Create an invalid buffer.
- const size_t buffer_size = 0;
- mojo::ScopedSharedBufferHandle buffer =
- mojo::SharedBufferHandle::Create(buffer_size);
-
+TEST_F(DevToolsVideoConsumerTest, CallbackIsNotCalledWhenBufferIsNotValid) {
// On invalid buffer, the |receiver_| doesn't get a frame.
EXPECT_CALL(receiver_, OnFrameFromVideoConsumerMock(_)).Times(0);
- SimulateFrameCapture(std::move(buffer), buffer_size);
+ SimulateFrameCapture(base::ReadOnlySharedMemoryRegion());
base::RunLoop().RunUntilIdle();
}
// Tests that the OnFrameFromVideoConsumer callback is not called when
-// OnFrameCaptured is passed a buffer with invalid mapping.
-TEST_F(DevToolsVideoConsumerTest, OnFrameCapturedExitsOnInvalidMapping) {
- // Create a valid buffer, but change buffer_size to simulate an invalid
- // mapping.
- size_t buffer_size = media::VideoFrame::AllocationSize(kFormat, kResolution);
- mojo::ScopedSharedBufferHandle buffer =
- mojo::SharedBufferHandle::Create(buffer_size);
- buffer_size = 0;
-
+// OnFrameCaptured is passed a buffer with less-than-expected size.
+TEST_F(DevToolsVideoConsumerTest, CallbackIsNotCalledWhenBufferIsTooSmall) {
// On invalid mapping, the |receiver_| doesn't get a frame.
EXPECT_CALL(receiver_, OnFrameFromVideoConsumerMock(_)).Times(0);
- SimulateFrameCapture(std::move(buffer), buffer_size);
+ constexpr size_t too_few_number_of_bytes = 4;
+ ASSERT_LT(too_few_number_of_bytes,
+ media::VideoFrame::AllocationSize(kFormat, kResolution));
+ auto region =
+ mojo::CreateReadOnlySharedMemoryRegion(too_few_number_of_bytes).region;
+ ASSERT_TRUE(region.IsValid());
+ SimulateFrameCapture(std::move(region));
base::RunLoop().RunUntilIdle();
}
diff --git a/chromium/content/browser/devtools/protocol/browser_handler.cc b/chromium/content/browser/devtools/protocol/browser_handler.cc
index 618ca845bad..2c57058886f 100644
--- a/chromium/content/browser/devtools/protocol/browser_handler.cc
+++ b/chromium/content/browser/devtools/protocol/browser_handler.cc
@@ -13,7 +13,11 @@
#include "base/metrics/statistics_recorder.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "content/browser/devtools/devtools_manager.h"
+#include "content/browser/permissions/permission_controller_impl.h"
+#include "content/public/browser/browser_context.h"
#include "content/public/browser/devtools_agent_host.h"
+#include "content/public/browser/permission_type.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/user_agent.h"
@@ -27,6 +31,24 @@ BrowserHandler::BrowserHandler()
BrowserHandler::~BrowserHandler() {}
+Response BrowserHandler::Disable() {
+ for (auto& browser_context_id : contexts_with_overridden_permissions_) {
+ content::BrowserContext* browser_context = nullptr;
+ std::string error;
+ Maybe<std::string> context_id =
+ browser_context_id == "" ? Maybe<std::string>()
+ : Maybe<std::string>(browser_context_id);
+ FindBrowserContext(context_id, &browser_context);
+ if (browser_context) {
+ PermissionControllerImpl* permission_controller =
+ PermissionControllerImpl::FromBrowserContext(browser_context);
+ permission_controller->ResetPermissionOverridesForDevTools();
+ }
+ }
+ contexts_with_overridden_permissions_.clear();
+ return Response::OK();
+}
+
void BrowserHandler::Wire(UberDispatcher* dispatcher) {
Browser::Dispatcher::wire(dispatcher, this);
}
@@ -81,6 +103,47 @@ std::unique_ptr<Browser::Histogram> Convert(base::HistogramBase& in_histogram,
.Build();
}
+Response FromProtocolPermissionType(
+ const protocol::Browser::PermissionType& type,
+ PermissionType* out_type) {
+ if (type == protocol::Browser::PermissionTypeEnum::Notifications) {
+ *out_type = PermissionType::NOTIFICATIONS;
+ } else if (type == protocol::Browser::PermissionTypeEnum::Geolocation) {
+ *out_type = PermissionType::GEOLOCATION;
+ } else if (type ==
+ protocol::Browser::PermissionTypeEnum::ProtectedMediaIdentifier) {
+ *out_type = PermissionType::PROTECTED_MEDIA_IDENTIFIER;
+ } else if (type == protocol::Browser::PermissionTypeEnum::Midi) {
+ *out_type = PermissionType::MIDI;
+ } else if (type == protocol::Browser::PermissionTypeEnum::MidiSysex) {
+ *out_type = PermissionType::MIDI_SYSEX;
+ } else if (type == protocol::Browser::PermissionTypeEnum::DurableStorage) {
+ *out_type = PermissionType::DURABLE_STORAGE;
+ } else if (type == protocol::Browser::PermissionTypeEnum::AudioCapture) {
+ *out_type = PermissionType::AUDIO_CAPTURE;
+ } else if (type == protocol::Browser::PermissionTypeEnum::VideoCapture) {
+ *out_type = PermissionType::VIDEO_CAPTURE;
+ } else if (type == protocol::Browser::PermissionTypeEnum::BackgroundSync) {
+ *out_type = PermissionType::BACKGROUND_SYNC;
+ } else if (type == protocol::Browser::PermissionTypeEnum::Flash) {
+ *out_type = PermissionType::FLASH;
+ } else if (type == protocol::Browser::PermissionTypeEnum::Sensors) {
+ *out_type = PermissionType::SENSORS;
+ } else if (type ==
+ protocol::Browser::PermissionTypeEnum::AccessibilityEvents) {
+ *out_type = PermissionType::ACCESSIBILITY_EVENTS;
+ } else if (type == protocol::Browser::PermissionTypeEnum::ClipboardRead) {
+ *out_type = PermissionType::CLIPBOARD_READ;
+ } else if (type == protocol::Browser::PermissionTypeEnum::ClipboardWrite) {
+ *out_type = PermissionType::CLIPBOARD_WRITE;
+ } else if (type == protocol::Browser::PermissionTypeEnum::PaymentHandler) {
+ *out_type = PermissionType::PAYMENT_HANDLER;
+ } else {
+ return Response::InvalidParams("Unknown permission type: " + type);
+ }
+ return Response::OK();
+}
+
} // namespace
Response BrowserHandler::GetHistograms(
@@ -101,6 +164,72 @@ Response BrowserHandler::GetHistograms(
return Response::OK();
}
+Response BrowserHandler::FindBrowserContext(
+ const Maybe<std::string>& browser_context_id,
+ BrowserContext** browser_context) {
+ DevToolsManagerDelegate* delegate =
+ DevToolsManager::GetInstance()->delegate();
+ if (!delegate)
+ return Response::Error("Browser context management is not supported.");
+ if (!browser_context_id.isJust()) {
+ *browser_context = delegate->GetDefaultBrowserContext();
+ if (*browser_context == nullptr)
+ return Response::Error("Browser context management is not supported.");
+ return Response::OK();
+ }
+
+ std::string context_id = browser_context_id.fromJust();
+ for (auto* context : delegate->GetBrowserContexts()) {
+ if (context->UniqueId() == context_id) {
+ *browser_context = context;
+ return Response::OK();
+ }
+ }
+ return Response::InvalidParams("Failed to find browser context for id " +
+ context_id);
+}
+
+Response BrowserHandler::GrantPermissions(
+ const std::string& origin,
+ std::unique_ptr<protocol::Array<protocol::Browser::PermissionType>>
+ permissions,
+ Maybe<std::string> browser_context_id) {
+ BrowserContext* browser_context = nullptr;
+ Response response = FindBrowserContext(browser_context_id, &browser_context);
+ if (!response.isSuccess())
+ return response;
+ PermissionControllerImpl::PermissionOverrides overrides;
+ for (size_t i = 0; i < permissions->length(); ++i) {
+ PermissionType type;
+ Response type_response =
+ FromProtocolPermissionType(permissions->get(i), &type);
+ if (!type_response.isSuccess())
+ return type_response;
+ overrides.insert(type);
+ }
+
+ PermissionControllerImpl* permission_controller =
+ PermissionControllerImpl::FromBrowserContext(browser_context);
+ GURL url = GURL(origin).GetOrigin();
+ permission_controller->SetPermissionOverridesForDevTools(url, overrides);
+ contexts_with_overridden_permissions_.insert(
+ browser_context_id.fromMaybe(""));
+ return Response::OK();
+}
+
+Response BrowserHandler::ResetPermissions(
+ Maybe<std::string> browser_context_id) {
+ BrowserContext* browser_context = nullptr;
+ Response response = FindBrowserContext(browser_context_id, &browser_context);
+ if (!response.isSuccess())
+ return response;
+ PermissionControllerImpl* permission_controller =
+ PermissionControllerImpl::FromBrowserContext(browser_context);
+ permission_controller->ResetPermissionOverridesForDevTools();
+ contexts_with_overridden_permissions_.erase(browser_context_id.fromMaybe(""));
+ return Response::OK();
+}
+
Response BrowserHandler::GetHistogram(
const std::string& in_name,
const Maybe<bool> in_delta,
@@ -119,8 +248,8 @@ Response BrowserHandler::GetHistogram(
}
Response BrowserHandler::GetBrowserCommandLine(
- std::unique_ptr<protocol::Array<String>>* arguments) {
- *arguments = protocol::Array<String>::create();
+ std::unique_ptr<protocol::Array<std::string>>* arguments) {
+ *arguments = protocol::Array<std::string>::create();
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
// The commandline is potentially sensitive, only return it if it
// contains kEnableAutomation.
diff --git a/chromium/content/browser/devtools/protocol/browser_handler.h b/chromium/content/browser/devtools/protocol/browser_handler.h
index 9ced0243186..5175b0ffb41 100644
--- a/chromium/content/browser/devtools/protocol/browser_handler.h
+++ b/chromium/content/browser/devtools/protocol/browser_handler.h
@@ -5,11 +5,15 @@
#ifndef CONTENT_BROWSER_DEVTOOLS_PROTOCOL_BROWSER_HANDLER_H_
#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_BROWSER_HANDLER_H_
+#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "content/browser/devtools/protocol/browser.h"
#include "content/browser/devtools/protocol/devtools_domain_handler.h"
namespace content {
+
+class BrowserContext;
+
namespace protocol {
class BrowserHandler : public DevToolsDomainHandler, public Browser::Backend {
@@ -19,6 +23,8 @@ class BrowserHandler : public DevToolsDomainHandler, public Browser::Backend {
void Wire(UberDispatcher* dispatcher) override;
+ Response Disable() override;
+
// Protocol methods.
Response GetVersion(std::string* protocol_version,
std::string* product,
@@ -37,9 +43,22 @@ class BrowserHandler : public DevToolsDomainHandler, public Browser::Backend {
std::unique_ptr<Browser::Histogram>* out_histogram) override;
Response GetBrowserCommandLine(
- std::unique_ptr<protocol::Array<String>>* arguments) override;
+ std::unique_ptr<protocol::Array<std::string>>* arguments) override;
+
+ Response GrantPermissions(
+ const std::string& origin,
+ std::unique_ptr<protocol::Array<protocol::Browser::PermissionType>>
+ permissions,
+ Maybe<std::string> browser_context_id) override;
+
+ Response ResetPermissions(Maybe<std::string> browser_context_id) override;
private:
+ Response FindBrowserContext(const Maybe<std::string>& browser_context_id,
+ BrowserContext** browser_context);
+
+ base::flat_set<std::string> contexts_with_overridden_permissions_;
+
DISALLOW_COPY_AND_ASSIGN(BrowserHandler);
};
diff --git a/chromium/content/browser/devtools/protocol/devtools_download_manager_delegate.cc b/chromium/content/browser/devtools/protocol/devtools_download_manager_delegate.cc
index f71a5bf4ab3..bfaa525d37e 100644
--- a/chromium/content/browser/devtools/protocol/devtools_download_manager_delegate.cc
+++ b/chromium/content/browser/devtools/protocol/devtools_download_manager_delegate.cc
@@ -6,7 +6,7 @@
#include "base/bind.h"
#include "base/files/file_util.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/threading/thread_restrictions.h"
#include "content/browser/devtools/protocol/devtools_download_manager_helper.h"
#include "content/public/browser/browser_context.h"
diff --git a/chromium/content/browser/devtools/protocol/devtools_download_manager_helper.cc b/chromium/content/browser/devtools/protocol/devtools_download_manager_helper.cc
index d1b63f6f571..736caf3b557 100644
--- a/chromium/content/browser/devtools/protocol/devtools_download_manager_helper.cc
+++ b/chromium/content/browser/devtools/protocol/devtools_download_manager_helper.cc
@@ -6,9 +6,6 @@
#include "base/bind.h"
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(
- content::protocol::DevToolsDownloadManagerHelper);
-
namespace content {
namespace protocol {
diff --git a/chromium/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/chromium/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
index aa29868d07d..c66b3c9454a 100644
--- a/chromium/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/chromium/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -11,12 +11,8 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
-#include "base/json/json_reader.h"
-#include "base/json/json_writer.h"
#include "base/logging.h"
-#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
#include "base/sys_info.h"
#include "base/values.h"
#include "build/build_config.h"
@@ -24,13 +20,13 @@
#include "components/download/public/common/download_file_impl.h"
#include "components/download/public/common/download_task_runner.h"
#include "content/browser/devtools/protocol/devtools_download_manager_delegate.h"
+#include "content/browser/devtools/protocol/devtools_protocol_test_support.h"
#include "content/browser/download/download_manager_impl.h"
#include "content/browser/frame_host/interstitial_page_impl.h"
#include "content/browser/frame_host/navigator.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/download_manager.h"
#include "content/public/browser/interstitial_page_delegate.h"
#include "content/public/browser/javascript_dialog_manager.h"
@@ -46,7 +42,6 @@
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test_utils.h"
-#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/download_test_observer.h"
#include "content/public/test/slow_download_http_response.h"
@@ -55,10 +50,6 @@
#include "content/shell/browser/shell_browser_context.h"
#include "content/shell/browser/shell_content_browser_client.h"
#include "content/shell/browser/shell_download_manager_delegate.h"
-#include "content/test/content_browser_test_utils_internal.h"
-#include "net/dns/mock_host_resolver.h"
-#include "net/test/cert_test_util.h"
-#include "net/test/embedded_test_server/embedded_test_server.h"
#include "services/network/public/cpp/features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -84,10 +75,6 @@ namespace content {
namespace {
-const char kIdParam[] = "id";
-const char kMethodParam[] = "method";
-const char kParamsParam[] = "params";
-
// If |params| contains an explanation with a non-empty certificate list,
// returns true and points |certificate| to the certificate list of the first
// explanation that contains a nonempty certificate list. Otherwise returns
@@ -178,326 +165,6 @@ class TestJavaScriptDialogManager : public JavaScriptDialogManager,
} // namespace
-class DevToolsProtocolTest : public ContentBrowserTest,
- public DevToolsAgentHostClient,
- public WebContentsDelegate {
- public:
- typedef base::Callback<bool(base::DictionaryValue*)> NotificationMatcher;
-
- DevToolsProtocolTest()
- : last_sent_id_(0),
- waiting_for_command_result_id_(0),
- in_dispatch_(false),
- agent_host_can_close_(false) {}
-
- void SetUpOnMainThread() override {
- host_resolver()->AddRule("*", "127.0.0.1");
- }
-
- protected:
- // WebContentsDelegate methods:
- bool DidAddMessageToConsole(WebContents* source,
- int32_t level,
- const base::string16& message,
- int32_t line_no,
- const base::string16& source_id) override {
- console_messages_.push_back(base::UTF16ToUTF8(message));
- return true;
- }
-
- blink::WebSecurityStyle GetSecurityStyle(
- content::WebContents* web_contents,
- content::SecurityStyleExplanations* security_style_explanations)
- override {
- security_style_explanations->secure_explanations.push_back(
- SecurityStyleExplanation(
- "an explanation title", "an explanation summary",
- "an explanation description", cert_,
- blink::WebMixedContentContextType::kNotMixedContent));
- return blink::kWebSecurityStyleNeutral;
- }
-
- base::DictionaryValue* SendCommand(
- const std::string& method,
- std::unique_ptr<base::DictionaryValue> params) {
- return SendCommand(method, std::move(params), true);
- }
-
- base::DictionaryValue* SendCommand(
- const std::string& method,
- std::unique_ptr<base::DictionaryValue> params,
- bool wait) {
- in_dispatch_ = true;
- base::DictionaryValue command;
- command.SetInteger(kIdParam, ++last_sent_id_);
- command.SetString(kMethodParam, method);
- if (params)
- command.Set(kParamsParam, std::move(params));
-
- std::string json_command;
- base::JSONWriter::Write(command, &json_command);
- agent_host_->DispatchProtocolMessage(this, json_command);
- // Some messages are dispatched synchronously.
- // Only run loop if we are not finished yet.
- if (in_dispatch_ && wait) {
- WaitForResponse();
- in_dispatch_ = false;
- return result_.get();
- }
- in_dispatch_ = false;
- return result_.get();
- }
-
- void WaitForResponse() {
- waiting_for_command_result_id_ = last_sent_id_;
- base::RunLoop().Run();
- }
-
- bool HasValue(const std::string& path) {
- base::Value* value = nullptr;
- return result_->Get(path, &value);
- }
-
- bool HasListItem(const std::string& path_to_list,
- const std::string& name,
- const std::string& value) {
- base::ListValue* list;
- if (!result_->GetList(path_to_list, &list))
- return false;
-
- for (size_t i = 0; i != list->GetSize(); i++) {
- base::DictionaryValue* item;
- if (!list->GetDictionary(i, &item))
- return false;
- std::string id;
- if (!item->GetString(name, &id))
- return false;
- if (id == value)
- return true;
- }
- return false;
- }
-
- void Attach() {
- agent_host_ = DevToolsAgentHost::GetOrCreateFor(shell()->web_contents());
- agent_host_->AttachClient(this);
- shell()->web_contents()->SetDelegate(this);
- }
-
- void AttachToBrowserTarget() {
- // Tethering domain is not used in tests.
- agent_host_ = DevToolsAgentHost::CreateForBrowser(
- nullptr, DevToolsAgentHost::CreateServerSocketCallback());
- agent_host_->AttachClient(this);
- shell()->web_contents()->SetDelegate(this);
- }
-
- void Detach() {
- if (agent_host_) {
- agent_host_->DetachClient(this);
- agent_host_ = nullptr;
- }
- }
-
- void TearDownOnMainThread() override { Detach(); }
-
- std::unique_ptr<base::DictionaryValue> WaitForNotification(
- const std::string& notification) {
- return WaitForNotification(notification, false);
- }
-
- std::unique_ptr<base::DictionaryValue> WaitForNotification(
- const std::string& notification,
- bool allow_existing) {
- if (allow_existing) {
- for (size_t i = 0; i < notifications_.size(); i++) {
- if (notifications_[i] == notification) {
- std::unique_ptr<base::DictionaryValue> result =
- std::move(notification_params_[i]);
- notifications_.erase(notifications_.begin() + i);
- notification_params_.erase(notification_params_.begin() + i);
- return result;
- }
- }
- }
-
- waiting_for_notification_ = notification;
- RunMessageLoop();
- return std::move(waiting_for_notification_params_);
- }
-
- // Waits for a notification whose params, when passed to |matcher|, returns
- // true. Existing notifications are allowed.
- std::unique_ptr<base::DictionaryValue> WaitForMatchingNotification(
- const std::string& notification,
- const NotificationMatcher& matcher) {
- for (size_t i = 0; i < notifications_.size(); i++) {
- if (notifications_[i] == notification &&
- matcher.Run(notification_params_[i].get())) {
- std::unique_ptr<base::DictionaryValue> result =
- std::move(notification_params_[i]);
- notifications_.erase(notifications_.begin() + i);
- notification_params_.erase(notification_params_.begin() + i);
- return result;
- }
- }
-
- waiting_for_notification_ = notification;
- waiting_for_notification_matcher_ = matcher;
- RunMessageLoop();
- return std::move(waiting_for_notification_params_);
- }
-
- void ClearNotifications() {
- notifications_.clear();
- notification_params_.clear();
- }
-
- struct ExpectedNavigation {
- std::string url;
- bool is_redirect;
- bool abort;
- };
-
- std::string RemovePort(const GURL& url) {
- GURL::Replacements remove_port;
- remove_port.ClearPort();
- return url.ReplaceComponents(remove_port).spec();
- }
-
- // Waits for the expected navigations to occur in any order. If an expected
- // navigation occurs, Network.continueInterceptedRequest is called with the
- // specified navigation_response to either allow it to proceed or to cancel
- // it.
- void ProcessNavigationsAnyOrder(
- std::vector<ExpectedNavigation> expected_navigations) {
- std::unique_ptr<base::DictionaryValue> params;
- while (!expected_navigations.empty()) {
- std::unique_ptr<base::DictionaryValue> params =
- WaitForNotification("Network.requestIntercepted");
-
- std::string interception_id;
- ASSERT_TRUE(params->GetString("interceptionId", &interception_id));
- bool is_redirect = params->HasKey("redirectUrl");
- bool is_navigation;
- ASSERT_TRUE(params->GetBoolean("isNavigationRequest", &is_navigation));
- std::string resource_type;
- ASSERT_TRUE(params->GetString("resourceType", &resource_type));
- std::string url;
- ASSERT_TRUE(params->GetString("request.url", &url));
- if (is_redirect)
- ASSERT_TRUE(params->GetString("redirectUrl", &url));
- // The url will typically have a random port which we want to remove.
- url = RemovePort(GURL(url));
-
- if (!is_navigation) {
- params.reset(new base::DictionaryValue());
- params->SetString("interceptionId", interception_id);
- SendCommand("Network.continueInterceptedRequest", std::move(params),
- false);
- continue;
- }
-
- bool navigation_was_expected = false;
- for (auto it = expected_navigations.begin();
- it != expected_navigations.end(); it++) {
- if (url != it->url || is_redirect != it->is_redirect)
- continue;
-
- params.reset(new base::DictionaryValue());
- params->SetString("interceptionId", interception_id);
- if (it->abort)
- params->SetString("errorReason", "Aborted");
- SendCommand("Network.continueInterceptedRequest", std::move(params),
- false);
-
- navigation_was_expected = true;
- expected_navigations.erase(it);
- break;
- }
- EXPECT_TRUE(navigation_was_expected)
- << "url = " << url << "is_redirect = " << is_redirect;
- }
- }
-
- std::vector<std::string> GetAllFrameUrls() {
- std::vector<std::string> urls;
- for (RenderFrameHost* render_frame_host :
- shell()->web_contents()->GetAllFrames()) {
- urls.push_back(RemovePort(render_frame_host->GetLastCommittedURL()));
- }
- return urls;
- }
-
- void set_agent_host_can_close() { agent_host_can_close_ = true; }
-
- void SetSecurityExplanationCert(
- const scoped_refptr<net::X509Certificate>& cert) {
- cert_ = cert;
- }
-
- std::unique_ptr<base::DictionaryValue> result_;
- scoped_refptr<DevToolsAgentHost> agent_host_;
- int last_sent_id_;
- std::vector<int> result_ids_;
- std::vector<std::string> notifications_;
- std::vector<std::string> console_messages_;
- std::vector<std::unique_ptr<base::DictionaryValue>> notification_params_;
-
- private:
- void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
- const std::string& message) override {
- std::unique_ptr<base::DictionaryValue> root(
- static_cast<base::DictionaryValue*>(
- base::JSONReader::Read(message).release()));
- int id;
- if (root->GetInteger("id", &id)) {
- result_ids_.push_back(id);
- base::DictionaryValue* result;
- ASSERT_TRUE(root->GetDictionary("result", &result));
- result_.reset(result->DeepCopy());
- in_dispatch_ = false;
- if (id && id == waiting_for_command_result_id_) {
- waiting_for_command_result_id_ = 0;
- base::RunLoop::QuitCurrentDeprecated();
- }
- } else {
- std::string notification;
- EXPECT_TRUE(root->GetString("method", &notification));
- notifications_.push_back(notification);
- base::DictionaryValue* params;
- if (root->GetDictionary("params", &params)) {
- notification_params_.push_back(params->CreateDeepCopy());
- } else {
- notification_params_.push_back(
- base::WrapUnique(new base::DictionaryValue()));
- }
- if (waiting_for_notification_ == notification &&
- (waiting_for_notification_matcher_.is_null() ||
- waiting_for_notification_matcher_.Run(
- notification_params_[notification_params_.size() - 1].get()))) {
- waiting_for_notification_ = std::string();
- waiting_for_notification_matcher_ = NotificationMatcher();
- waiting_for_notification_params_ = base::WrapUnique(
- notification_params_[notification_params_.size() - 1]->DeepCopy());
- base::RunLoop::QuitCurrentDeprecated();
- }
- }
- }
-
- void AgentHostClosed(DevToolsAgentHost* agent_host) override {
- if (!agent_host_can_close_)
- NOTREACHED();
- }
-
- std::string waiting_for_notification_;
- NotificationMatcher waiting_for_notification_matcher_;
- std::unique_ptr<base::DictionaryValue> waiting_for_notification_params_;
- int waiting_for_command_result_id_;
- bool in_dispatch_;
- bool agent_host_can_close_;
- scoped_refptr<net::X509Certificate> cert_;
-};
class TestInterstitialDelegate : public InterstitialPageDelegate {
private:
@@ -2438,7 +2105,7 @@ class DevToolsDownloadContentTest : public DevToolsProtocolTest {
std::string file_contents;
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_during_test_verification;
+ base::ScopedAllowBlockingForTesting allow_blocking;
bool read = base::ReadFileToString(path, &file_contents);
EXPECT_TRUE(read) << "Failed reading file: " << path.value() << std::endl;
if (!read)
diff --git a/chromium/content/browser/devtools/protocol/devtools_protocol_test_support.cc b/chromium/content/browser/devtools/protocol/devtools_protocol_test_support.cc
new file mode 100644
index 00000000000..41ba4bc6448
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/devtools_protocol_test_support.cc
@@ -0,0 +1,285 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/devtools/protocol/devtools_protocol_test_support.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/security_style_explanations.h"
+#include "content/public/test/test_utils.h"
+#include "content/shell/browser/shell.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+
+namespace content {
+
+namespace {
+
+const char kIdParam[] = "id";
+const char kMethodParam[] = "method";
+const char kParamsParam[] = "params";
+
+} // namespace
+
+DevToolsProtocolTest::DevToolsProtocolTest()
+ : last_sent_id_(0),
+ waiting_for_command_result_id_(0),
+ in_dispatch_(false),
+ agent_host_can_close_(false) {}
+
+DevToolsProtocolTest::~DevToolsProtocolTest() = default;
+
+void DevToolsProtocolTest::SetUpOnMainThread() {
+ host_resolver()->AddRule("*", "127.0.0.1");
+}
+
+bool DevToolsProtocolTest::DidAddMessageToConsole(
+ WebContents* source,
+ int32_t level,
+ const base::string16& message,
+ int32_t line_no,
+ const base::string16& source_id) {
+ console_messages_.push_back(base::UTF16ToUTF8(message));
+ return true;
+}
+
+base::DictionaryValue* DevToolsProtocolTest::SendCommand(
+ const std::string& method,
+ std::unique_ptr<base::DictionaryValue> params,
+ bool wait) {
+ in_dispatch_ = true;
+ base::DictionaryValue command;
+ command.SetInteger(kIdParam, ++last_sent_id_);
+ command.SetString(kMethodParam, method);
+ if (params)
+ command.Set(kParamsParam, std::move(params));
+
+ std::string json_command;
+ base::JSONWriter::Write(command, &json_command);
+ agent_host_->DispatchProtocolMessage(this, json_command);
+ // Some messages are dispatched synchronously.
+ // Only run loop if we are not finished yet.
+ if (in_dispatch_ && wait) {
+ WaitForResponse();
+ in_dispatch_ = false;
+ return result_.get();
+ }
+ in_dispatch_ = false;
+ return result_.get();
+}
+
+void DevToolsProtocolTest::WaitForResponse() {
+ waiting_for_command_result_id_ = last_sent_id_;
+ RunLoopUpdatingQuitClosure();
+}
+
+bool DevToolsProtocolTest::HasValue(const std::string& path) {
+ base::Value* value = nullptr;
+ return result_->Get(path, &value);
+}
+
+bool DevToolsProtocolTest::HasListItem(const std::string& path_to_list,
+ const std::string& name,
+ const std::string& value) {
+ base::ListValue* list;
+ if (!result_->GetList(path_to_list, &list))
+ return false;
+
+ for (size_t i = 0; i != list->GetSize(); i++) {
+ base::DictionaryValue* item;
+ if (!list->GetDictionary(i, &item))
+ return false;
+ std::string id;
+ if (!item->GetString(name, &id))
+ return false;
+ if (id == value)
+ return true;
+ }
+ return false;
+}
+
+void DevToolsProtocolTest::Attach() {
+ agent_host_ = DevToolsAgentHost::GetOrCreateFor(shell()->web_contents());
+ agent_host_->AttachClient(this);
+ shell()->web_contents()->SetDelegate(this);
+}
+
+void DevToolsProtocolTest::AttachToBrowserTarget() {
+ // Tethering domain is not used in tests.
+ agent_host_ = DevToolsAgentHost::CreateForBrowser(
+ nullptr, DevToolsAgentHost::CreateServerSocketCallback());
+ agent_host_->AttachClient(this);
+ shell()->web_contents()->SetDelegate(this);
+}
+
+void DevToolsProtocolTest::TearDownOnMainThread() {
+ Detach();
+}
+
+std::unique_ptr<base::DictionaryValue>
+DevToolsProtocolTest::WaitForNotification(const std::string& notification,
+ bool allow_existing) {
+ if (allow_existing) {
+ for (size_t i = 0; i < notifications_.size(); i++) {
+ if (notifications_[i] == notification) {
+ std::unique_ptr<base::DictionaryValue> result =
+ std::move(notification_params_[i]);
+ notifications_.erase(notifications_.begin() + i);
+ notification_params_.erase(notification_params_.begin() + i);
+ return result;
+ }
+ }
+ }
+
+ waiting_for_notification_ = notification;
+ RunLoopUpdatingQuitClosure();
+ return std::move(waiting_for_notification_params_);
+}
+
+blink::WebSecurityStyle DevToolsProtocolTest::GetSecurityStyle(
+ content::WebContents* web_contents,
+ content::SecurityStyleExplanations* security_style_explanations) {
+ security_style_explanations->secure_explanations.push_back(
+ SecurityStyleExplanation(
+ "an explanation title", "an explanation summary",
+ "an explanation description", cert_,
+ blink::WebMixedContentContextType::kNotMixedContent));
+ return blink::kWebSecurityStyleNeutral;
+}
+
+std::unique_ptr<base::DictionaryValue>
+DevToolsProtocolTest::WaitForMatchingNotification(
+ const std::string& notification,
+ const NotificationMatcher& matcher) {
+ for (size_t i = 0; i < notifications_.size(); i++) {
+ if (notifications_[i] == notification &&
+ matcher.Run(notification_params_[i].get())) {
+ std::unique_ptr<base::DictionaryValue> result =
+ std::move(notification_params_[i]);
+ notifications_.erase(notifications_.begin() + i);
+ notification_params_.erase(notification_params_.begin() + i);
+ return result;
+ }
+ }
+
+ waiting_for_notification_ = notification;
+ waiting_for_notification_matcher_ = matcher;
+ RunLoopUpdatingQuitClosure();
+ return std::move(waiting_for_notification_params_);
+}
+
+void DevToolsProtocolTest::ProcessNavigationsAnyOrder(
+ std::vector<ExpectedNavigation> expected_navigations) {
+ std::unique_ptr<base::DictionaryValue> params;
+ while (!expected_navigations.empty()) {
+ std::unique_ptr<base::DictionaryValue> params =
+ WaitForNotification("Network.requestIntercepted");
+
+ std::string interception_id;
+ ASSERT_TRUE(params->GetString("interceptionId", &interception_id));
+ bool is_redirect = params->HasKey("redirectUrl");
+ bool is_navigation;
+ ASSERT_TRUE(params->GetBoolean("isNavigationRequest", &is_navigation));
+ std::string resource_type;
+ ASSERT_TRUE(params->GetString("resourceType", &resource_type));
+ std::string url;
+ ASSERT_TRUE(params->GetString("request.url", &url));
+ if (is_redirect)
+ ASSERT_TRUE(params->GetString("redirectUrl", &url));
+ // The url will typically have a random port which we want to remove.
+ url = RemovePort(GURL(url));
+
+ if (!is_navigation) {
+ params.reset(new base::DictionaryValue());
+ params->SetString("interceptionId", interception_id);
+ SendCommand("Network.continueInterceptedRequest", std::move(params),
+ false);
+ continue;
+ }
+
+ bool navigation_was_expected = false;
+ for (auto it = expected_navigations.begin();
+ it != expected_navigations.end(); it++) {
+ if (url != it->url || is_redirect != it->is_redirect)
+ continue;
+
+ params.reset(new base::DictionaryValue());
+ params->SetString("interceptionId", interception_id);
+ if (it->abort)
+ params->SetString("errorReason", "Aborted");
+ SendCommand("Network.continueInterceptedRequest", std::move(params),
+ false);
+
+ navigation_was_expected = true;
+ expected_navigations.erase(it);
+ break;
+ }
+ EXPECT_TRUE(navigation_was_expected)
+ << "url = " << url << "is_redirect = " << is_redirect;
+ }
+}
+
+void DevToolsProtocolTest::RunLoopUpdatingQuitClosure() {
+ base::RunLoop run_loop;
+ run_loop_quit_closure_ = run_loop.QuitClosure();
+ run_loop.Run();
+}
+
+void DevToolsProtocolTest::DispatchProtocolMessage(
+ DevToolsAgentHost* agent_host,
+ const std::string& message) {
+ std::unique_ptr<base::DictionaryValue> root(
+ static_cast<base::DictionaryValue*>(
+ base::JSONReader::Read(message).release()));
+ int id;
+ if (root->GetInteger("id", &id)) {
+ result_ids_.push_back(id);
+ base::DictionaryValue* result;
+ ASSERT_TRUE(root->GetDictionary("result", &result));
+ result_.reset(result->DeepCopy());
+ in_dispatch_ = false;
+ if (id && id == waiting_for_command_result_id_) {
+ waiting_for_command_result_id_ = 0;
+ std::move(run_loop_quit_closure_).Run();
+ }
+ } else {
+ std::string notification;
+ EXPECT_TRUE(root->GetString("method", &notification));
+ notifications_.push_back(notification);
+ base::DictionaryValue* params;
+ if (root->GetDictionary("params", &params)) {
+ notification_params_.push_back(params->CreateDeepCopy());
+ } else {
+ notification_params_.push_back(
+ base::WrapUnique(new base::DictionaryValue()));
+ }
+ if (waiting_for_notification_ == notification &&
+ (waiting_for_notification_matcher_.is_null() ||
+ waiting_for_notification_matcher_.Run(
+ notification_params_[notification_params_.size() - 1].get()))) {
+ waiting_for_notification_ = std::string();
+ waiting_for_notification_matcher_ = NotificationMatcher();
+ waiting_for_notification_params_ = base::WrapUnique(
+ notification_params_[notification_params_.size() - 1]->DeepCopy());
+ std::move(run_loop_quit_closure_).Run();
+ }
+ }
+}
+
+std::vector<std::string> DevToolsProtocolTest::GetAllFrameUrls() {
+ std::vector<std::string> urls;
+ for (RenderFrameHost* render_frame_host :
+ shell()->web_contents()->GetAllFrames()) {
+ urls.push_back(RemovePort(render_frame_host->GetLastCommittedURL()));
+ }
+ return urls;
+}
+
+void DevToolsProtocolTest::AgentHostClosed(DevToolsAgentHost* agent_host) {
+ if (!agent_host_can_close_)
+ NOTREACHED();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/devtools_protocol_test_support.h b/chromium/content/browser/devtools/protocol/devtools_protocol_test_support.h
new file mode 100644
index 00000000000..15e5d23afce
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/devtools_protocol_test_support.h
@@ -0,0 +1,150 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_TEST_SUPPORT_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_TEST_SUPPORT_H_
+
+#include <memory>
+#include <string>
+#include "base/callback.h"
+#include "base/values.h"
+#include "content/public/browser/devtools_agent_host.h"
+#include "content/public/browser/web_contents_delegate.h"
+#include "content/public/test/content_browser_test.h"
+#include "net/test/cert_test_util.h"
+
+namespace content {
+
+class DevToolsProtocolTest : public ContentBrowserTest,
+ public DevToolsAgentHostClient,
+ public WebContentsDelegate {
+ public:
+ typedef base::RepeatingCallback<bool(base::DictionaryValue*)>
+ NotificationMatcher;
+
+ DevToolsProtocolTest();
+ ~DevToolsProtocolTest() override;
+
+ void SetUpOnMainThread() override;
+
+ protected:
+ // WebContentsDelegate methods:
+ bool DidAddMessageToConsole(WebContents* source,
+ int32_t level,
+ const base::string16& message,
+ int32_t line_no,
+ const base::string16& source_id) override;
+
+ blink::WebSecurityStyle GetSecurityStyle(
+ content::WebContents* web_contents,
+ content::SecurityStyleExplanations* security_style_explanations) override;
+
+ base::DictionaryValue* SendCommand(
+ const std::string& method,
+ std::unique_ptr<base::DictionaryValue> params) {
+ return SendCommand(method, std::move(params), true);
+ }
+
+ base::DictionaryValue* SendCommand(
+ const std::string& method,
+ std::unique_ptr<base::DictionaryValue> params,
+ bool wait);
+
+ void WaitForResponse();
+
+ bool HasValue(const std::string& path);
+
+ bool HasListItem(const std::string& path_to_list,
+ const std::string& name,
+ const std::string& value);
+
+ void Attach();
+
+ void AttachToBrowserTarget();
+
+ void Detach() {
+ if (agent_host_) {
+ agent_host_->DetachClient(this);
+ agent_host_ = nullptr;
+ }
+ }
+
+ void TearDownOnMainThread() override;
+
+ std::unique_ptr<base::DictionaryValue> WaitForNotification(
+ const std::string& notification) {
+ return WaitForNotification(notification, false);
+ }
+
+ std::unique_ptr<base::DictionaryValue> WaitForNotification(
+ const std::string& notification,
+ bool allow_existing);
+
+ // Waits for a notification whose params, when passed to |matcher|, returns
+ // true. Existing notifications are allowed.
+ std::unique_ptr<base::DictionaryValue> WaitForMatchingNotification(
+ const std::string& notification,
+ const NotificationMatcher& matcher);
+
+ void ClearNotifications() {
+ notifications_.clear();
+ notification_params_.clear();
+ }
+
+ struct ExpectedNavigation {
+ std::string url;
+ bool is_redirect;
+ bool abort;
+ };
+
+ std::string RemovePort(const GURL& url) {
+ GURL::Replacements remove_port;
+ remove_port.ClearPort();
+ return url.ReplaceComponents(remove_port).spec();
+ }
+
+ // Waits for the expected navigations to occur in any order. If an expected
+ // navigation occurs, Network.continueInterceptedRequest is called with the
+ // specified navigation_response to either allow it to proceed or to cancel
+ // it.
+ void ProcessNavigationsAnyOrder(
+ std::vector<ExpectedNavigation> expected_navigations);
+
+ std::vector<std::string> GetAllFrameUrls();
+
+ void set_agent_host_can_close() { agent_host_can_close_ = true; }
+
+ void SetSecurityExplanationCert(
+ const scoped_refptr<net::X509Certificate>& cert) {
+ cert_ = cert;
+ }
+
+ std::unique_ptr<base::DictionaryValue> result_;
+ scoped_refptr<DevToolsAgentHost> agent_host_;
+ int last_sent_id_;
+ std::vector<int> result_ids_;
+ std::vector<std::string> notifications_;
+ std::vector<std::string> console_messages_;
+ std::vector<std::unique_ptr<base::DictionaryValue>> notification_params_;
+
+ private:
+ void RunLoopUpdatingQuitClosure();
+ void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
+ const std::string& message) override;
+
+ void AgentHostClosed(DevToolsAgentHost* agent_host) override;
+
+ std::string waiting_for_notification_;
+ NotificationMatcher waiting_for_notification_matcher_;
+ std::unique_ptr<base::DictionaryValue> waiting_for_notification_params_;
+ int waiting_for_command_result_id_;
+ bool in_dispatch_;
+ bool agent_host_can_close_;
+ scoped_refptr<net::X509Certificate> cert_;
+ base::OnceClosure run_loop_quit_closure_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_TEST_SUPPORT_H_
diff --git a/chromium/content/browser/devtools/protocol/input_handler.cc b/chromium/content/browser/devtools/protocol/input_handler.cc
index e6b74e54193..d89856b04b3 100644
--- a/chromium/content/browser/devtools/protocol/input_handler.cc
+++ b/chromium/content/browser/devtools/protocol/input_handler.cc
@@ -19,11 +19,13 @@
#include "content/common/input/synthetic_pinch_gesture_params.h"
#include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
#include "content/common/input/synthetic_tap_gesture_params.h"
+#include "content/public/browser/web_contents.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/blink/web_input_event_traits.h"
#include "ui/events/gesture_detection/gesture_provider_config_helper.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/range/range.h"
namespace content {
namespace protocol {
@@ -421,11 +423,18 @@ void InputHandler::SetRenderer(int process_host_id,
if (frame_host == host_)
return;
ClearInputState();
- if (host_ && ignore_input_events_)
- host_->GetRenderWidgetHost()->SetIgnoreInputEvents(false);
+
+ WebContents* old_web_contents = WebContents::FromRenderFrameHost(host_);
+ WebContents* new_web_contents = WebContents::FromRenderFrameHost(frame_host);
+
host_ = frame_host;
- if (host_ && ignore_input_events_)
- host_->GetRenderWidgetHost()->SetIgnoreInputEvents(true);
+
+ if (ignore_input_events_ && old_web_contents != new_web_contents) {
+ if (old_web_contents)
+ old_web_contents->SetIgnoreInputEvents(false);
+ if (new_web_contents)
+ new_web_contents->SetIgnoreInputEvents(true);
+ }
}
void InputHandler::Wire(UberDispatcher* dispatcher) {
@@ -438,8 +447,9 @@ void InputHandler::OnPageScaleFactorChanged(float page_scale_factor) {
Response InputHandler::Disable() {
ClearInputState();
- if (host_ && ignore_input_events_)
- host_->GetRenderWidgetHost()->SetIgnoreInputEvents(false);
+ WebContents* web_contents = WebContents::FromRenderFrameHost(host_);
+ if (web_contents && ignore_input_events_)
+ web_contents->SetIgnoreInputEvents(false);
ignore_input_events_ = false;
touch_points_.clear();
return Response::OK();
@@ -535,6 +545,31 @@ void InputHandler::DispatchKeyEvent(
EnsureInjector(widget_host)->InjectKeyboardEvent(event, std::move(callback));
}
+void InputHandler::InsertText(const std::string& text,
+ std::unique_ptr<InsertTextCallback> callback) {
+ base::string16 text16 = base::UTF8ToUTF16(text);
+ base::OnceClosure closure =
+ base::BindOnce(&InsertTextCallback::sendSuccess, std::move(callback));
+
+ if (!host_ || !host_->GetRenderWidgetHost()) {
+ callback->sendFailure(Response::InternalError());
+ return;
+ }
+
+ RenderWidgetHostImpl* widget_host = host_->GetRenderWidgetHost();
+ if (!host_->GetParent() && widget_host->delegate()) {
+ RenderWidgetHostImpl* target_host =
+ widget_host->delegate()->GetFocusedRenderWidgetHost(widget_host);
+ if (target_host)
+ widget_host = target_host;
+ }
+
+ widget_host->Focus();
+ widget_host->GetWidgetInputHandler()->ImeCommitText(
+ text16, std::vector<ui::ImeTextSpan>(), gfx::Range::InvalidRange(), 0,
+ std::move(closure));
+}
+
void InputHandler::DispatchMouseEvent(
const std::string& event_type,
double x,
@@ -832,8 +867,9 @@ Response InputHandler::EmulateTouchFromMouseEvent(const std::string& type,
Response InputHandler::SetIgnoreInputEvents(bool ignore) {
ignore_input_events_ = ignore;
- if (host_)
- host_->GetRenderWidgetHost()->SetIgnoreInputEvents(ignore);
+ WebContents* web_contents = WebContents::FromRenderFrameHost(host_);
+ if (web_contents)
+ web_contents->SetIgnoreInputEvents(ignore);
return Response::OK();
}
diff --git a/chromium/content/browser/devtools/protocol/input_handler.h b/chromium/content/browser/devtools/protocol/input_handler.h
index ae8fd55904c..293b7765a86 100644
--- a/chromium/content/browser/devtools/protocol/input_handler.h
+++ b/chromium/content/browser/devtools/protocol/input_handler.h
@@ -56,6 +56,9 @@ class InputHandler : public DevToolsDomainHandler, public Input::Backend {
Maybe<int> location,
std::unique_ptr<DispatchKeyEventCallback> callback) override;
+ void InsertText(const std::string& text,
+ std::unique_ptr<InsertTextCallback> callback) override;
+
void DispatchMouseEvent(
const std::string& type,
double x,
diff --git a/chromium/content/browser/devtools/protocol/memory_handler.cc b/chromium/content/browser/devtools/protocol/memory_handler.cc
index 06a5638dab3..328ecd8aeea 100644
--- a/chromium/content/browser/devtools/protocol/memory_handler.cc
+++ b/chromium/content/browser/devtools/protocol/memory_handler.cc
@@ -4,7 +4,10 @@
#include "content/browser/devtools/protocol/memory_handler.h"
+#include <cinttypes>
+
#include "base/memory/memory_pressure_listener.h"
+#include "base/sampling_heap_profiler/module_cache.h"
#include "base/sampling_heap_profiler/sampling_heap_profiler.h"
#include "base/strings/stringprintf.h"
#include "content/public/browser/render_process_host.h"
@@ -33,15 +36,19 @@ void MemoryHandler::SetRenderer(int process_host_id,
Response MemoryHandler::GetBrowserSamplingProfile(
std::unique_ptr<Memory::SamplingProfile>* out_profile) {
+ base::ModuleCache module_cache;
std::unique_ptr<Array<Memory::SamplingProfileNode>> samples =
Array<Memory::SamplingProfileNode>::create();
std::vector<base::SamplingHeapProfiler::Sample> raw_samples =
- base::SamplingHeapProfiler::GetInstance()->GetSamples(0);
+ base::SamplingHeapProfiler::Get()->GetSamples(0);
for (auto& sample : raw_samples) {
std::unique_ptr<Array<String>> stack = Array<String>::create();
- for (auto* frame : sample.stack)
- stack->addItem(base::StringPrintf("%p", frame));
+ for (const void* frame : sample.stack) {
+ uintptr_t address = reinterpret_cast<uintptr_t>(frame);
+ module_cache.GetModuleForAddress(address); // Populates module_cache.
+ stack->addItem(base::StringPrintf("0x%" PRIxPTR, address));
+ }
samples->addItem(Memory::SamplingProfileNode::Create()
.SetSize(sample.size)
.SetTotal(sample.total)
@@ -49,8 +56,23 @@ Response MemoryHandler::GetBrowserSamplingProfile(
.Build());
}
- *out_profile =
- Memory::SamplingProfile::Create().SetSamples(std::move(samples)).Build();
+ std::unique_ptr<Array<Memory::Module>> modules =
+ Array<Memory::Module>::create();
+ for (const auto* module : module_cache.GetModules()) {
+ modules->addItem(Memory::Module::Create()
+ .SetName(base::StringPrintf(
+ "%" PRIsFP, module->filename.value().c_str()))
+ .SetUuid(module->id)
+ .SetBaseAddress(base::StringPrintf(
+ "0x%" PRIxPTR, module->base_address))
+ .SetSize(static_cast<double>(module->size))
+ .Build());
+ }
+
+ *out_profile = Memory::SamplingProfile::Create()
+ .SetSamples(std::move(samples))
+ .SetModules(std::move(modules))
+ .Build();
return Response::OK();
}
diff --git a/chromium/content/browser/devtools/protocol/page_handler.cc b/chromium/content/browser/devtools/protocol/page_handler.cc
index a55920d878a..92d78224bbe 100644
--- a/chromium/content/browser/devtools/protocol/page_handler.cc
+++ b/chromium/content/browser/devtools/protocol/page_handler.cc
@@ -20,10 +20,9 @@
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
-#include "components/viz/common/features.h"
#include "content/browser/devtools/devtools_session.h"
#include "content/browser/devtools/protocol/devtools_download_manager_delegate.h"
#include "content/browser/devtools/protocol/devtools_download_manager_helper.h"
@@ -47,7 +46,6 @@
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/browser_side_navigation_policy.h"
-#include "content/public/common/content_features.h"
#include "content/public/common/referrer.h"
#include "content/public/common/result_codes.h"
#include "content/public/common/use_zoom_for_dsf_policy.h"
@@ -61,6 +59,10 @@
#include "ui/gfx/skbitmap_operations.h"
#include "ui/snapshot/snapshot.h"
+#ifdef OS_ANDROID
+#include "content/browser/renderer_host/compositor_impl_android.h"
+#endif
+
namespace content {
namespace protocol {
@@ -118,16 +120,19 @@ std::unique_ptr<Page::ScreencastFrameMetadata> BuildScreencastFrameMetadata(
const gfx::SizeF content_size_dip =
gfx::ScaleSize(gfx::SizeF(surface_size), 1 / device_scale_factor);
float top_offset_dip = top_controls_height * top_controls_shown_ratio;
- if (IsUseZoomForDSFEnabled())
+ gfx::Vector2dF root_scroll_offset_dip = root_scroll_offset;
+ if (IsUseZoomForDSFEnabled()) {
top_offset_dip /= device_scale_factor;
+ root_scroll_offset_dip.Scale(1 / device_scale_factor);
+ }
std::unique_ptr<Page::ScreencastFrameMetadata> page_metadata =
Page::ScreencastFrameMetadata::Create()
.SetPageScaleFactor(page_scale_factor)
.SetOffsetTop(top_offset_dip)
.SetDeviceWidth(content_size_dip.width())
.SetDeviceHeight(content_size_dip.height())
- .SetScrollOffsetX(root_scroll_offset.x())
- .SetScrollOffsetY(root_scroll_offset.y())
+ .SetScrollOffsetX(root_scroll_offset_dip.x())
+ .SetScrollOffsetY(root_scroll_offset_dip.y())
.SetTimestamp(base::Time::Now().ToDoubleT())
.Build();
return page_metadata;
@@ -170,11 +175,16 @@ void GetMetadataFromFrame(const media::VideoFrame& frame,
media::VideoFrameMetadata::ROOT_SCROLL_OFFSET_X, &root_scroll_offset_x);
success &= frame.metadata()->GetDouble(
media::VideoFrameMetadata::ROOT_SCROLL_OFFSET_Y, &root_scroll_offset_y);
+#if defined(OS_ANDROID)
success &= frame.metadata()->GetDouble(
media::VideoFrameMetadata::TOP_CONTROLS_HEIGHT, top_controls_height);
success &= frame.metadata()->GetDouble(
media::VideoFrameMetadata::TOP_CONTROLS_SHOWN_RATIO,
top_controls_shown_ratio);
+#else
+ *top_controls_height = 0.;
+ *top_controls_shown_ratio = 0.;
+#endif // defined(OS_ANDROID)
DCHECK(success);
root_scroll_offset->set_x(root_scroll_offset_x);
@@ -202,9 +212,13 @@ PageHandler::PageHandler(EmulationHandler* emulation_handler)
emulation_handler_(emulation_handler),
observer_(this),
weak_factory_(this) {
- if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor) ||
- base::FeatureList::IsEnabled(
- features::kUseVideoCaptureApiForDevToolsSnapshots)) {
+ bool create_video_consumer = true;
+#ifdef OS_ANDROID
+ // Video capture doesn't work on Android WebView. Use CopyFromSurface instead.
+ if (!CompositorImpl::IsInitialized())
+ create_video_consumer = false;
+#endif
+ if (create_video_consumer) {
video_consumer_ = std::make_unique<DevToolsVideoConsumer>(
base::BindRepeating(&PageHandler::OnFrameFromVideoConsumer,
weak_factory_.GetWeakPtr()));
@@ -264,18 +278,6 @@ void PageHandler::Wire(UberDispatcher* dispatcher) {
Page::Dispatcher::wire(dispatcher, this);
}
-void PageHandler::OnSwapCompositorFrame(
- viz::CompositorFrameMetadata frame_metadata) {
- if (video_consumer_)
- return;
-
- last_compositor_frame_metadata_ = std::move(frame_metadata);
- has_compositor_frame_metadata_ = true;
-
- if (screencast_enabled_)
- InnerSwapCompositorFrame();
-}
-
void PageHandler::OnSynchronousSwapCompositorFrame(
viz::CompositorFrameMetadata frame_metadata) {
if (has_compositor_frame_metadata_) {
@@ -406,24 +408,21 @@ Response PageHandler::Close() {
return Response::OK();
}
-Response PageHandler::Reload(Maybe<bool> bypassCache,
- Maybe<std::string> script_to_evaluate_on_load) {
+void PageHandler::Reload(Maybe<bool> bypassCache,
+ Maybe<std::string> script_to_evaluate_on_load,
+ std::unique_ptr<ReloadCallback> callback) {
WebContentsImpl* web_contents = GetWebContents();
- if (!web_contents)
- return Response::InternalError();
- if (web_contents->IsCrashed() ||
- web_contents->GetURL().scheme() == url::kDataScheme ||
- (web_contents->GetController().GetVisibleEntry() &&
- web_contents->GetController().GetVisibleEntry()->IsViewSourceMode())) {
- web_contents->GetController().Reload(bypassCache.fromMaybe(false)
- ? ReloadType::BYPASSING_CACHE
- : ReloadType::NORMAL,
- false);
- return Response::OK();
- } else {
- // Handle reload in renderer except for crashed and view source mode.
- return Response::FallThrough();
+ if (!web_contents) {
+ callback->sendFailure(Response::InternalError());
+ return;
}
+ // It is important to fallback before triggering reload, so that
+ // renderer could prepare beforehand.
+ callback->fallThrough();
+ web_contents->GetController().Reload(bypassCache.fromMaybe(false)
+ ? ReloadType::BYPASSING_CACHE
+ : ReloadType::NORMAL,
+ false);
}
void PageHandler::Navigate(const std::string& url,
@@ -946,13 +945,19 @@ void PageHandler::InnerSwapCompositorFrame() {
if (snapshot_size.IsEmpty())
return;
+ double top_controls_height = 0.;
+ double top_controls_shown_ratio = 0.;
+#if defined(OS_ANDROID)
+ top_controls_height = last_compositor_frame_metadata_.top_controls_height;
+ top_controls_shown_ratio =
+ last_compositor_frame_metadata_.top_controls_shown_ratio;
+#endif
std::unique_ptr<Page::ScreencastFrameMetadata> page_metadata =
BuildScreencastFrameMetadata(
surface_size, last_compositor_frame_metadata_.device_scale_factor,
last_compositor_frame_metadata_.page_scale_factor,
last_compositor_frame_metadata_.root_scroll_offset,
- last_compositor_frame_metadata_.top_controls_height,
- last_compositor_frame_metadata_.top_controls_shown_ratio);
+ top_controls_height, top_controls_shown_ratio);
if (!page_metadata)
return;
diff --git a/chromium/content/browser/devtools/protocol/page_handler.h b/chromium/content/browser/devtools/protocol/page_handler.h
index eb6a09acea3..ea8e3b17f31 100644
--- a/chromium/content/browser/devtools/protocol/page_handler.h
+++ b/chromium/content/browser/devtools/protocol/page_handler.h
@@ -68,7 +68,6 @@ class PageHandler : public DevToolsDomainHandler,
void Wire(UberDispatcher* dispatcher) override;
void SetRenderer(int process_host_id,
RenderFrameHostImpl* frame_host) override;
- void OnSwapCompositorFrame(viz::CompositorFrameMetadata frame_metadata);
void OnSynchronousSwapCompositorFrame(
viz::CompositorFrameMetadata frame_metadata);
void DidAttachInterstitialPage();
@@ -93,8 +92,9 @@ class PageHandler : public DevToolsDomainHandler,
Response Crash() override;
Response Close() override;
- Response Reload(Maybe<bool> bypassCache,
- Maybe<std::string> script_to_evaluate_on_load) override;
+ void Reload(Maybe<bool> bypassCache,
+ Maybe<std::string> script_to_evaluate_on_load,
+ std::unique_ptr<ReloadCallback> callback) override;
void Navigate(const std::string& url,
Maybe<std::string> referrer,
Maybe<std::string> transition_type,
diff --git a/chromium/content/browser/devtools/protocol/service_worker_handler.cc b/chromium/content/browser/devtools/protocol/service_worker_handler.cc
index 77d1cc9fda7..06c7cf436fd 100644
--- a/chromium/content/browser/devtools/protocol/service_worker_handler.cc
+++ b/chromium/content/browser/devtools/protocol/service_worker_handler.cc
@@ -27,7 +27,6 @@
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
-#include "content/public/common/push_event_payload.h"
#include "content/public/common/push_messaging_status.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_provider_type.mojom.h"
@@ -309,11 +308,11 @@ Response ServiceWorkerHandler::DeliverPushMessage(
int64_t id = 0;
if (!base::StringToInt64(registration_id, &id))
return CreateInvalidVersionIdErrorResponse();
- PushEventPayload payload;
+ base::Optional<std::string> payload;
if (data.size() > 0)
- payload.setData(data);
+ payload = data;
BrowserContext::DeliverPushMessage(
- browser_context_, GURL(origin), id, payload,
+ browser_context_, GURL(origin), id, std::move(payload),
base::BindRepeating([](mojom::PushDeliveryStatus status) {}));
return Response::OK();
diff --git a/chromium/content/browser/devtools/protocol/system_info_handler.cc b/chromium/content/browser/devtools/protocol/system_info_handler.cc
index c6673d3451c..c0c84ef83f8 100644
--- a/chromium/content/browser/devtools/protocol/system_info_handler.cc
+++ b/chromium/content/browser/devtools/protocol/system_info_handler.cc
@@ -33,7 +33,8 @@ using GetInfoCallback = SystemInfo::Backend::GetInfoCallback;
// Give the GPU process a few seconds to provide GPU info.
// Linux Debug builds need more time -- see Issue 796437.
-#if defined(OS_LINUX) && !defined(NDEBUG)
+// Windows builds need more time -- see Issue 873112.
+#if (defined(OS_LINUX) && !defined(NDEBUG)) || defined(OS_WIN)
const int kGPUInfoWatchdogTimeoutMs = 20000;
#else
const int kGPUInfoWatchdogTimeoutMs = 5000;
diff --git a/chromium/content/browser/devtools/protocol/target_handler.cc b/chromium/content/browser/devtools/protocol/target_handler.cc
index 1d467539ccc..f24ac4f28e2 100644
--- a/chromium/content/browser/devtools/protocol/target_handler.cc
+++ b/chromium/content/browser/devtools/protocol/target_handler.cc
@@ -27,8 +27,6 @@ namespace protocol {
namespace {
-static const char kMethod[] = "method";
-static const char kResumeMethod[] = "Runtime.runIfWaitingForDebugger";
static const char kInitializerScript[] = R"(
(function() {
const bindingName = "%s";
@@ -241,8 +239,10 @@ class TargetHandler::Session : public DevToolsAgentHostClient {
DevToolsAgentHostImpl* agent_host_impl =
static_cast<DevToolsAgentHostImpl*>(agent_host);
if (flatten_protocol) {
- handler->target_registry_->AttachSubtargetSession(id, agent_host_impl,
- session);
+ handler->target_registry_->AttachSubtargetSession(
+ id, agent_host_impl, session,
+ base::BindOnce(&Session::ResumeIfThrottled,
+ base::Unretained(session)));
} else {
agent_host_impl->AttachClient(session);
}
@@ -275,17 +275,16 @@ class TargetHandler::Session : public DevToolsAgentHostClient {
void SetThrottle(Throttle* throttle) { throttle_ = throttle; }
+ void ResumeIfThrottled() {
+ if (throttle_)
+ throttle_->Clear();
+ }
+
void SendMessageToAgentHost(const std::string& message) {
if (throttle_) {
- bool resuming = false;
std::unique_ptr<base::Value> value = base::JSONReader::Read(message);
- if (value && value->is_dict()) {
- base::Value* method = value->FindKey(kMethod);
- resuming = method && method->is_string() &&
- method->GetString() == kResumeMethod;
- }
- if (resuming)
- throttle_->Clear();
+ if (TargetRegistry::IsRuntimeResumeCommand(value.get()))
+ ResumeIfThrottled();
}
agent_host_->DispatchProtocolMessage(this, message);
@@ -426,7 +425,7 @@ void TargetHandler::SetRenderer(int process_host_id,
}
Response TargetHandler::Disable() {
- SetAutoAttach(false, false);
+ SetAutoAttach(false, false, false);
SetDiscoverTargets(false);
auto_attached_sessions_.clear();
attached_sessions_.clear();
@@ -455,7 +454,7 @@ void TargetHandler::ClearThrottles() {
void TargetHandler::AutoAttach(DevToolsAgentHost* host,
bool waiting_for_debugger) {
std::string session_id =
- Session::Attach(this, host, waiting_for_debugger, false);
+ Session::Attach(this, host, waiting_for_debugger, flatten_auto_attach_);
auto_attached_sessions_[host] = attached_sessions_[session_id].get();
}
@@ -517,8 +516,10 @@ Response TargetHandler::SetDiscoverTargets(bool discover) {
return Response::OK();
}
-Response TargetHandler::SetAutoAttach(
- bool auto_attach, bool wait_for_debugger_on_start) {
+Response TargetHandler::SetAutoAttach(bool auto_attach,
+ bool wait_for_debugger_on_start,
+ Maybe<bool> flatten) {
+ flatten_auto_attach_ = flatten.fromMaybe(false);
auto_attacher_.SetAutoAttach(auto_attach, wait_for_debugger_on_start);
if (!auto_attacher_.ShouldThrottleFramesNavigation())
ClearThrottles();
@@ -643,19 +644,6 @@ Response TargetHandler::ExposeDevToolsProtocol(
return Response::OK();
}
-Response TargetHandler::CreateBrowserContext(std::string* out_context_id) {
- return Response::Error("Not supported");
-}
-
-Response TargetHandler::DisposeBrowserContext(const std::string& context_id) {
- return Response::Error("Not supported");
-}
-
-Response TargetHandler::GetBrowserContexts(
- std::unique_ptr<protocol::Array<String>>* browser_context_ids) {
- return Response::Error("Not supported");
-}
-
Response TargetHandler::CreateTarget(const std::string& url,
Maybe<int> width,
Maybe<int> height,
@@ -732,5 +720,67 @@ void TargetHandler::DevToolsAgentHostCrashed(DevToolsAgentHost* host,
: 0);
}
+protocol::Response TargetHandler::CreateBrowserContext(
+ std::string* out_context_id) {
+ DevToolsManagerDelegate* delegate =
+ DevToolsManager::GetInstance()->delegate();
+ if (!delegate)
+ return Response::Error("Browser context management is not supported.");
+ BrowserContext* context = delegate->CreateBrowserContext();
+ if (!context)
+ return Response::Error("Failed to create browser context.");
+ *out_context_id = context->UniqueId();
+ return protocol::Response::OK();
+}
+
+protocol::Response TargetHandler::GetBrowserContexts(
+ std::unique_ptr<protocol::Array<protocol::String>>* browser_context_ids) {
+ DevToolsManagerDelegate* delegate =
+ DevToolsManager::GetInstance()->delegate();
+ if (!delegate)
+ return Response::Error("Browser context management is not supported.");
+ std::vector<content::BrowserContext*> contexts =
+ delegate->GetBrowserContexts();
+ *browser_context_ids = std::make_unique<protocol::Array<protocol::String>>();
+ for (auto* context : contexts)
+ (*browser_context_ids)->addItem(context->UniqueId());
+ return protocol::Response::OK();
+}
+
+void TargetHandler::DisposeBrowserContext(
+ const std::string& context_id,
+ std::unique_ptr<DisposeBrowserContextCallback> callback) {
+ DevToolsManagerDelegate* delegate =
+ DevToolsManager::GetInstance()->delegate();
+ if (!delegate) {
+ callback->sendFailure(protocol::Response::Error(
+ "Browser context management is not supported."));
+ return;
+ }
+ std::vector<content::BrowserContext*> contexts =
+ delegate->GetBrowserContexts();
+ auto context_it =
+ std::find_if(contexts.begin(), contexts.end(),
+ [&context_id](content::BrowserContext* context) {
+ return context->UniqueId() == context_id;
+ });
+ if (context_it == contexts.end()) {
+ callback->sendFailure(protocol::Response::Error(
+ "Failed to find context with id " + context_id));
+ return;
+ }
+ delegate->DisposeBrowserContext(
+ *context_it,
+ base::BindOnce(
+ [](std::unique_ptr<DisposeBrowserContextCallback> callback,
+ bool success, const std::string& error) {
+ if (success)
+ callback->sendSuccess();
+ else
+ callback->sendFailure(protocol::Response::Error(error));
+ },
+ std::move(callback)));
+}
+
} // namespace protocol
} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/target_handler.h b/chromium/content/browser/devtools/protocol/target_handler.h
index ba5702adbd0..06a9bbb9ca5 100644
--- a/chromium/content/browser/devtools/protocol/target_handler.h
+++ b/chromium/content/browser/devtools/protocol/target_handler.h
@@ -49,7 +49,8 @@ class TargetHandler : public DevToolsDomainHandler,
// Domain implementation.
Response SetDiscoverTargets(bool discover) override;
Response SetAutoAttach(bool auto_attach,
- bool wait_for_debugger_on_start) override;
+ bool wait_for_debugger_on_start,
+ Maybe<bool> flatten) override;
Response SetRemoteLocations(
std::unique_ptr<protocol::Array<Target::RemoteLocation>>) override;
Response AttachToTarget(const std::string& target_id,
@@ -70,7 +71,9 @@ class TargetHandler : public DevToolsDomainHandler,
Response ExposeDevToolsProtocol(const std::string& target_id,
Maybe<std::string> binding_name) override;
Response CreateBrowserContext(std::string* out_context_id) override;
- Response DisposeBrowserContext(const std::string& context_id) override;
+ void DisposeBrowserContext(
+ const std::string& context_id,
+ std::unique_ptr<DisposeBrowserContextCallback> callback) override;
Response GetBrowserContexts(
std::unique_ptr<protocol::Array<String>>* browser_context_ids) override;
Response CreateTarget(const std::string& url,
@@ -107,6 +110,7 @@ class TargetHandler : public DevToolsDomainHandler,
std::unique_ptr<Target::Frontend> frontend_;
TargetAutoAttacher auto_attacher_;
+ bool flatten_auto_attach_ = false;
bool discover_;
std::map<std::string, std::unique_ptr<Session>> attached_sessions_;
std::map<DevToolsAgentHost*, Session*> auto_attached_sessions_;
diff --git a/chromium/content/browser/devtools/protocol/tethering_handler.cc b/chromium/content/browser/devtools/protocol/tethering_handler.cc
index ce6738651b2..4640abe9ff0 100644
--- a/chromium/content/browser/devtools/protocol/tethering_handler.cc
+++ b/chromium/content/browser/devtools/protocol/tethering_handler.cc
@@ -108,8 +108,8 @@ class SocketPump {
new net::IOBuffer(kSocketPumpBufferSize);
int result =
from->Read(buffer.get(), kSocketPumpBufferSize,
- base::Bind(&SocketPump::OnRead, base::Unretained(this), from,
- to, buffer));
+ base::BindOnce(&SocketPump::OnRead, base::Unretained(this),
+ from, to, buffer));
if (result != net::ERR_IO_PENDING)
OnRead(from, to, buffer, result);
}
@@ -125,13 +125,14 @@ class SocketPump {
int total = result;
scoped_refptr<net::DrainableIOBuffer> drainable =
- new net::DrainableIOBuffer(buffer.get(), total);
+ base::MakeRefCounted<net::DrainableIOBuffer>(std::move(buffer), total);
++pending_writes_;
- result = to->Write(drainable.get(), total,
- base::Bind(&SocketPump::OnWritten,
- base::Unretained(this), drainable, from, to),
- kTrafficAnnotation);
+ result =
+ to->Write(drainable.get(), total,
+ base::BindOnce(&SocketPump::OnWritten, base::Unretained(this),
+ drainable, from, to),
+ kTrafficAnnotation);
if (result != net::ERR_IO_PENDING)
OnWritten(drainable, from, to, result);
}
@@ -151,8 +152,8 @@ class SocketPump {
++pending_writes_;
result =
to->Write(drainable.get(), drainable->BytesRemaining(),
- base::Bind(&SocketPump::OnWritten, base::Unretained(this),
- drainable, from, to),
+ base::BindOnce(&SocketPump::OnWritten,
+ base::Unretained(this), drainable, from, to),
kTrafficAnnotation);
if (result != net::ERR_IO_PENDING)
OnWritten(drainable, from, to, result);
diff --git a/chromium/content/browser/devtools/protocol/tracing_handler.cc b/chromium/content/browser/devtools/protocol/tracing_handler.cc
index 9546e5dd5a3..a93a43faa7c 100644
--- a/chromium/content/browser/devtools/protocol/tracing_handler.cc
+++ b/chromium/content/browser/devtools/protocol/tracing_handler.cc
@@ -24,7 +24,6 @@
#include "base/trace_event/trace_event_impl.h"
#include "base/trace_event/tracing_agent.h"
#include "components/tracing/common/trace_startup_config.h"
-#include "components/viz/common/features.h"
#include "content/browser/devtools/devtools_frame_trace_recorder.h"
#include "content/browser/devtools/devtools_io_context.h"
#include "content/browser/devtools/devtools_session.h"
@@ -35,10 +34,10 @@
#include "content/browser/frame_host/frame_tree_node.h"
#include "content/browser/frame_host/navigation_handle_impl.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/tracing/tracing_controller_impl.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/common/content_features.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
#include "services/tracing/public/mojom/constants.mojom.h"
@@ -218,10 +217,7 @@ TracingHandler::TracingHandler(FrameTreeNode* frame_tree_node_,
return_as_stream_(false),
gzip_compression_(false),
weak_factory_(this) {
- bool use_video_capture_api =
- base::FeatureList::IsEnabled(features::kVizDisplayCompositor) ||
- base::FeatureList::IsEnabled(
- features::kUseVideoCaptureApiForDevToolsSnapshots);
+ bool use_video_capture_api = true;
#ifdef OS_ANDROID
// Video capture API cannot be used on Android WebView.
if (!CompositorImpl::IsInitialized())
@@ -409,12 +405,30 @@ void TracingHandler::Start(Maybe<std::string> categories,
options.fromMaybe(""));
}
- // If inspected target is a render process Tracing.start will be handled by
- // tracing agent in the renderer.
- if (frame_tree_node_)
- callback->fallThrough();
+ // GPU process id can only be retrieved on IO thread. Do some thread hopping.
+ BrowserThread::PostTaskAndReplyWithResult(
+ BrowserThread::IO, FROM_HERE, base::BindOnce([]() {
+ GpuProcessHost* gpu_process_host =
+ GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
+ /* force_create */ false);
+ return gpu_process_host ? gpu_process_host->process_id()
+ : base::kNullProcessId;
+ }),
+ base::BindOnce(&TracingHandler::StartTracingWithGpuPid,
+ weak_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void TracingHandler::StartTracingWithGpuPid(
+ std::unique_ptr<StartCallback> callback,
+ base::ProcessId gpu_pid) {
+ // Check if tracing was stopped in mid-air.
+ if (!did_initiate_recording_) {
+ callback->sendFailure(Response::Error(
+ "Tracing was stopped before start has been completed."));
+ return;
+ }
- SetupProcessFilter(nullptr);
+ SetupProcessFilter(gpu_pid, nullptr);
TracingController::GetInstance()->StartTracing(
trace_config_, base::BindRepeating(&TracingHandler::OnRecordingEnabled,
@@ -423,14 +437,20 @@ void TracingHandler::Start(Maybe<std::string> categories,
}
void TracingHandler::SetupProcessFilter(
+ base::ProcessId gpu_pid,
RenderFrameHost* new_render_frame_host) {
if (!frame_tree_node_)
return;
base::ProcessId browser_pid = base::Process::Current().Pid();
std::unordered_set<base::ProcessId> included_process_ids({browser_pid});
+
+ if (gpu_pid != base::kNullProcessId)
+ included_process_ids.insert(gpu_pid);
+
if (new_render_frame_host)
AppendProcessId(new_render_frame_host, &included_process_ids);
+
for (FrameTreeNode* node :
frame_tree_node_->frame_tree()->SubtreeNodes(frame_tree_node_)) {
RenderFrameHost* frame_host = node->current_frame_host();
@@ -467,14 +487,12 @@ void TracingHandler::OnProcessReady(RenderProcessHost* process_host) {
trace_config_, base::RepeatingCallback<void()>());
}
-void TracingHandler::End(std::unique_ptr<EndCallback> callback) {
+Response TracingHandler::End() {
// Startup tracing triggered by --trace-config-file is a special case, where
// tracing is started automatically upon browser startup and can be stopped
// via DevTools.
- if (!did_initiate_recording_ && !IsStartupTracingActive()) {
- callback->sendFailure(Response::Error("Tracing is not started"));
- return;
- }
+ if (!did_initiate_recording_ && !IsStartupTracingActive())
+ return Response::Error("Tracing is not started");
scoped_refptr<TracingController::TraceDataEndpoint> endpoint;
if (return_as_stream_) {
@@ -493,12 +511,8 @@ void TracingHandler::End(std::unique_ptr<EndCallback> callback) {
endpoint = new DevToolsTraceEndpointProxy(weak_factory_.GetWeakPtr());
StopTracing(endpoint, tracing::mojom::kChromeTraceEventLabel);
}
- // If inspected target is a render process Tracing.end will be handled by
- // tracing agent in the renderer.
- if (frame_tree_node_)
- callback->fallThrough();
- else
- callback->sendSuccess();
+
+ return Response::OK();
}
void TracingHandler::GetCategories(
@@ -511,10 +525,14 @@ void TracingHandler::GetCategories(
void TracingHandler::OnRecordingEnabled(
std::unique_ptr<StartCallback> callback) {
- EmitFrameTree();
+ if (!did_initiate_recording_) {
+ callback->sendFailure(Response::Error(
+ "Tracing was stopped before start has been completed."));
+ return;
+ }
- if (!frame_tree_node_)
- callback->sendSuccess();
+ EmitFrameTree();
+ callback->sendSuccess();
bool screenshot_enabled;
TRACE_EVENT_CATEGORY_GROUP_ENABLED(
@@ -663,7 +681,8 @@ void TracingHandler::ReadyToCommitNavigation(
"FrameCommittedInBrowser", TRACE_EVENT_SCOPE_THREAD,
"data", std::move(data));
- SetupProcessFilter(navigation_handle->GetRenderFrameHost());
+ SetupProcessFilter(base::kNullProcessId,
+ navigation_handle->GetRenderFrameHost());
TracingController::GetInstance()->StartTracing(
trace_config_, base::RepeatingCallback<void()>());
}
diff --git a/chromium/content/browser/devtools/protocol/tracing_handler.h b/chromium/content/browser/devtools/protocol/tracing_handler.h
index 82f11ef2a25..97ba2286280 100644
--- a/chromium/content/browser/devtools/protocol/tracing_handler.h
+++ b/chromium/content/browser/devtools/protocol/tracing_handler.h
@@ -69,7 +69,7 @@ class TracingHandler : public DevToolsDomainHandler, public Tracing::Backend {
Maybe<std::string> transfer_compression,
Maybe<Tracing::TraceConfig> config,
std::unique_ptr<StartCallback> callback) override;
- void End(std::unique_ptr<EndCallback> callback) override;
+ Response End() override;
void GetCategories(std::unique_ptr<GetCategoriesCallback> callback) override;
void RequestMemoryDump(
std::unique_ptr<RequestMemoryDumpCallback> callback) override;
@@ -116,7 +116,9 @@ class TracingHandler : public DevToolsDomainHandler, public Tracing::Backend {
CONTENT_EXPORT static base::trace_event::TraceConfig
GetTraceConfigFromDevToolsConfig(
const base::DictionaryValue& devtools_config);
- void SetupProcessFilter(RenderFrameHost*);
+ void SetupProcessFilter(base::ProcessId gpu_pid, RenderFrameHost*);
+ void StartTracingWithGpuPid(std::unique_ptr<StartCallback>,
+ base::ProcessId gpu_pid);
void AppendProcessId(RenderFrameHost*,
std::unordered_set<base::ProcessId>* process_set);
void OnProcessReady(RenderProcessHost*);
diff --git a/chromium/content/browser/devtools/protocol_config.json b/chromium/content/browser/devtools/protocol_config.json
index 0919b220303..1c779296c95 100644
--- a/chromium/content/browser/devtools/protocol_config.json
+++ b/chromium/content/browser/devtools/protocol_config.json
@@ -11,7 +11,7 @@
"options": [
{
"domain": "Browser",
- "include": ["getVersion", "getHistograms", "getHistogram", "getBrowserCommandLine"]
+ "include": ["getVersion", "getHistograms", "getHistogram", "getBrowserCommandLine", "grantPermissions", "resetPermissions"]
},
{
"domain": "DOM",
@@ -24,7 +24,7 @@
},
{
"domain": "Input",
- "async": ["dispatchKeyEvent", "dispatchMouseEvent", "dispatchTouchEvent", "synthesizePinchGesture", "synthesizeScrollGesture", "synthesizeTapGesture"]
+ "async": ["dispatchKeyEvent", "insertText", "dispatchMouseEvent", "dispatchTouchEvent", "synthesizePinchGesture", "synthesizeScrollGesture", "synthesizeTapGesture"]
},
{
"domain": "Inspector"
@@ -51,7 +51,7 @@
"startScreencast", "stopScreencast", "screencastFrameAck", "handleJavaScriptDialog", "setColorPickerEnabled", "requestAppBanner",
"printToPDF", "bringToFront", "setDownloadBehavior", "getAppManifest", "crash", "close", "setWebLifecycleState"],
"include_events": ["colorPicked", "interstitialShown", "interstitialHidden", "javascriptDialogOpening", "javascriptDialogClosed", "screencastVisibilityChanged", "screencastFrame"],
- "async": ["captureScreenshot", "printToPDF", "navigate", "getAppManifest"]
+ "async": ["captureScreenshot", "printToPDF", "navigate", "getAppManifest", "reload"]
},
{
"domain": "Runtime",
@@ -77,7 +77,8 @@
"async": ["getInfo"]
},
{
- "domain": "Target"
+ "domain": "Target",
+ "async": ["disposeBrowserContext"]
},
{
"domain": "Tethering",
@@ -85,7 +86,7 @@
},
{
"domain": "Tracing",
- "async": ["start", "end", "getCategories", "requestMemoryDump"]
+ "async": ["start", "getCategories", "requestMemoryDump"]
}
]
},
diff --git a/chromium/content/browser/devtools/render_frame_devtools_agent_host.cc b/chromium/content/browser/devtools/render_frame_devtools_agent_host.cc
index 9493103481a..f80fb077ae0 100644
--- a/chromium/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/chromium/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -12,7 +12,6 @@
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
-#include "components/viz/common/features.h"
#include "content/browser/bad_message.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/devtools/devtools_frame_trace_recorder.h"
@@ -51,7 +50,6 @@
#include "content/public/browser/render_widget_host_iterator.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/browser_side_navigation_policy.h"
-#include "content/public/common/content_features.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
#include "net/base/load_flags.h"
#include "net/http/http_request_headers.h"
@@ -429,14 +427,7 @@ WebContents* RenderFrameDevToolsAgentHost::GetWebContents() {
bool RenderFrameDevToolsAgentHost::AttachSession(DevToolsSession* session,
TargetRegistry* registry) {
- DevToolsManager* manager = DevToolsManager::GetInstance();
- if (manager->delegate() && web_contents()) {
- if (!manager->delegate()->AllowInspectingWebContents(web_contents()))
- return false;
- }
- const bool is_webui =
- frame_host_ && (frame_host_->web_ui() || frame_host_->pending_web_ui());
- if (!session->client()->MayAttachToRenderer(frame_host_, is_webui))
+ if (!ShouldAllowSession(session, frame_host_))
return false;
session->SetRenderer(frame_host_ ? frame_host_->GetProcess()->GetID()
@@ -477,10 +468,7 @@ bool RenderFrameDevToolsAgentHost::AttachSession(DevToolsSession* session,
session->AttachToAgent(agent_ptr_);
if (sessions().size() == 1) {
- bool use_video_capture_api =
- base::FeatureList::IsEnabled(features::kVizDisplayCompositor) ||
- base::FeatureList::IsEnabled(
- features::kUseVideoCaptureApiForDevToolsSnapshots);
+ bool use_video_capture_api = true;
#ifdef OS_ANDROID
// Video capture API cannot be used on Android WebView.
if (!CompositorImpl::IsInitialized())
@@ -604,14 +592,10 @@ void RenderFrameDevToolsAgentHost::UpdateFrameHost(
agent_ptr_.reset();
std::vector<DevToolsSession*> restricted_sessions;
- const bool is_webui =
- frame_host && (frame_host->web_ui() || frame_host->pending_web_ui());
-
for (DevToolsSession* session : sessions()) {
- if (!session->client()->MayAttachToRenderer(frame_host, is_webui))
+ if (!ShouldAllowSession(session, frame_host))
restricted_sessions.push_back(session);
}
-
if (!restricted_sessions.empty())
ForceDetachRestrictedSessions(restricted_sessions);
@@ -786,23 +770,6 @@ void RenderFrameDevToolsAgentHost::OnVisibilityChanged(
#endif
}
-void RenderFrameDevToolsAgentHost::DidReceiveCompositorFrame() {
- const viz::CompositorFrameMetadata& metadata =
- RenderWidgetHostImpl::From(
- web_contents()->GetRenderViewHost()->GetWidget())
- ->last_frame_metadata();
- for (auto* page : protocol::PageHandler::ForAgentHost(this))
- page->OnSwapCompositorFrame(metadata.Clone());
-
- if (!frame_trace_recorder_)
- return;
- bool did_initiate_recording = false;
- for (auto* tracing : protocol::TracingHandler::ForAgentHost(this))
- did_initiate_recording |= tracing->did_initiate_recording();
- if (did_initiate_recording)
- frame_trace_recorder_->OnSwapCompositorFrame(frame_host_, metadata);
-}
-
void RenderFrameDevToolsAgentHost::OnPageScaleFactorChanged(
float page_scale_factor) {
for (auto* input : protocol::InputHandler::ForAgentHost(this))
@@ -981,4 +948,19 @@ bool RenderFrameDevToolsAgentHost::IsChildFrame() {
return frame_tree_node_ && frame_tree_node_->parent();
}
+bool RenderFrameDevToolsAgentHost::ShouldAllowSession(
+ DevToolsSession* session,
+ RenderFrameHostImpl* frame_host) {
+ DevToolsManager* manager = DevToolsManager::GetInstance();
+ if (manager->delegate() && frame_host) {
+ if (!manager->delegate()->AllowInspectingRenderFrameHost(frame_host))
+ return false;
+ }
+ const bool is_webui =
+ frame_host && (frame_host->web_ui() || frame_host->pending_web_ui());
+ if (!session->client()->MayAttachToRenderer(frame_host, is_webui))
+ return false;
+ return true;
+}
+
} // namespace content
diff --git a/chromium/content/browser/devtools/render_frame_devtools_agent_host.h b/chromium/content/browser/devtools/render_frame_devtools_agent_host.h
index b4184bb250d..37f0c8d1e77 100644
--- a/chromium/content/browser/devtools/render_frame_devtools_agent_host.h
+++ b/chromium/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -178,7 +178,6 @@ class CONTENT_EXPORT RenderFrameDevToolsAgentHost
void DidAttachInterstitialPage() override;
void DidDetachInterstitialPage() override;
void OnVisibilityChanged(content::Visibility visibility) override;
- void DidReceiveCompositorFrame() override;
void OnPageScaleFactorChanged(float page_scale_factor) override;
bool IsChildFrame();
@@ -191,6 +190,9 @@ class CONTENT_EXPORT RenderFrameDevToolsAgentHost
void RevokePolicy();
void SetFrameTreeNode(FrameTreeNode* frame_tree_node);
+ bool ShouldAllowSession(DevToolsSession* session,
+ RenderFrameHostImpl* frame_host);
+
#if defined(OS_ANDROID)
device::mojom::WakeLock* GetWakeLock();
#endif
diff --git a/chromium/content/browser/devtools/service_worker_devtools_manager.h b/chromium/content/browser/devtools/service_worker_devtools_manager.h
index 1018d40705a..0153f487adb 100644
--- a/chromium/content/browser/devtools/service_worker_devtools_manager.h
+++ b/chromium/content/browser/devtools/service_worker_devtools_manager.h
@@ -109,7 +109,7 @@ class CONTENT_EXPORT ServiceWorkerDevToolsManager {
ServiceWorkerDevToolsManager();
~ServiceWorkerDevToolsManager();
- base::ObserverList<Observer> observer_list_;
+ base::ObserverList<Observer>::Unchecked observer_list_;
bool debug_service_worker_on_start_;
// We retatin agent hosts as long as the service worker is alive.
diff --git a/chromium/content/browser/devtools/target_registry.cc b/chromium/content/browser/devtools/target_registry.cc
index 07d168aa79b..6250b22c8e5 100644
--- a/chromium/content/browser/devtools/target_registry.cc
+++ b/chromium/content/browser/devtools/target_registry.cc
@@ -9,35 +9,76 @@
namespace content {
+namespace {
+static const char kMethod[] = "method";
+static const char kResumeMethod[] = "Runtime.runIfWaitingForDebugger";
+} // namespace
+
+// static
+bool TargetRegistry::IsRuntimeResumeCommand(base::Value* value) {
+ if (value && value->is_dict()) {
+ base::Value* method = value->FindKey(kMethod);
+ return method && method->is_string() &&
+ method->GetString() == kResumeMethod;
+ }
+ return false;
+}
+
+struct TargetRegistry::SessionInfo {
+ SessionInfo(scoped_refptr<DevToolsAgentHostImpl> agent_host,
+ DevToolsAgentHostClient* client,
+ base::OnceClosure resume_if_throttled)
+ : agent_host(agent_host),
+ client(client),
+ resume_if_throttled(std::move(resume_if_throttled)) {}
+ scoped_refptr<DevToolsAgentHostImpl> agent_host;
+ DevToolsAgentHostClient* client;
+ base::OnceClosure resume_if_throttled;
+};
+
TargetRegistry::TargetRegistry(DevToolsSession* root_session)
: root_session_(root_session) {}
TargetRegistry::~TargetRegistry() {}
-void TargetRegistry::AttachSubtargetSession(const std::string& session_id,
- DevToolsAgentHostImpl* agent_host,
- DevToolsAgentHostClient* client) {
- sessions_[session_id] = std::make_pair(agent_host, client);
+void TargetRegistry::AttachSubtargetSession(
+ const std::string& session_id,
+ DevToolsAgentHostImpl* agent_host,
+ DevToolsAgentHostClient* client,
+ base::OnceClosure resume_if_throttled) {
+ sessions_[session_id] = std::make_unique<SessionInfo>(
+ agent_host, client, std::move(resume_if_throttled));
agent_host->AttachSubtargetClient(client, this);
}
void TargetRegistry::DetachSubtargetSession(const std::string& session_id) {
sessions_.erase(session_id);
}
-bool TargetRegistry::DispatchMessageOnAgentHost(
- const std::string& message,
+bool TargetRegistry::CanDispatchMessageOnAgentHost(
base::DictionaryValue* parsed_message) {
+ return parsed_message->FindKeyOfType("sessionId",
+ base::DictionaryValue::Type::STRING);
+}
+
+void TargetRegistry::DispatchMessageOnAgentHost(
+ const std::string& message,
+ std::unique_ptr<base::DictionaryValue> parsed_message) {
std::string session_id;
- if (!parsed_message->GetString("sessionId", &session_id))
- return false;
+ bool result = parsed_message->GetString("sessionId", &session_id);
+ DCHECK(result);
auto it = sessions_.find(session_id);
if (it == sessions_.end()) {
LOG(ERROR) << "Unknown session " << session_id;
- return true;
+ return;
+ }
+ scoped_refptr<DevToolsAgentHostImpl> agent_host = it->second->agent_host;
+ DevToolsAgentHostClient* client = it->second->client;
+ if (!it->second->resume_if_throttled.is_null() &&
+ IsRuntimeResumeCommand(parsed_message.get())) {
+ std::move(it->second->resume_if_throttled).Run();
}
- scoped_refptr<DevToolsAgentHostImpl> agent_host = it->second.first;
- DevToolsAgentHostClient* client = it->second.second;
- return agent_host->DispatchProtocolMessage(client, message, parsed_message);
+ agent_host->DispatchProtocolMessage(client, message,
+ std::move(parsed_message));
}
void TargetRegistry::SendMessageToClient(const std::string& session_id,
diff --git a/chromium/content/browser/devtools/target_registry.h b/chromium/content/browser/devtools/target_registry.h
index d915e1f1368..9892da5507e 100644
--- a/chromium/content/browser/devtools/target_registry.h
+++ b/chromium/content/browser/devtools/target_registry.h
@@ -7,6 +7,7 @@
#include <string>
+#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/containers/flat_map.h"
#include "base/values.h"
@@ -18,24 +19,27 @@ class DevToolsSession;
class TargetRegistry {
public:
+ static bool IsRuntimeResumeCommand(base::Value* value);
+
explicit TargetRegistry(DevToolsSession* root_session);
~TargetRegistry();
void AttachSubtargetSession(const std::string& session_id,
DevToolsAgentHostImpl* agent_host,
- DevToolsAgentHostClient* client);
+ DevToolsAgentHostClient* client,
+ base::OnceClosure resume_if_throttled);
void DetachSubtargetSession(const std::string& session_id);
- bool DispatchMessageOnAgentHost(const std::string& message,
- base::DictionaryValue* parsed_message);
+ bool CanDispatchMessageOnAgentHost(base::DictionaryValue* parsed_message);
+ void DispatchMessageOnAgentHost(
+ const std::string& message,
+ std::unique_ptr<base::DictionaryValue> parsed_message);
void SendMessageToClient(const std::string& session_id,
const std::string& message);
private:
DevToolsSession* root_session_;
- base::flat_map<
- std::string,
- std::pair<scoped_refptr<DevToolsAgentHostImpl>, DevToolsAgentHostClient*>>
- sessions_;
+ struct SessionInfo;
+ base::flat_map<std::string, std::unique_ptr<SessionInfo>> sessions_;
DISALLOW_COPY_AND_ASSIGN(TargetRegistry);
};
diff --git a/chromium/content/browser/display_cutout/display_cutout_host_impl.cc b/chromium/content/browser/display_cutout/display_cutout_host_impl.cc
index 4785df22f40..5d61832fc4e 100644
--- a/chromium/content/browser/display_cutout/display_cutout_host_impl.cc
+++ b/chromium/content/browser/display_cutout/display_cutout_host_impl.cc
@@ -12,12 +12,8 @@
namespace content {
-DisplayCutoutHostImpl::DisplayCutoutHostImpl(
- WebContentsImpl* web_contents,
- ViewportFitChangedCallback callback)
- : WebContentsObserver(web_contents),
- viewport_fit_changed_callback_(callback),
- bindings_(web_contents, this) {}
+DisplayCutoutHostImpl::DisplayCutoutHostImpl(WebContentsImpl* web_contents)
+ : bindings_(web_contents, this), web_contents_impl_(web_contents) {}
DisplayCutoutHostImpl::~DisplayCutoutHostImpl() = default;
@@ -37,7 +33,7 @@ void DisplayCutoutHostImpl::ViewportFitChangedForFrame(
// If we are the current |RenderFrameHost| frame then notify
// WebContentsObservers about the new value.
if (current_rfh_ == rfh)
- viewport_fit_changed_callback_.Run(value);
+ web_contents_impl_->NotifyViewportFitChanged(value);
MaybeQueueUKMEvent(rfh);
}
@@ -46,11 +42,8 @@ void DisplayCutoutHostImpl::DidAcquireFullscreen(RenderFrameHost* rfh) {
SetCurrentRenderFrameHost(rfh);
}
-void DisplayCutoutHostImpl::DidToggleFullscreenModeForTab(
- bool entered_fullscreen,
- bool will_cause_resize) {
- if (!entered_fullscreen)
- SetCurrentRenderFrameHost(nullptr);
+void DisplayCutoutHostImpl::DidExitFullscreen() {
+ SetCurrentRenderFrameHost(nullptr);
}
void DisplayCutoutHostImpl::DidStartNavigation(
@@ -78,11 +71,10 @@ void DisplayCutoutHostImpl::DidFinishNavigation(
// fullscreen then we should make the main frame the current
// |RenderFrameHost|.
RenderWidgetHostImpl* rwh =
- web_contents_impl()->GetRenderViewHost()->GetWidget();
- blink::WebDisplayMode mode = web_contents_impl()->GetDisplayMode(rwh);
- if (mode == blink::WebDisplayMode::kWebDisplayModeFullscreen) {
- SetCurrentRenderFrameHost(web_contents_impl()->GetMainFrame());
- }
+ web_contents_impl_->GetRenderViewHost()->GetWidget();
+ blink::WebDisplayMode mode = web_contents_impl_->GetDisplayMode(rwh);
+ if (mode == blink::WebDisplayMode::kWebDisplayModeFullscreen)
+ SetCurrentRenderFrameHost(web_contents_impl_->GetMainFrame());
}
void DisplayCutoutHostImpl::RenderFrameDeleted(RenderFrameHost* rfh) {
@@ -132,7 +124,8 @@ void DisplayCutoutHostImpl::SetCurrentRenderFrameHost(RenderFrameHost* rfh) {
// If the new RenderFrameHost is nullptr we should stop here and notify
// observers that the new viewport fit is kAuto (the default).
if (!rfh) {
- viewport_fit_changed_callback_.Run(blink::mojom::ViewportFit::kAuto);
+ web_contents_impl_->NotifyViewportFitChanged(
+ blink::mojom::ViewportFit::kAuto);
return;
}
@@ -143,7 +136,7 @@ void DisplayCutoutHostImpl::SetCurrentRenderFrameHost(RenderFrameHost* rfh) {
SendSafeAreaToFrame(rfh, insets_);
// Notify the WebContentsObservers that the viewport fit value has changed.
- viewport_fit_changed_callback_.Run(GetValueOrDefault(rfh));
+ web_contents_impl_->NotifyViewportFitChanged(GetValueOrDefault(rfh));
}
void DisplayCutoutHostImpl::SendSafeAreaToFrame(RenderFrameHost* rfh,
@@ -167,10 +160,6 @@ blink::mojom::ViewportFit DisplayCutoutHostImpl::GetValueOrDefault(
return blink::mojom::ViewportFit::kAuto;
}
-WebContentsImpl* DisplayCutoutHostImpl::web_contents_impl() {
- return static_cast<WebContentsImpl*>(web_contents());
-}
-
void DisplayCutoutHostImpl::MaybeQueueUKMEvent(RenderFrameHost* frame) {
if (!frame)
return;
@@ -206,7 +195,7 @@ void DisplayCutoutHostImpl::MaybeQueueUKMEvent(RenderFrameHost* frame) {
void DisplayCutoutHostImpl::RecordPendingUKMEvents() {
for (const auto& event : pending_ukm_events_) {
ukm::builders::Layout_DisplayCutout_StateChanged builder(
- web_contents_impl()->GetUkmSourceIdForLastCommittedSource());
+ web_contents_impl_->GetUkmSourceIdForLastCommittedSource());
builder.SetIsMainFrame(event.is_main_frame);
builder.SetViewportFit_Applied(static_cast<int>(event.applied_value));
builder.SetViewportFit_Supplied(static_cast<int>(event.supplied_value));
diff --git a/chromium/content/browser/display_cutout/display_cutout_host_impl.h b/chromium/content/browser/display_cutout/display_cutout_host_impl.h
index eba70e23dac..3c24e135971 100644
--- a/chromium/content/browser/display_cutout/display_cutout_host_impl.h
+++ b/chromium/content/browser/display_cutout/display_cutout_host_impl.h
@@ -11,14 +11,9 @@
namespace content {
-class DisplayCutoutHostImpl : public blink::mojom::DisplayCutoutHost,
- public WebContentsObserver {
+class DisplayCutoutHostImpl : public blink::mojom::DisplayCutoutHost {
public:
- // Called when the effective viewport fit value has changed.
- using ViewportFitChangedCallback =
- base::RepeatingCallback<void(blink::mojom::ViewportFit)>;
-
- DisplayCutoutHostImpl(WebContentsImpl*, ViewportFitChangedCallback);
+ explicit DisplayCutoutHostImpl(WebContentsImpl*);
~DisplayCutoutHostImpl() override;
// blink::mojom::DisplayCutoutHost
@@ -29,15 +24,14 @@ class DisplayCutoutHostImpl : public blink::mojom::DisplayCutoutHost,
void ViewportFitChangedForFrame(RenderFrameHost* rfh,
blink::mojom::ViewportFit value);
- // WebContentsObserver override.
- void DidAcquireFullscreen(RenderFrameHost* rfh) override;
- void DidToggleFullscreenModeForTab(bool entered_fullscreen,
- bool will_cause_resize) override;
- void DidStartNavigation(NavigationHandle* navigation_handle) override;
- void DidFinishNavigation(NavigationHandle* navigation_handle) override;
- void RenderFrameDeleted(RenderFrameHost* rfh) override;
- void RenderFrameCreated(RenderFrameHost* rfh) override;
- void WebContentsDestroyed() override;
+ // Called by WebContents when various events occur.
+ void DidAcquireFullscreen(RenderFrameHost* rfh);
+ void DidExitFullscreen();
+ void DidStartNavigation(NavigationHandle* navigation_handle);
+ void DidFinishNavigation(NavigationHandle* navigation_handle);
+ void RenderFrameDeleted(RenderFrameHost* rfh);
+ void RenderFrameCreated(RenderFrameHost* rfh);
+ void WebContentsDestroyed();
// Updates the safe area insets on the current frame.
void SetDisplayCutoutSafeArea(gfx::Insets insets);
@@ -63,8 +57,6 @@ class DisplayCutoutHostImpl : public blink::mojom::DisplayCutoutHost,
// stored value.
blink::mojom::ViewportFit GetValueOrDefault(RenderFrameHost* rfh) const;
- WebContentsImpl* web_contents_impl();
-
// Builds and records a Layout.DisplayCutout.StateChanged UKM event for the
// provided |frame|. The event will be added to the list of pending events.
void MaybeQueueUKMEvent(RenderFrameHost* frame);
@@ -88,11 +80,13 @@ class DisplayCutoutHostImpl : public blink::mojom::DisplayCutoutHost,
// Stores a map of RenderFrameHosts and their current viewport fit values.
std::map<RenderFrameHost*, blink::mojom::ViewportFit> values_;
- // Stores the callback for when the effective viewport fit value has changed.
- ViewportFitChangedCallback viewport_fit_changed_callback_;
-
// Holds WebContents associated mojo bindings.
WebContentsFrameBindingSet<blink::mojom::DisplayCutoutHost> bindings_;
+
+ // Weak pointer to the owning |WebContentsImpl| instance.
+ WebContentsImpl* web_contents_impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(DisplayCutoutHostImpl);
};
} // namespace content
diff --git a/chromium/content/browser/do_not_track_browsertest.cc b/chromium/content/browser/do_not_track_browsertest.cc
index 83c39160e4c..1aa00dc5b57 100644
--- a/chromium/content/browser/do_not_track_browsertest.cc
+++ b/chromium/content/browser/do_not_track_browsertest.cc
@@ -267,6 +267,103 @@ IN_PROC_BROWSER_TEST_F(DoNotTrackTest, FetchFromServiceWorker) {
ExpectPageTextEq("1");
}
+// Checks that the DNT header is preserved when fetching from a page controlled
+// by a service worker which doesn't have a fetch handler and falls back to the
+// network.
+IN_PROC_BROWSER_TEST_F(DoNotTrackTest,
+ FetchFromServiceWorkerControlledPage_NoFetchHandler) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ if (!EnableDoNotTrack())
+ return;
+
+ {
+ // Register a service worker which controls /service_worker.
+ const GURL url = embedded_test_server()->GetURL(
+ "/service_worker/create_service_worker.html?"
+ "worker_url=/service_worker/empty.js");
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+ const base::string16 title = base::ASCIIToUTF16("DONE");
+ TitleWatcher watcher(shell()->web_contents(), title);
+ EXPECT_EQ(title, watcher.WaitAndGetTitle());
+ }
+
+ {
+ // Issue a request from a controlled page.
+ const GURL url = embedded_test_server()->GetURL(
+ "/service_worker/fetch_from_page.html?url=/echoheader?DNT");
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+ const base::string16 title = base::ASCIIToUTF16("DONE");
+ TitleWatcher watcher(shell()->web_contents(), title);
+ EXPECT_EQ(title, watcher.WaitAndGetTitle());
+ }
+
+ ExpectPageTextEq("1");
+}
+
+// Checks that the DNT header is preserved when fetching from a page controlled
+// by a service worker which has a fetch handler but falls back to the network.
+IN_PROC_BROWSER_TEST_F(DoNotTrackTest,
+ FetchFromServiceWorkerControlledPage_PassThrough) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ if (!EnableDoNotTrack())
+ return;
+
+ {
+ // Register a service worker which controls /service_worker.
+ const GURL url = embedded_test_server()->GetURL(
+ "/service_worker/create_service_worker.html?"
+ "worker_url=/service_worker/fetch_event_pass_through.js");
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+ const base::string16 title = base::ASCIIToUTF16("DONE");
+ TitleWatcher watcher(shell()->web_contents(), title);
+ EXPECT_EQ(title, watcher.WaitAndGetTitle());
+ }
+
+ {
+ // Issue a request from a controlled page.
+ const GURL url = embedded_test_server()->GetURL(
+ "/service_worker/fetch_from_page.html?url=/echoheader?DNT");
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+ const base::string16 title = base::ASCIIToUTF16("DONE");
+ TitleWatcher watcher(shell()->web_contents(), title);
+ EXPECT_EQ(title, watcher.WaitAndGetTitle());
+ }
+
+ ExpectPageTextEq("1");
+}
+
+// Checks that the DNT header is preserved when fetching from a page controlled
+// by a service worker which has a fetch handler and responds with fetch().
+IN_PROC_BROWSER_TEST_F(DoNotTrackTest,
+ FetchFromServiceWorkerControlledPage_RespondWithFetch) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ if (!EnableDoNotTrack())
+ return;
+
+ {
+ // Register a service worker which controls /service_worker.
+ const GURL url = embedded_test_server()->GetURL(
+ "/service_worker/create_service_worker.html?"
+ "worker_url=/service_worker/fetch_event_respond_with_fetch.js");
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+ const base::string16 title = base::ASCIIToUTF16("DONE");
+ TitleWatcher watcher(shell()->web_contents(), title);
+ EXPECT_EQ(title, watcher.WaitAndGetTitle());
+ }
+
+ {
+ // Issue a request from a controlled page.
+ const GURL url = embedded_test_server()->GetURL(
+ "/service_worker/fetch_from_page.html?url=/echoheader?DNT");
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+ const base::string16 title = base::ASCIIToUTF16("DONE");
+ TitleWatcher watcher(shell()->web_contents(), title);
+ EXPECT_EQ(title, watcher.WaitAndGetTitle());
+ }
+
+ ExpectPageTextEq("1");
+}
+
} // namespace
} // namespace content
diff --git a/chromium/content/browser/dom_storage/OWNERS b/chromium/content/browser/dom_storage/OWNERS
index 19d6324eaf3..60343af7f2a 100644
--- a/chromium/content/browser/dom_storage/OWNERS
+++ b/chromium/content/browser/dom_storage/OWNERS
@@ -1,5 +1,9 @@
+# Primary
dmurph@chromium.org
mek@chromium.org
+# Secondary
+pwnall@chromium.org
+
# TEAM: storage-dev@chromium.org
# COMPONENT: Blink>Storage>DOMStorage
diff --git a/chromium/content/browser/dom_storage/README.md b/chromium/content/browser/dom_storage/README.md
new file mode 100644
index 00000000000..803f4757cf9
--- /dev/null
+++ b/chromium/content/browser/dom_storage/README.md
@@ -0,0 +1,105 @@
+# DOM Storage
+
+*Under Contruction*
+
+# Session Storage (Mojo)
+
+*Under Contruction*
+
+The browser manages the lifetime of session storage namespaces with
+[SessionStorageNamespaceImpl](
+https://cs.chromium.org/chromium/src/content/browser/dom_storage/session_storage_namespace_impl.h).
+
+The object calls [`SessionStorageContextMojo::CreateSessionNamespace`](
+https://cs.chromium.org/chromium/src/content/browser/dom_storage/session_storage_context_mojo.h?dr=CSs&l=50)
+when it is created, and [`SessionStorageContextMojo::DeleteSessionNamespace`](
+https://cs.chromium.org/chromium/src/content/browser/dom_storage/session_storage_context_mojo.h?dr=CSs&l=53)
+when it's destructed.
+
+
+This object is primarily held by both the [`NavigationControllerImpl`](
+https://cs.chromium.org/chromium/src/content/browser/frame_host/navigation_controller_impl.h?dr=CSs&l=426)
+and in the [`ContentPlatformSpecificTabData`](
+https://cs.chromium.org/chromium/src/components/sessions/content/content_platform_specific_tab_data.h?dr=C&l=35)
+which is used to restore tabs. The services stores recent tab
+closures for possible browser restore [here](
+https://cs.chromium.org/chromium/src/components/sessions/core/tab_restore_service_helper.h?dr=C&l=186).
+
+In the future when it's fully mojo-ified, the lifetime will be managed by the
+mojo [`SessionStorageNamespace`](
+https://cs.chromium.org/chromium/src/content/common/storage_partition_service.mojom)
+which can be passed to the renderer and the session restore service. There will
+always need to be an ID though as we save this ID to disk in the session
+restore service.
+
+## High Level Access And Lifetime Flow
+
+ 1. Before a renderer tab is opened, a `SessionStorageNamespaceImpl` object is
+ created, which in turn calls
+ `SessionStorageContextMojo::CreateSessionNamespace`.
+ * This can happen by either navigation or session restore.
+ 1. The following can happen in any order:
+ * Renderer creation, usage, and destruction
+ * The `session_namespace_id` is sent to the renderer, which uses
+ `StorageParitionService` to access storage.
+ * The renderer is destroyed, calling
+ `SessionStorageContextMojo::DeleteSessionNamespace`.
+ * If `SetShouldPersist(true)` was not called (or called with false),
+ then the data is deleted from disk.
+ * `SetShouldPersist(true)` is called from the session restores service,
+ which means the data should NOT be deleted on disk when the namespace is
+ destroyed. This is called for all tabs that the session restore services
+ wants to persist to disk.
+ * The session restore service calls
+ `DomStorageContext::StartScavengingUnusedSessionStorage` to clean up any
+ namespaces that are on disk but were not used by any recreated tab. This
+ is an 'after startup task', and usually happens before `SetShouldPesist`
+ is called.
+
+## Possible Edge Case: Persisted Data vs Stale Disk Data
+
+Namespace is created, persisted, destroyed, and then we scavange unused session
+storage.
+
+Flow:
+ 1. `SessionStorageContextMojo::CreateSessionNamespace`
+ 1. `SetShouldPersist(true)`
+ 1. `SessionStorageContextMojo::DeleteSessionNamespace`
+ 1. `DomStorageContext::StartScavengingUnusedSessionStorage`
+ 1. The data should still reside on disk after scavenging.
+
+The namespace could accidentally be considered a 'leftover' namespace by the
+scavenging algorithm and deleted from disk.
+
+## Navigation Details
+
+When navigating from a previous frame, the previous frame will allocate a new
+session storage id for the new frame, as well as issue the 'clone' call [here](https://cs.chromium.org/chromium/src/content/renderer/render_view_impl.cc?q=RenderViewImpl::RenderViewImpl&l=1273).
+
+The `session_namespace_id` for a frame's session storage is stored in the
+`CreateNewWindowParams` object in [frame.mojom](https://cs.chromium.org/chromium/src/content/common/frame.mojom).
+
+If the frame wasn't created from a previous frame, the SessionStorage namespace
+object is created [here](https://cs.chromium.org/chromium/src/content/browser/frame_host/navigation_controller_impl.cc?type=cs&l=1904)
+and the id is accessed [here](https://cs.chromium.org/chromium/src/content/browser/renderer_host/render_view_host_impl.cc?type=cs&l=321).
+
+## Renderer Connection to Session Storage
+
+Renderers use the `session_namespace_id` from the `CreateNewWindowParams`. They
+access session storage by using [`StoragePartitionService::OpenSessionStorage`](
+https://cs.chromium.org/chromium/src/content/common/storage_partition_service.mojom),
+and then `SessionStorageNamespace::OpenArea` with the `session_namespace_id`.
+
+They can then bind to a `LevelDBWrapper` on a per-origin basis.
+
+## Session Restore Service Interaction
+
+A reference to the session is stored in the [`ContentPlatformSpecificTabData`](
+https://cs.chromium.org/chromium/src/components/sessions/content/content_platform_specific_tab_data.h?dr=C&l=35)
+which is used to restore recently closed tabs. The services stores recent tab
+closures for possible browser restore [here](
+https://cs.chromium.org/chromium/src/components/sessions/core/tab_restore_service_helper.h?dr=C&l=186).
+
+When tabs are inserted, the session storage service saves the id to disk [here](https://cs.chromium.org/chromium/src/chrome/browser/sessions/session_service.cc?type=cs&l=313)
+using the `commands` (which are saved to disk). The session id is also accessed
+here for saving in `commands` in `TabClosing` and `BuildCommandsForTab`.
diff --git a/chromium/content/browser/dom_storage/dom_storage_context_impl.h b/chromium/content/browser/dom_storage/dom_storage_context_impl.h
index c2177798926..2c1e6c8b229 100644
--- a/chromium/content/browser/dom_storage/dom_storage_context_impl.h
+++ b/chromium/content/browser/dom_storage/dom_storage_context_impl.h
@@ -217,7 +217,7 @@ class CONTENT_EXPORT DOMStorageContextImpl
scoped_refptr<DOMStorageTaskRunner> task_runner_;
// List of objects observing local storage events.
- base::ObserverList<EventObserver> event_observers_;
+ base::ObserverList<EventObserver>::Unchecked event_observers_;
// For diagnostic purposes.
base::circular_deque<std::string> recently_deleted_session_ids_;
diff --git a/chromium/content/browser/dom_storage/dom_storage_context_wrapper.cc b/chromium/content/browser/dom_storage/dom_storage_context_wrapper.cc
index 3d71c01f1ec..1f5335f00de 100644
--- a/chromium/content/browser/dom_storage/dom_storage_context_wrapper.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_context_wrapper.cc
@@ -19,7 +19,7 @@
#include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "content/browser/dom_storage/dom_storage_area.h"
@@ -35,7 +35,7 @@
#include "content/public/common/content_client.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
-#include "sql/connection.h"
+#include "sql/database.h"
namespace content {
namespace {
@@ -128,7 +128,7 @@ DOMStorageContextWrapper::DOMStorageContextWrapper(
base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
scoped_refptr<base::SequencedTaskRunner> commit_sequence =
base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::BACKGROUND,
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
legacy_localstorage_path_ =
@@ -173,7 +173,8 @@ DOMStorageContextWrapper::DOMStorageContextWrapper(
base::MemoryCoordinatorClientRegistry::GetInstance()->Register(this);
} else {
memory_pressure_listener_.reset(new base::MemoryPressureListener(
- base::Bind(&DOMStorageContextWrapper::OnMemoryPressure, this)));
+ base::BindRepeating(&DOMStorageContextWrapper::OnMemoryPressure,
+ base::Unretained(this))));
}
}
@@ -243,7 +244,7 @@ void DOMStorageContextWrapper::DeleteLocalStorage(const GURL& origin,
if (!legacy_localstorage_path_.empty()) {
context_->task_runner()->PostShutdownBlockingTask(
FROM_HERE, DOMStorageTaskRunner::PRIMARY_SEQUENCE,
- base::BindOnce(base::IgnoreResult(&sql::Connection::Delete),
+ base::BindOnce(base::IgnoreResult(&sql::Database::Delete),
legacy_localstorage_path_.Append(
DOMStorageArea::DatabaseFileNameFromOrigin(
url::Origin::Create(origin)))));
@@ -395,6 +396,7 @@ void DOMStorageContextWrapper::OpenLocalStorage(
void DOMStorageContextWrapper::OpenSessionStorage(
int process_id,
const std::string& namespace_id,
+ mojo::ReportBadMessageCallback bad_message_callback,
blink::mojom::SessionStorageNamespaceRequest request) {
if (!mojo_session_state_)
return;
@@ -403,9 +405,11 @@ void DOMStorageContextWrapper::OpenSessionStorage(
// as soon as that task is posted, mojo_state_ is set to null, preventing
// further tasks from being queued.
mojo_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&SessionStorageContextMojo::OpenSessionStorage,
- base::Unretained(mojo_session_state_),
- process_id, namespace_id, std::move(request)));
+ FROM_HERE,
+ base::BindOnce(&SessionStorageContextMojo::OpenSessionStorage,
+ base::Unretained(mojo_session_state_), process_id,
+ namespace_id, std::move(bad_message_callback),
+ std::move(request)));
}
void DOMStorageContextWrapper::SetLocalStorageDatabaseForTesting(
diff --git a/chromium/content/browser/dom_storage/dom_storage_context_wrapper.h b/chromium/content/browser/dom_storage/dom_storage_context_wrapper.h
index 9ab2eed323a..ac7e069f4c7 100644
--- a/chromium/content/browser/dom_storage/dom_storage_context_wrapper.h
+++ b/chromium/content/browser/dom_storage/dom_storage_context_wrapper.h
@@ -18,6 +18,7 @@
#include "content/browser/dom_storage/dom_storage_context_impl.h"
#include "content/common/content_export.h"
#include "content/public/browser/dom_storage_context.h"
+#include "mojo/public/cpp/bindings/message.h"
#include "third_party/blink/public/mojom/dom_storage/session_storage_namespace.mojom.h"
#include "third_party/blink/public/mojom/dom_storage/storage_area.mojom.h"
#include "url/origin.h"
@@ -83,6 +84,7 @@ class CONTENT_EXPORT DOMStorageContextWrapper
blink::mojom::StorageAreaRequest request);
void OpenSessionStorage(int process_id,
const std::string& namespace_id,
+ mojo::ReportBadMessageCallback bad_message_callback,
blink::mojom::SessionStorageNamespaceRequest request);
void SetLocalStorageDatabaseForTesting(
diff --git a/chromium/content/browser/dom_storage/dom_storage_database.cc b/chromium/content/browser/dom_storage/dom_storage_database.cc
index b260d7f3e46..2609b896ee6 100644
--- a/chromium/content/browser/dom_storage/dom_storage_database.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_database.cc
@@ -35,7 +35,7 @@ DOMStorageDatabase::~DOMStorageDatabase() {
if (known_to_be_empty_ && !file_path_.empty()) {
// Delete the db and any lingering journal file from disk.
Close();
- sql::Connection::Delete(file_path_);
+ sql::Database::Delete(file_path_);
}
}
@@ -148,7 +148,7 @@ bool DOMStorageDatabase::LazyOpen(bool create_if_needed) {
return false;
}
- db_.reset(new sql::Connection());
+ db_.reset(new sql::Database());
db_->set_histogram_tag("DOMStorageDatabase");
// This db does not use [meta] table, store mmap status data elsewhere.
@@ -173,7 +173,7 @@ bool DOMStorageDatabase::LazyOpen(bool create_if_needed) {
}
}
- // sql::Connection uses UTF-8 encoding, but WebCore style databases use
+ // sql::Database uses UTF-8 encoding, but WebCore style databases use
// UTF-16, so ensure we match.
ignore_result(db_->Execute("PRAGMA encoding=\"UTF-16\""));
@@ -186,12 +186,8 @@ bool DOMStorageDatabase::LazyOpen(bool create_if_needed) {
// and whether it's usable (i.e. not corrupted).
SchemaVersion current_version = DetectSchemaVersion();
- if (current_version == V2) {
+ if (current_version == V2)
return true;
- } else if (current_version == V1) {
- if (UpgradeVersion1To2())
- return true;
- }
}
// This is the exceptional case - to try and recover we'll attempt
@@ -206,7 +202,7 @@ DOMStorageDatabase::SchemaVersion DOMStorageDatabase::DetectSchemaVersion() {
// Connection::Open() may succeed even if the file we try and open is not a
// database, however in the case that the database is corrupted to the point
// that SQLite doesn't actually think it's a database,
- // sql::Connection::GetCachedStatement will DCHECK when we later try and
+ // sql::Database::GetCachedStatement will DCHECK when we later try and
// run statements. So we run a query here that will not DCHECK but fail
// on an invalid database to verify that what we've opened is usable.
if (db_->ExecuteAndReturnErrorCode("PRAGMA auto_vacuum") != SQLITE_OK)
@@ -218,20 +214,7 @@ DOMStorageDatabase::SchemaVersion DOMStorageDatabase::DetectSchemaVersion() {
!db_->DoesColumnExist("ItemTable", "value"))
return INVALID;
- // We must use a unique statement here as we aren't going to step it.
- sql::Statement statement(
- db_->GetUniqueStatement("SELECT key,value from ItemTable LIMIT 1"));
- if (statement.DeclaredColumnType(0) != sql::COLUMN_TYPE_TEXT)
- return INVALID;
-
- switch (statement.DeclaredColumnType(1)) {
- case sql::COLUMN_TYPE_BLOB:
- return V2;
- case sql::COLUMN_TYPE_TEXT:
- return V1;
- default:
- return INVALID;
- }
+ return V2;
}
bool DOMStorageDatabase::CreateTableV2() {
@@ -254,8 +237,7 @@ bool DOMStorageDatabase::DeleteFileAndRecreate() {
tried_to_recreate_ = true;
// If it's not a directory and we can delete the file, try and open it again.
- if (!base::DirectoryExists(file_path_) &&
- sql::Connection::Delete(file_path_)) {
+ if (!base::DirectoryExists(file_path_) && sql::Database::Delete(file_path_)) {
return LazyOpen(true);
}
@@ -263,32 +245,6 @@ bool DOMStorageDatabase::DeleteFileAndRecreate() {
return false;
}
-bool DOMStorageDatabase::UpgradeVersion1To2() {
- DCHECK(IsOpen());
- DCHECK(DetectSchemaVersion() == V1);
-
- sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE,
- "SELECT * FROM ItemTable"));
- DCHECK(statement.is_valid());
-
- // Need to migrate from TEXT value column to BLOB.
- // Store the current database content so we can re-insert
- // the data into the new V2 table.
- DOMStorageValuesMap values;
- while (statement.Step()) {
- base::string16 key = statement.ColumnString16(0);
- base::NullableString16 value(statement.ColumnString16(1), false);
- values[key] = value;
- }
-
- sql::Transaction migration(db_.get());
- return migration.Begin() &&
- db_->Execute("DROP TABLE ItemTable") &&
- CreateTableV2() &&
- CommitChanges(false, values) &&
- migration.Commit();
-}
-
void DOMStorageDatabase::Close() {
db_.reset(nullptr);
}
diff --git a/chromium/content/browser/dom_storage/dom_storage_database.h b/chromium/content/browser/dom_storage/dom_storage_database.h
index 5ea7d79329b..77bed12178c 100644
--- a/chromium/content/browser/dom_storage/dom_storage_database.h
+++ b/chromium/content/browser/dom_storage/dom_storage_database.h
@@ -15,7 +15,7 @@
#include "base/strings/string16.h"
#include "content/common/content_export.h"
#include "content/common/dom_storage/dom_storage_types.h"
-#include "sql/connection.h"
+#include "sql/database.h"
namespace base {
namespace trace_event {
@@ -80,8 +80,11 @@ class CONTENT_EXPORT DOMStorageDatabase {
enum SchemaVersion {
INVALID,
- V1,
- V2
+
+ // V1 is deprecated.
+
+ // 2011-07-15 - https://bugs.webkit.org/show_bug.cgi?id=58762
+ V2,
};
// Open the database at file_path_ if it exists already and creates it if
@@ -105,12 +108,6 @@ class CONTENT_EXPORT DOMStorageDatabase {
// scratch.
bool DeleteFileAndRecreate();
- // Version 1 -> 2 migrates the value column in the ItemTable from a TEXT
- // to a BLOB. Exisitng data is preserved on success. Returns false if the
- // upgrade failed. If true is returned, the database is guaranteed to be at
- // version 2.
- bool UpgradeVersion1To2();
-
void Close();
bool IsOpen() const { return db_.get() ? db_->is_open() : false; }
@@ -119,7 +116,7 @@ class CONTENT_EXPORT DOMStorageDatabase {
// Path to the database on disk.
const base::FilePath file_path_;
- std::unique_ptr<sql::Connection> db_;
+ std::unique_ptr<sql::Database> db_;
bool failed_to_open_;
bool tried_to_recreate_;
bool known_to_be_empty_;
diff --git a/chromium/content/browser/dom_storage/dom_storage_database_unittest.cc b/chromium/content/browser/dom_storage/dom_storage_database_unittest.cc
index d3b199a0e86..7c83def70b8 100644
--- a/chromium/content/browser/dom_storage/dom_storage_database_unittest.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_database_unittest.cc
@@ -18,16 +18,7 @@ using base::ASCIIToUTF16;
namespace content {
-void CreateV1Table(sql::Connection* db) {
- ASSERT_TRUE(db->is_open());
- ASSERT_TRUE(db->Execute("DROP TABLE IF EXISTS ItemTable"));
- ASSERT_TRUE(db->Execute(
- "CREATE TABLE ItemTable ("
- "key TEXT UNIQUE ON CONFLICT REPLACE, "
- "value TEXT NOT NULL ON CONFLICT FAIL)"));
-}
-
-void CreateV2Table(sql::Connection* db) {
+void CreateV2Table(sql::Database* db) {
ASSERT_TRUE(db->is_open());
ASSERT_TRUE(db->Execute("DROP TABLE IF EXISTS ItemTable"));
ASSERT_TRUE(db->Execute(
@@ -36,37 +27,15 @@ void CreateV2Table(sql::Connection* db) {
"value BLOB NOT NULL ON CONFLICT FAIL)"));
}
-void CreateInvalidKeyColumnTable(sql::Connection* db) {
- // Create a table with the key type as FLOAT - this is "invalid"
+void CreateInvalidTable(sql::Database* db) {
+ // Create a table with out a key column - this is "invalid"
// as far as the DOM Storage db is concerned.
ASSERT_TRUE(db->is_open());
ASSERT_TRUE(db->Execute("DROP TABLE IF EXISTS ItemTable"));
ASSERT_TRUE(db->Execute(
"CREATE TABLE IF NOT EXISTS ItemTable ("
- "key FLOAT UNIQUE ON CONFLICT REPLACE, "
"value BLOB NOT NULL ON CONFLICT FAIL)"));
}
-void CreateInvalidValueColumnTable(sql::Connection* db) {
- // Create a table with the value type as FLOAT - this is "invalid"
- // as far as the DOM Storage db is concerned.
- ASSERT_TRUE(db->is_open());
- ASSERT_TRUE(db->Execute("DROP TABLE IF EXISTS ItemTable"));
- ASSERT_TRUE(db->Execute(
- "CREATE TABLE IF NOT EXISTS ItemTable ("
- "key TEXT UNIQUE ON CONFLICT REPLACE, "
- "value FLOAT NOT NULL ON CONFLICT FAIL)"));
-}
-
-void InsertDataV1(sql::Connection* db,
- const base::string16& key,
- const base::string16& value) {
- sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE,
- "INSERT INTO ItemTable VALUES (?,?)"));
- statement.BindString16(0, key);
- statement.BindString16(1, value);
- ASSERT_TRUE(statement.is_valid());
- statement.Run();
-}
void CheckValuesMatch(DOMStorageDatabase* db,
const DOMStorageValuesMap& expected) {
@@ -198,42 +167,16 @@ TEST(DOMStorageDatabaseTest, TestLazyOpenIsLazy) {
TEST(DOMStorageDatabaseTest, TestDetectSchemaVersion) {
DOMStorageDatabase db;
- db.db_.reset(new sql::Connection());
+ db.db_.reset(new sql::Database());
ASSERT_TRUE(db.db_->OpenInMemory());
- CreateInvalidValueColumnTable(db.db_.get());
+ CreateInvalidTable(db.db_.get());
EXPECT_EQ(DOMStorageDatabase::INVALID, db.DetectSchemaVersion());
- CreateInvalidKeyColumnTable(db.db_.get());
- EXPECT_EQ(DOMStorageDatabase::INVALID, db.DetectSchemaVersion());
-
- CreateV1Table(db.db_.get());
- EXPECT_EQ(DOMStorageDatabase::V1, db.DetectSchemaVersion());
-
CreateV2Table(db.db_.get());
EXPECT_EQ(DOMStorageDatabase::V2, db.DetectSchemaVersion());
}
-TEST(DOMStorageDatabaseTest, TestLazyOpenUpgradesDatabase) {
- // This test needs to operate with a file on disk so that we
- // can create a table at version 1 and then close it again
- // so that LazyOpen sees there is work to do (LazyOpen will return
- // early if the database is already open).
- base::ScopedTempDir temp_dir;
- ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- base::FilePath file_name =
- temp_dir.GetPath().AppendASCII("TestDOMStorageDatabase.db");
-
- DOMStorageDatabase db(file_name);
- db.db_.reset(new sql::Connection());
- ASSERT_TRUE(db.db_->Open(file_name));
- CreateV1Table(db.db_.get());
- db.Close();
-
- EXPECT_TRUE(db.LazyOpen(true));
- EXPECT_EQ(DOMStorageDatabase::V2, db.DetectSchemaVersion());
-}
-
TEST(DOMStorageDatabaseTest, SimpleWriteAndReadBack) {
DOMStorageDatabase db;
@@ -266,25 +209,6 @@ TEST(DOMStorageDatabaseTest, WriteWithClear) {
CheckValuesMatch(&db, storage);
}
-TEST(DOMStorageDatabaseTest, UpgradeFromV1ToV2WithData) {
- const base::string16 kCannedKey = ASCIIToUTF16("foo");
- const base::NullableString16 kCannedValue(ASCIIToUTF16("bar"), false);
- DOMStorageValuesMap expected;
- expected[kCannedKey] = kCannedValue;
-
- DOMStorageDatabase db;
- db.db_.reset(new sql::Connection());
- ASSERT_TRUE(db.db_->OpenInMemory());
- CreateV1Table(db.db_.get());
- InsertDataV1(db.db_.get(), kCannedKey, kCannedValue.string());
-
- ASSERT_TRUE(db.UpgradeVersion1To2());
-
- EXPECT_EQ(DOMStorageDatabase::V2, db.DetectSchemaVersion());
-
- CheckValuesMatch(&db, expected);
-}
-
TEST(DOMStorageDatabaseTest, TestSimpleRemoveOneValue) {
DOMStorageDatabase db;
diff --git a/chromium/content/browser/dom_storage/local_storage_context_mojo.cc b/chromium/content/browser/dom_storage/local_storage_context_mojo.cc
index 3d90057ed86..2ace7b3ef8b 100644
--- a/chromium/content/browser/dom_storage/local_storage_context_mojo.cc
+++ b/chromium/content/browser/dom_storage/local_storage_context_mojo.cc
@@ -32,7 +32,7 @@
#include "content/public/browser/local_storage_usage_info.h"
#include "services/file/public/mojom/constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
-#include "sql/connection.h"
+#include "sql/database.h"
#include "storage/browser/quota/special_storage_policy.h"
#include "third_party/leveldatabase/env_chromium.h"
#include "third_party/leveldatabase/leveldb_chrome.h"
@@ -264,7 +264,7 @@ class LocalStorageContextMojo::StorageAreaHolder final
deleted_old_data_ = true;
context_->task_runner_->PostShutdownBlockingTask(
FROM_HERE, DOMStorageTaskRunner::PRIMARY_SEQUENCE,
- base::BindOnce(base::IgnoreResult(&sql::Connection::Delete),
+ base::BindOnce(base::IgnoreResult(&sql::Database::Delete),
sql_db_path()));
}
diff --git a/chromium/content/browser/dom_storage/local_storage_context_mojo_unittest.cc b/chromium/content/browser/dom_storage/local_storage_context_mojo_unittest.cc
index a01c79873af..1a9716341c2 100644
--- a/chromium/content/browser/dom_storage/local_storage_context_mojo_unittest.cc
+++ b/chromium/content/browser/dom_storage/local_storage_context_mojo_unittest.cc
@@ -1081,7 +1081,6 @@ TEST_F(LocalStorageContextMojoTestWithService, RecreateOnCommitFailure) {
area1->Put(key, value, base::nullopt, "source",
base::BindLambdaForTesting([&](bool success) {
EXPECT_TRUE(success);
- put_loop.Quit();
}));
put_loop.RunUntilIdle();
values_written++;
@@ -1093,6 +1092,7 @@ TEST_F(LocalStorageContextMojoTestWithService, RecreateOnCommitFailure) {
// Make sure all messages to the DB have been processed (Flush above merely
// schedules a commit, but there is no guarantee about those having been
// processed yet).
+ mock_leveldb_service.FlushBindingsForTesting();
if (mock_db)
mock_db->FlushForTesting();
// At this point enough commit failures should have happened to cause the
diff --git a/chromium/content/browser/dom_storage/session_storage_area_impl_unittest.cc b/chromium/content/browser/dom_storage/session_storage_area_impl_unittest.cc
index 7fdc77561d6..30a580275b7 100644
--- a/chromium/content/browser/dom_storage/session_storage_area_impl_unittest.cc
+++ b/chromium/content/browser/dom_storage/session_storage_area_impl_unittest.cc
@@ -12,7 +12,7 @@
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/sequenced_task_runner.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/test/bind_test_util.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread.h"
diff --git a/chromium/content/browser/dom_storage/session_storage_context_mojo.cc b/chromium/content/browser/dom_storage/session_storage_context_mojo.cc
index a3998a49115..f64bab5bd63 100644
--- a/chromium/content/browser/dom_storage/session_storage_context_mojo.cc
+++ b/chromium/content/browser/dom_storage/session_storage_context_mojo.cc
@@ -121,25 +121,25 @@ SessionStorageContextMojo::~SessionStorageContextMojo() {
void SessionStorageContextMojo::OpenSessionStorage(
int process_id,
const std::string& namespace_id,
+ mojo::ReportBadMessageCallback bad_message_callback,
blink::mojom::SessionStorageNamespaceRequest request) {
if (connection_state_ != CONNECTION_FINISHED) {
RunWhenConnected(
base::BindOnce(&SessionStorageContextMojo::OpenSessionStorage,
weak_ptr_factory_.GetWeakPtr(), process_id, namespace_id,
- std::move(request)));
+ std::move(bad_message_callback), std::move(request)));
return;
}
auto found = namespaces_.find(namespace_id);
if (found == namespaces_.end()) {
- mojo::ReportBadMessage("Namespace not found: " + namespace_id);
+ std::move(bad_message_callback).Run("Namespace not found: " + namespace_id);
return;
}
if (!found->second->IsPopulated() &&
!found->second->waiting_on_clone_population()) {
found->second->PopulateFromMetadata(
- database_.get(), metadata_.GetOrCreateNamespaceEntry(namespace_id),
- data_maps_);
+ database_.get(), metadata_.GetOrCreateNamespaceEntry(namespace_id));
}
PurgeUnusedAreasIfNeeded();
@@ -439,6 +439,39 @@ bool SessionStorageContextMojo::OnMemoryDump(
return true;
}
+void SessionStorageContextMojo::SetDatabaseForTesting(
+ leveldb::mojom::LevelDBDatabaseAssociatedPtr database) {
+ DCHECK_EQ(connection_state_, NO_CONNECTION);
+ connection_state_ = CONNECTION_IN_PROGRESS;
+ database_ = std::move(database);
+ OnDatabaseOpened(true, leveldb::mojom::DatabaseError::OK);
+}
+
+void SessionStorageContextMojo::FlushAreaForTesting(
+ const std::string& namespace_id,
+ const url::Origin& origin) {
+ if (connection_state_ != CONNECTION_FINISHED)
+ return;
+ const auto& it = namespaces_.find(namespace_id);
+ if (it == namespaces_.end())
+ return;
+ it->second->FlushOriginForTesting(origin);
+}
+
+scoped_refptr<SessionStorageMetadata::MapData>
+SessionStorageContextMojo::RegisterNewAreaMap(
+ SessionStorageMetadata::NamespaceEntry namespace_entry,
+ const url::Origin& origin) {
+ std::vector<leveldb::mojom::BatchedOperationPtr> save_operations;
+ scoped_refptr<SessionStorageMetadata::MapData> map_entry =
+ metadata_.RegisterNewMap(namespace_entry, origin, &save_operations);
+
+ database_->Write(std::move(save_operations),
+ base::BindOnce(&SessionStorageContextMojo::OnCommitResult,
+ base::Unretained(this)));
+ return map_entry;
+}
+
void SessionStorageContextMojo::OnDataMapCreation(
const std::vector<uint8_t>& map_prefix,
SessionStorageDataMap* map) {
@@ -481,37 +514,13 @@ void SessionStorageContextMojo::OnCommitResult(
}
}
-void SessionStorageContextMojo::SetDatabaseForTesting(
- leveldb::mojom::LevelDBDatabaseAssociatedPtr database) {
- DCHECK_EQ(connection_state_, NO_CONNECTION);
- connection_state_ = CONNECTION_IN_PROGRESS;
- database_ = std::move(database);
- OnDatabaseOpened(true, leveldb::mojom::DatabaseError::OK);
-}
-
-void SessionStorageContextMojo::FlushAreaForTesting(
- const std::string& namespace_id,
- const url::Origin& origin) {
- if (connection_state_ != CONNECTION_FINISHED)
- return;
- const auto& it = namespaces_.find(namespace_id);
- if (it == namespaces_.end())
- return;
- it->second->FlushOriginForTesting(origin);
-}
-
-scoped_refptr<SessionStorageMetadata::MapData>
-SessionStorageContextMojo::RegisterNewAreaMap(
- SessionStorageMetadata::NamespaceEntry namespace_entry,
- const url::Origin& origin) {
- std::vector<leveldb::mojom::BatchedOperationPtr> save_operations;
- scoped_refptr<SessionStorageMetadata::MapData> map_entry =
- metadata_.RegisterNewMap(namespace_entry, origin, &save_operations);
-
- database_->Write(std::move(save_operations),
- base::BindOnce(&SessionStorageContextMojo::OnCommitResult,
- base::Unretained(this)));
- return map_entry;
+scoped_refptr<SessionStorageDataMap>
+SessionStorageContextMojo::MaybeGetExistingDataMapForId(
+ const std::vector<uint8_t>& map_number_as_bytes) {
+ auto it = data_maps_.find(map_number_as_bytes);
+ if (it == data_maps_.end())
+ return nullptr;
+ return base::WrapRefCounted(it->second);
}
void SessionStorageContextMojo::RegisterShallowClonedNamespace(
@@ -525,6 +534,7 @@ void SessionStorageContextMojo::RegisterShallowClonedNamespace(
if (it != namespaces_.end()) {
found = true;
if (it->second->IsPopulated()) {
+ // Assumes this method is called on a stack handling a mojo message.
mojo::ReportBadMessage("Cannot clone to already populated namespace");
return;
}
@@ -555,17 +565,12 @@ void SessionStorageContextMojo::RegisterShallowClonedNamespace(
std::unique_ptr<SessionStorageNamespaceImplMojo>
SessionStorageContextMojo::CreateSessionStorageNamespaceImplMojo(
std::string namespace_id) {
- SessionStorageNamespaceImplMojo::RegisterShallowClonedNamespace
- add_namespace_callback = base::BindRepeating(
- &SessionStorageContextMojo::RegisterShallowClonedNamespace,
- base::Unretained(this));
SessionStorageAreaImpl::RegisterNewAreaMap map_id_callback =
base::BindRepeating(&SessionStorageContextMojo::RegisterNewAreaMap,
base::Unretained(this));
return std::make_unique<SessionStorageNamespaceImplMojo>(
- std::move(namespace_id), this, std::move(add_namespace_callback),
- std::move(map_id_callback));
+ std::move(namespace_id), this, std::move(map_id_callback), this);
}
void SessionStorageContextMojo::DoDatabaseDelete(
diff --git a/chromium/content/browser/dom_storage/session_storage_context_mojo.h b/chromium/content/browser/dom_storage/session_storage_context_mojo.h
index 9a4c3aa3d20..3cf456dc89a 100644
--- a/chromium/content/browser/dom_storage/session_storage_context_mojo.h
+++ b/chromium/content/browser/dom_storage/session_storage_context_mojo.h
@@ -23,6 +23,7 @@
#include "content/browser/dom_storage/session_storage_namespace_impl_mojo.h"
#include "content/common/content_export.h"
#include "content/public/browser/session_storage_usage_info.h"
+#include "mojo/public/cpp/bindings/message.h"
#include "services/file/public/mojom/file_system.mojom.h"
#include "third_party/blink/public/mojom/dom_storage/session_storage_namespace.mojom.h"
#include "url/origin.h"
@@ -45,7 +46,8 @@ struct SessionStorageUsageInfo;
// ShutdownAndDelete (on the correct task runner).
class CONTENT_EXPORT SessionStorageContextMojo
: public base::trace_event::MemoryDumpProvider,
- public SessionStorageDataMap::Listener {
+ public SessionStorageDataMap::Listener,
+ public SessionStorageNamespaceImplMojo::Delegate {
public:
using GetStorageUsageCallback =
base::OnceCallback<void(std::vector<SessionStorageUsageInfo>)>;
@@ -82,6 +84,7 @@ class CONTENT_EXPORT SessionStorageContextMojo
void OpenSessionStorage(int process_id,
const std::string& namespace_id,
+ mojo::ReportBadMessageCallback bad_message_callback,
blink::mojom::SessionStorageNamespaceRequest request);
void CreateSessionNamespace(const std::string& namespace_id);
@@ -123,12 +126,6 @@ class CONTENT_EXPORT SessionStorageContextMojo
bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
base::trace_event::ProcessMemoryDump* pmd) override;
- // SessionStorageAreaImpl::Listener implementation:
- void OnDataMapCreation(const std::vector<uint8_t>& map_prefix,
- SessionStorageDataMap* map) override;
- void OnDataMapDestruction(const std::vector<uint8_t>& map_prefix) override;
- void OnCommitResult(leveldb::mojom::DatabaseError error) override;
-
// Sets the database for testing.
void SetDatabaseForTesting(
leveldb::mojom::LevelDBDatabaseAssociatedPtr database);
@@ -152,10 +149,20 @@ class CONTENT_EXPORT SessionStorageContextMojo
SessionStorageMetadata::NamespaceEntry namespace_entry,
const url::Origin& origin);
+ // SessionStorageAreaImpl::Listener implementation:
+ void OnDataMapCreation(const std::vector<uint8_t>& map_prefix,
+ SessionStorageDataMap* map) override;
+ void OnDataMapDestruction(const std::vector<uint8_t>& map_prefix) override;
+ void OnCommitResult(leveldb::mojom::DatabaseError error) override;
+
+ // SessionStorageNamespaceImplMojo::Delegate implementation:
+ scoped_refptr<SessionStorageDataMap> MaybeGetExistingDataMapForId(
+ const std::vector<uint8_t>& map_number_as_bytes) override;
void RegisterShallowClonedNamespace(
SessionStorageMetadata::NamespaceEntry source_namespace_entry,
const std::string& new_namespace_id,
- const SessionStorageNamespaceImplMojo::OriginAreas& clone_from_areas);
+ const SessionStorageNamespaceImplMojo::OriginAreas& clone_from_areas)
+ override;
std::unique_ptr<SessionStorageNamespaceImplMojo>
CreateSessionStorageNamespaceImplMojo(std::string namespace_id);
diff --git a/chromium/content/browser/dom_storage/session_storage_context_mojo_unittest.cc b/chromium/content/browser/dom_storage/session_storage_context_mojo_unittest.cc
index f09686f30e9..d7584324c3c 100644
--- a/chromium/content/browser/dom_storage/session_storage_context_mojo_unittest.cc
+++ b/chromium/content/browser/dom_storage/session_storage_context_mojo_unittest.cc
@@ -72,6 +72,11 @@ class SessionStorageContextMojoTest : public test::MojoTestWithFileService {
mojo::core::ProcessErrorCallback());
}
+ mojo::ReportBadMessageCallback GetBadMessageCallback() {
+ return base::BindOnce(&SessionStorageContextMojoTest::OnBadMessage,
+ base::Unretained(this));
+ }
+
void OnBadMessage(const std::string& reason) { bad_message_called_ = true; }
void SetBackingMode(SessionStorageContextMojo::BackingMode backing_mode) {
@@ -111,6 +116,7 @@ class SessionStorageContextMojoTest : public test::MojoTestWithFileService {
context()->CreateSessionNamespace(namespace_id);
blink::mojom::SessionStorageNamespacePtr ss_namespace;
context()->OpenSessionStorage(kTestProcessId, namespace_id,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace));
blink::mojom::StorageAreaAssociatedPtr leveldb;
ss_namespace->OpenArea(origin, mojo::MakeRequest(&leveldb));
@@ -127,6 +133,7 @@ class SessionStorageContextMojoTest : public test::MojoTestWithFileService {
context()->CreateSessionNamespace(namespace_id);
blink::mojom::SessionStorageNamespacePtr ss_namespace;
context()->OpenSessionStorage(kTestProcessId, namespace_id,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace));
blink::mojom::StorageAreaAssociatedPtr leveldb;
ss_namespace->OpenArea(origin, mojo::MakeRequest(&leveldb));
@@ -188,9 +195,11 @@ TEST_F(SessionStorageContextMojoTest, MigrationV0ToV1) {
blink::mojom::SessionStorageNamespacePtr ss_namespace1;
context()->OpenSessionStorage(kTestProcessId, namespace_id1,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace1));
blink::mojom::SessionStorageNamespacePtr ss_namespace2;
context()->OpenSessionStorage(kTestProcessId, namespace_id2,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace2));
blink::mojom::StorageAreaAssociatedPtr leveldb_n2_o1;
@@ -220,6 +229,7 @@ TEST_F(SessionStorageContextMojoTest, StartupShutdownSave) {
blink::mojom::SessionStorageNamespacePtr ss_namespace1;
context()->OpenSessionStorage(kTestProcessId, namespace_id1,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace1));
blink::mojom::StorageAreaAssociatedPtr leveldb_n1_o1;
@@ -247,6 +257,7 @@ TEST_F(SessionStorageContextMojoTest, StartupShutdownSave) {
// This will re-open the context, and load the persisted namespace.
context()->CreateSessionNamespace(namespace_id1);
context()->OpenSessionStorage(kTestProcessId, namespace_id1,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace1));
ss_namespace1->OpenArea(origin1, mojo::MakeRequest(&leveldb_n1_o1));
@@ -261,6 +272,7 @@ TEST_F(SessionStorageContextMojoTest, StartupShutdownSave) {
// This will re-open the context, and the namespace should be empty.
context()->CreateSessionNamespace(namespace_id1);
context()->OpenSessionStorage(kTestProcessId, namespace_id1,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace1));
ss_namespace1->OpenArea(origin1, mojo::MakeRequest(&leveldb_n1_o1));
@@ -276,6 +288,7 @@ TEST_F(SessionStorageContextMojoTest, CloneBeforeBrowserClone) {
context()->CreateSessionNamespace(namespace_id1);
blink::mojom::SessionStorageNamespacePtr ss_namespace1;
context()->OpenSessionStorage(kTestProcessId, namespace_id1,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace1));
blink::mojom::StorageAreaAssociatedPtr leveldb_n1_o1;
ss_namespace1->OpenArea(origin1, mojo::MakeRequest(&leveldb_n1_o1));
@@ -296,6 +309,7 @@ TEST_F(SessionStorageContextMojoTest, CloneBeforeBrowserClone) {
// Open the second namespace.
blink::mojom::SessionStorageNamespacePtr ss_namespace2;
context()->OpenSessionStorage(kTestProcessId, namespace_id2,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace2));
blink::mojom::StorageAreaAssociatedPtr leveldb_n2_o1;
ss_namespace2->OpenArea(origin1, mojo::MakeRequest(&leveldb_n2_o1));
@@ -313,6 +327,7 @@ TEST_F(SessionStorageContextMojoTest, Cloning) {
context()->CreateSessionNamespace(namespace_id1);
blink::mojom::SessionStorageNamespacePtr ss_namespace1;
context()->OpenSessionStorage(kTestProcessId, namespace_id1,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace1));
blink::mojom::StorageAreaAssociatedPtr leveldb_n1_o1;
ss_namespace1->OpenArea(origin1, mojo::MakeRequest(&leveldb_n1_o1));
@@ -334,6 +349,7 @@ TEST_F(SessionStorageContextMojoTest, Cloning) {
// Open the second namespace.
blink::mojom::SessionStorageNamespacePtr ss_namespace2;
context()->OpenSessionStorage(kTestProcessId, namespace_id2,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace2));
blink::mojom::StorageAreaAssociatedPtr leveldb_n2_o1;
ss_namespace2->OpenArea(origin1, mojo::MakeRequest(&leveldb_n2_o1));
@@ -358,6 +374,7 @@ TEST_F(SessionStorageContextMojoTest, Cloning) {
// Re-open namespace 1, check that we don't have the extra data.
context()->CreateSessionNamespace(namespace_id1);
context()->OpenSessionStorage(kTestProcessId, namespace_id1,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace1));
ss_namespace1->OpenArea(origin1, mojo::MakeRequest(&leveldb_n1_o1));
@@ -374,6 +391,7 @@ TEST_F(SessionStorageContextMojoTest, ImmediateCloning) {
context()->CreateSessionNamespace(namespace_id1);
blink::mojom::SessionStorageNamespacePtr ss_namespace1;
context()->OpenSessionStorage(kTestProcessId, namespace_id1,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace1));
blink::mojom::StorageAreaAssociatedPtr leveldb_n1_o1;
ss_namespace1->OpenArea(origin1, mojo::MakeRequest(&leveldb_n1_o1));
@@ -387,6 +405,7 @@ TEST_F(SessionStorageContextMojoTest, ImmediateCloning) {
{
blink::mojom::SessionStorageNamespacePtr ss_namespace2;
context()->OpenSessionStorage(kTestProcessId, namespace_id2,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace2));
blink::mojom::StorageAreaAssociatedPtr leveldb_n2_o1;
ss_namespace2->OpenArea(origin1, mojo::MakeRequest(&leveldb_n2_o1));
@@ -411,6 +430,7 @@ TEST_F(SessionStorageContextMojoTest, ImmediateCloning) {
{
blink::mojom::SessionStorageNamespacePtr ss_namespace2;
context()->OpenSessionStorage(kTestProcessId, namespace_id2,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace2));
blink::mojom::StorageAreaAssociatedPtr leveldb_n2_o1;
ss_namespace2->OpenArea(origin1, mojo::MakeRequest(&leveldb_n2_o1));
@@ -457,6 +477,7 @@ TEST_F(SessionStorageContextMojoTest, Scavenging) {
blink::mojom::SessionStorageNamespacePtr ss_namespace1;
context()->OpenSessionStorage(kTestProcessId, namespace_id1,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace1));
blink::mojom::StorageAreaAssociatedPtr leveldb_n1_o1;
ss_namespace1->OpenArea(origin1, mojo::MakeRequest(&leveldb_n1_o1));
@@ -490,6 +511,7 @@ TEST_F(SessionStorageContextMojoTest, Scavenging) {
// data.
context()->CreateSessionNamespace(namespace_id1);
context()->OpenSessionStorage(kTestProcessId, namespace_id1,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace1));
ss_namespace1->OpenArea(origin1, mojo::MakeRequest(&leveldb_n1_o1));
std::vector<blink::mojom::KeyValuePtr> data;
@@ -509,6 +531,7 @@ TEST_F(SessionStorageContextMojoTest, Scavenging) {
}
context()->CreateSessionNamespace(namespace_id1);
context()->OpenSessionStorage(kTestProcessId, namespace_id1,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace1));
ss_namespace1->OpenArea(origin1, mojo::MakeRequest(&leveldb_n1_o1));
EXPECT_TRUE(test::GetAllSync(leveldb_n1_o1.get(), &data));
@@ -616,6 +639,7 @@ TEST_F(SessionStorageContextMojoTest, RecreateOnCommitFailure) {
base::RunLoop loop;
fake_leveldb_service.SetOnOpenCallback(loop.QuitClosure());
context()->OpenSessionStorage(kTestProcessId, namespace_id,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace));
ss_namespace->OpenArea(origin1, mojo::MakeRequest(&area1));
ss_namespace->OpenArea(origin2, mojo::MakeRequest(&area2));
@@ -663,7 +687,6 @@ TEST_F(SessionStorageContextMojoTest, RecreateOnCommitFailure) {
area1->Put(leveldb::StringPieceToUint8Vector("key"), value, base::nullopt,
"source", base::BindLambdaForTesting([&](bool success) {
EXPECT_TRUE(success);
- put_loop.Quit();
}));
area1.FlushForTesting();
put_loop.RunUntilIdle();
@@ -674,6 +697,7 @@ TEST_F(SessionStorageContextMojoTest, RecreateOnCommitFailure) {
// Make sure all messages to the DB have been processed (Flush above merely
// schedules a commit, but there is no guarantee about those having been
// processed yet).
+ fake_leveldb_service.FlushBindingsForTesting();
if (mock_db)
mock_db->FlushForTesting();
// At this point enough commit failures should have happened to cause the
@@ -689,6 +713,7 @@ TEST_F(SessionStorageContextMojoTest, RecreateOnCommitFailure) {
// Reconnect area1 to the database, and try to read a value.
context()->OpenSessionStorage(kTestProcessId, namespace_id,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace));
ss_namespace->OpenArea(origin1, mojo::MakeRequest(&area1));
@@ -751,6 +776,7 @@ TEST_F(SessionStorageContextMojoTest, DontRecreateOnRepeatedCommitFailure) {
base::RunLoop loop;
fake_leveldb_service.SetOnOpenCallback(loop.QuitClosure());
context()->OpenSessionStorage(kTestProcessId, namespace_id,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace));
ss_namespace->OpenArea(origin1, mojo::MakeRequest(&area));
loop.Run();
@@ -822,6 +848,7 @@ TEST_F(SessionStorageContextMojoTest, DontRecreateOnRepeatedCommitFailure) {
// This time all should just keep getting written, and commit errors are
// getting ignored.
context()->OpenSessionStorage(kTestProcessId, namespace_id,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace));
ss_namespace->OpenArea(origin1, mojo::MakeRequest(&area));
old_value = base::nullopt;
@@ -861,10 +888,10 @@ TEST_F(SessionStorageContextMojoTest, GetUsage) {
context()->CreateSessionNamespace(namespace_id1);
blink::mojom::SessionStorageNamespacePtr ss_namespace1;
context()->OpenSessionStorage(kTestProcessId, namespace_id1,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace1));
blink::mojom::StorageAreaAssociatedPtr leveldb_n1_o1;
ss_namespace1->OpenArea(origin1, mojo::MakeRequest(&leveldb_n1_o1));
-
// Put some data.
EXPECT_TRUE(test::PutSync(
leveldb_n1_o1.get(), leveldb::StringPieceToUint8Vector("key1"),
@@ -889,6 +916,7 @@ TEST_F(SessionStorageContextMojoTest, DeleteStorage) {
context()->CreateSessionNamespace(namespace_id1);
blink::mojom::SessionStorageNamespacePtr ss_namespace1;
context()->OpenSessionStorage(kTestProcessId, namespace_id1,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace1));
blink::mojom::StorageAreaAssociatedPtr leveldb_n1_o1;
ss_namespace1->OpenArea(origin1, mojo::MakeRequest(&leveldb_n1_o1));
@@ -919,6 +947,7 @@ TEST_F(SessionStorageContextMojoTest, DeleteStorage) {
context()->CreateSessionNamespace(namespace_id1);
context()->OpenSessionStorage(kTestProcessId, namespace_id1,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace1));
ss_namespace1->OpenArea(origin1, mojo::MakeRequest(&leveldb_n1_o1));
data.clear();
@@ -934,6 +963,7 @@ TEST_F(SessionStorageContextMojoTest, PurgeInactiveWrappers) {
context()->CreateSessionNamespace(namespace_id1);
blink::mojom::SessionStorageNamespacePtr ss_namespace1;
context()->OpenSessionStorage(kTestProcessId, namespace_id1,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace1));
blink::mojom::StorageAreaAssociatedPtr leveldb;
ss_namespace1->OpenArea(origin1, mojo::MakeRequest(&leveldb));
@@ -961,6 +991,7 @@ TEST_F(SessionStorageContextMojoTest, PurgeInactiveWrappers) {
for (int i = 1; i <= 100; ++i) {
blink::mojom::SessionStorageNamespacePtr ss_namespace1;
context()->OpenSessionStorage(kTestProcessId, namespace_id1,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace1));
blink::mojom::StorageAreaAssociatedPtr leveldb;
ss_namespace1->OpenArea(url::Origin::Create(GURL(base::StringPrintf(
@@ -973,6 +1004,7 @@ TEST_F(SessionStorageContextMojoTest, PurgeInactiveWrappers) {
// And make sure caches were actually cleared.
context()->OpenSessionStorage(kTestProcessId, namespace_id1,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace1));
ss_namespace1->OpenArea(origin1, mojo::MakeRequest(&leveldb));
std::vector<blink::mojom::KeyValuePtr> data;
@@ -988,6 +1020,7 @@ TEST_F(SessionStorageContextMojoTest, ClearDiskState) {
blink::mojom::SessionStorageNamespacePtr ss_namespace1;
context()->OpenSessionStorage(kTestProcessId, namespace_id1,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace1));
blink::mojom::StorageAreaAssociatedPtr leveldb_n1_o1;
@@ -1012,6 +1045,7 @@ TEST_F(SessionStorageContextMojoTest, ClearDiskState) {
// should have been deleted due to our backing mode.
context()->CreateSessionNamespace(namespace_id1);
context()->OpenSessionStorage(kTestProcessId, namespace_id1,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace1));
ss_namespace1->OpenArea(origin1, mojo::MakeRequest(&leveldb_n1_o1));
@@ -1031,6 +1065,7 @@ TEST_F(SessionStorageContextMojoTest, PurgeMemoryDoesNotCrashOrHang) {
context()->CreateSessionNamespace(namespace_id1);
blink::mojom::SessionStorageNamespacePtr ss_namespace1;
context()->OpenSessionStorage(kTestProcessId, namespace_id1,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace1));
blink::mojom::StorageAreaAssociatedPtr leveldb_n1_o1;
ss_namespace1->OpenArea(origin1, mojo::MakeRequest(&leveldb_n1_o1));
@@ -1038,6 +1073,7 @@ TEST_F(SessionStorageContextMojoTest, PurgeMemoryDoesNotCrashOrHang) {
context()->CreateSessionNamespace(namespace_id2);
blink::mojom::SessionStorageNamespacePtr ss_namespace2;
context()->OpenSessionStorage(kTestProcessId, namespace_id2,
+ GetBadMessageCallback(),
mojo::MakeRequest(&ss_namespace2));
blink::mojom::StorageAreaAssociatedPtr leveldb_n2_o1;
ss_namespace2->OpenArea(origin1, mojo::MakeRequest(&leveldb_n2_o1));
diff --git a/chromium/content/browser/dom_storage/session_storage_database.cc b/chromium/content/browser/dom_storage/session_storage_database.cc
index cc9e839424a..2a8d889e3a4 100644
--- a/chromium/content/browser/dom_storage/session_storage_database.cc
+++ b/chromium/content/browser/dom_storage/session_storage_database.cc
@@ -7,6 +7,7 @@
#include <inttypes.h>
#include <stddef.h>
+#include <utility>
#include <vector>
#include "base/files/file_util.h"
@@ -430,7 +431,11 @@ bool SessionStorageDatabase::LazyOpen(bool create_if_needed) {
<< ", error: " << s.ToString();
// Clear the directory and try again.
- base::DeleteFile(file_path_, true);
+ s = leveldb_chrome::DeleteDB(file_path_, leveldb_env::Options());
+ if (!s.ok()) {
+ LOG(WARNING) << "Failed to delete leveldb in " << file_path_.value()
+ << ", error: " << s.ToString();
+ }
s = TryToOpen(&db_);
if (!s.ok()) {
LOG(WARNING) << "Failed to open leveldb in " << file_path_.value()
diff --git a/chromium/content/browser/dom_storage/session_storage_namespace_impl_mojo.cc b/chromium/content/browser/dom_storage/session_storage_namespace_impl_mojo.cc
index 6bc8e13b918..136cf48e5b4 100644
--- a/chromium/content/browser/dom_storage/session_storage_namespace_impl_mojo.cc
+++ b/chromium/content/browser/dom_storage/session_storage_namespace_impl_mojo.cc
@@ -16,12 +16,12 @@ namespace content {
SessionStorageNamespaceImplMojo::SessionStorageNamespaceImplMojo(
std::string namespace_id,
SessionStorageDataMap::Listener* data_map_listener,
- RegisterShallowClonedNamespace add_namespace_callback,
- SessionStorageAreaImpl::RegisterNewAreaMap register_new_map_callback)
+ SessionStorageAreaImpl::RegisterNewAreaMap register_new_map_callback,
+ Delegate* delegate)
: namespace_id_(std::move(namespace_id)),
data_map_listener_(data_map_listener),
- add_namespace_callback_(std::move(add_namespace_callback)),
- register_new_map_callback_(std::move(register_new_map_callback)) {}
+ register_new_map_callback_(std::move(register_new_map_callback)),
+ delegate_(delegate) {}
SessionStorageNamespaceImplMojo::~SessionStorageNamespaceImplMojo() = default;
@@ -32,22 +32,19 @@ bool SessionStorageNamespaceImplMojo::HasAreaForOrigin(
void SessionStorageNamespaceImplMojo::PopulateFromMetadata(
leveldb::mojom::LevelDBDatabase* database,
- SessionStorageMetadata::NamespaceEntry namespace_metadata,
- const std::map<std::vector<uint8_t>, SessionStorageDataMap*>&
- current_data_maps) {
+ SessionStorageMetadata::NamespaceEntry namespace_metadata) {
DCHECK(!IsPopulated());
DCHECK(!waiting_on_clone_population());
database_ = database;
populated_ = true;
namespace_entry_ = namespace_metadata;
for (const auto& pair : namespace_entry_->second) {
- scoped_refptr<SessionStorageDataMap> data_map;
- auto map_it = current_data_maps.find(pair.second->MapNumberAsBytes());
- if (map_it == current_data_maps.end()) {
+ scoped_refptr<SessionStorageDataMap> data_map =
+ delegate_->MaybeGetExistingDataMapForId(
+ pair.second->MapNumberAsBytes());
+ if (!data_map) {
data_map = SessionStorageDataMap::Create(data_map_listener_, pair.second,
database_);
- } else {
- data_map = base::WrapRefCounted(map_it->second);
}
origin_areas_[pair.first] = std::make_unique<SessionStorageAreaImpl>(
namespace_entry_, pair.first, std::move(data_map),
@@ -145,23 +142,29 @@ void SessionStorageNamespaceImplMojo::OpenArea(
}
auto it = origin_areas_.find(origin);
if (it == origin_areas_.end()) {
- scoped_refptr<SessionStorageMetadata::MapData> map_data;
// The area may have been purged due to lack of bindings, so check the
// metadata for the map.
- auto map_it = namespace_entry_->second.find(origin);
- if (map_it != namespace_entry_->second.end()) {
- map_data = map_it->second;
+ scoped_refptr<SessionStorageDataMap> data_map;
+ auto map_data_it = namespace_entry_->second.find(origin);
+ if (map_data_it != namespace_entry_->second.end()) {
+ scoped_refptr<SessionStorageMetadata::MapData> map_data =
+ map_data_it->second;
+ data_map =
+ delegate_->MaybeGetExistingDataMapForId(map_data->MapNumberAsBytes());
+ if (!data_map) {
+ data_map = SessionStorageDataMap::Create(data_map_listener_, map_data,
+ database_);
+ }
} else {
- map_data = register_new_map_callback_.Run(namespace_entry_, origin);
+ data_map = SessionStorageDataMap::Create(
+ data_map_listener_,
+ register_new_map_callback_.Run(namespace_entry_, origin), database_);
}
it = origin_areas_
.emplace(std::make_pair(
- origin,
- std::make_unique<SessionStorageAreaImpl>(
- namespace_entry_, origin,
- SessionStorageDataMap::Create(
- data_map_listener_, std::move(map_data), database_),
- register_new_map_callback_)))
+ origin, std::make_unique<SessionStorageAreaImpl>(
+ namespace_entry_, origin, std::move(data_map),
+ register_new_map_callback_)))
.first;
}
it->second->Bind(std::move(database));
@@ -169,8 +172,8 @@ void SessionStorageNamespaceImplMojo::OpenArea(
void SessionStorageNamespaceImplMojo::Clone(
const std::string& clone_to_namespace) {
- add_namespace_callback_.Run(namespace_entry_, clone_to_namespace,
- origin_areas_);
+ delegate_->RegisterShallowClonedNamespace(namespace_entry_,
+ clone_to_namespace, origin_areas_);
}
void SessionStorageNamespaceImplMojo::FlushOriginForTesting(
diff --git a/chromium/content/browser/dom_storage/session_storage_namespace_impl_mojo.h b/chromium/content/browser/dom_storage/session_storage_namespace_impl_mojo.h
index eb70ad8dde2..0951c9b74d1 100644
--- a/chromium/content/browser/dom_storage/session_storage_namespace_impl_mojo.h
+++ b/chromium/content/browser/dom_storage/session_storage_namespace_impl_mojo.h
@@ -4,6 +4,7 @@
#ifndef CONTENT_BROWSER_DOM_STORAGE_SESSION_STORAGE_NAMESPACE_IMPL_MOJO_H_
#define CONTENT_BROWSER_DOM_STORAGE_SESSION_STORAGE_NAMESPACE_IMPL_MOJO_H_
+#include <map>
#include <memory>
#include "base/callback.h"
@@ -49,23 +50,38 @@ class CONTENT_EXPORT SessionStorageNamespaceImplMojo final
public:
using OriginAreas =
std::map<url::Origin, std::unique_ptr<SessionStorageAreaImpl>>;
- using RegisterShallowClonedNamespace = base::RepeatingCallback<void(
- SessionStorageMetadata::NamespaceEntry source_namespace,
- const std::string& destination_namespace,
- const OriginAreas& areas_to_clone)>;
+
+ class Delegate {
+ public:
+ virtual ~Delegate() = default;
+
+ // This is called when the |Clone()| method is called by mojo.
+ virtual void RegisterShallowClonedNamespace(
+ SessionStorageMetadata::NamespaceEntry source_namespace,
+ const std::string& destination_namespace,
+ const OriginAreas& areas_to_clone) = 0;
+
+ // This is called when |OpenArea()| is called. The map could have been
+ // purged in a call to |PurgeUnboundAreas| but the map could still be alive
+ // as a clone, used by another namespace.
+ // Returns nullptr if a data map was not found.
+ virtual scoped_refptr<SessionStorageDataMap> MaybeGetExistingDataMapForId(
+ const std::vector<uint8_t>& map_number_as_bytes) = 0;
+ };
// Constructs a namespace with the given |namespace_id|, expecting to be
// populated and bound later (see class comment). The |database| and
// |data_map_listener| are given to any data maps constructed for this
- // namespace. The |add_namespace_callback| is called when the |Clone| method
- // is called by mojo. The |register_new_map_callback| is given to the the
- // SessionStorageAreaImpl's, used per-origin, that are bound to in
- // OpenArea.
+ // namespace. The |delegate| is called when the |Clone| method
+ // is called by mojo, as well as when the |OpenArea| method is called and the
+ // map id for that origin is found in our metadata. The
+ // |register_new_map_callback| is given to the the SessionStorageAreaImpl's,
+ // used per-origin, that are bound to in OpenArea.
SessionStorageNamespaceImplMojo(
std::string namespace_id,
SessionStorageDataMap::Listener* data_map_listener,
- RegisterShallowClonedNamespace add_namespace_callback,
- SessionStorageAreaImpl::RegisterNewAreaMap register_new_map_callback);
+ SessionStorageAreaImpl::RegisterNewAreaMap register_new_map_callback,
+ Delegate* delegate);
~SessionStorageNamespaceImplMojo() override;
@@ -80,9 +96,7 @@ class CONTENT_EXPORT SessionStorageNamespaceImplMojo final
// disk. Should be called before |Bind|.
void PopulateFromMetadata(
leveldb::mojom::LevelDBDatabase* database,
- SessionStorageMetadata::NamespaceEntry namespace_metadata,
- const std::map<std::vector<uint8_t>, SessionStorageDataMap*>&
- current_data_maps);
+ SessionStorageMetadata::NamespaceEntry namespace_metadata);
// Can either be called before |Bind|, or if the source namespace isn't
// available yet, |SetWaitingForClonePopulation| can be called. Then |Bind|
@@ -137,14 +151,16 @@ class CONTENT_EXPORT SessionStorageNamespaceImplMojo final
private:
FRIEND_TEST_ALL_PREFIXES(SessionStorageContextMojoTest,
PurgeMemoryDoesNotCrashOrHang);
+ FRIEND_TEST_ALL_PREFIXES(SessionStorageNamespaceImplMojoTest,
+ ReopenClonedAreaAfterPurge);
const std::string namespace_id_;
SessionStorageMetadata::NamespaceEntry namespace_entry_;
- leveldb::mojom::LevelDBDatabase* database_;
+ leveldb::mojom::LevelDBDatabase* database_ = nullptr;
SessionStorageDataMap::Listener* data_map_listener_;
- RegisterShallowClonedNamespace add_namespace_callback_;
SessionStorageAreaImpl::RegisterNewAreaMap register_new_map_callback_;
+ Delegate* delegate_;
bool waiting_on_clone_population_ = false;
bool bind_waiting_on_clone_population_ = false;
diff --git a/chromium/content/browser/dom_storage/session_storage_namespace_impl_mojo_unittest.cc b/chromium/content/browser/dom_storage/session_storage_namespace_impl_mojo_unittest.cc
index b813634fcf5..5080467a908 100644
--- a/chromium/content/browser/dom_storage/session_storage_namespace_impl_mojo_unittest.cc
+++ b/chromium/content/browser/dom_storage/session_storage_namespace_impl_mojo_unittest.cc
@@ -42,7 +42,9 @@ class MockListener : public SessionStorageDataMap::Listener {
MOCK_METHOD1(OnCommitResult, void(leveldb::mojom::DatabaseError error));
};
-class SessionStorageNamespaceImplMojoTest : public testing::Test {
+class SessionStorageNamespaceImplMojoTest
+ : public testing::Test,
+ public SessionStorageNamespaceImplMojo::Delegate {
public:
SessionStorageNamespaceImplMojoTest()
: test_namespace_id1_(base::GenerateGUID()),
@@ -100,19 +102,13 @@ class SessionStorageNamespaceImplMojoTest : public testing::Test {
SessionStorageNamespaceImplMojo* CreateSessionStorageNamespaceImplMojo(
const std::string& namespace_id) {
DCHECK(namespaces_.find(namespace_id) == namespaces_.end());
- SessionStorageNamespaceImplMojo::RegisterShallowClonedNamespace
- add_namespace_callback =
- base::BindRepeating(&SessionStorageNamespaceImplMojoTest::
- RegisterShallowClonedNamespace,
- base::Unretained(this));
SessionStorageAreaImpl::RegisterNewAreaMap map_id_callback =
base::BindRepeating(
&SessionStorageNamespaceImplMojoTest::RegisterNewAreaMap,
base::Unretained(this));
auto namespace_impl = std::make_unique<SessionStorageNamespaceImplMojo>(
- namespace_id, &listener_, std::move(add_namespace_callback),
- std::move(map_id_callback));
+ namespace_id, &listener_, std::move(map_id_callback), this);
auto* namespace_impl_ptr = namespace_impl.get();
namespaces_[namespace_id] = std::move(namespace_impl);
return namespace_impl_ptr;
@@ -131,7 +127,8 @@ class SessionStorageNamespaceImplMojoTest : public testing::Test {
void RegisterShallowClonedNamespace(
NamespaceEntry source_namespace,
const std::string& destination_namespace,
- const SessionStorageNamespaceImplMojo::OriginAreas& areas_to_clone) {
+ const SessionStorageNamespaceImplMojo::OriginAreas& areas_to_clone)
+ override {
std::vector<leveldb::mojom::BatchedOperationPtr> save_operations;
NamespaceEntry namespace_entry =
metadata_.GetOrCreateNamespaceEntry(destination_namespace);
@@ -150,6 +147,14 @@ class SessionStorageNamespaceImplMojoTest : public testing::Test {
it->second->PopulateAsClone(&database_, namespace_entry, areas_to_clone);
}
+ scoped_refptr<SessionStorageDataMap> MaybeGetExistingDataMapForId(
+ const std::vector<uint8_t>& map_number_as_bytes) override {
+ auto it = data_maps_.find(map_number_as_bytes);
+ if (it == data_maps_.end())
+ return nullptr;
+ return it->second;
+ }
+
protected:
TestBrowserThreadBundle test_browser_thread_bundle_;
const std::string test_namespace_id1_;
@@ -162,6 +167,8 @@ class SessionStorageNamespaceImplMojoTest : public testing::Test {
std::map<std::string, std::unique_ptr<SessionStorageNamespaceImplMojo>>
namespaces_;
+ std::map<std::vector<uint8_t>, scoped_refptr<SessionStorageDataMap>>
+ data_maps_;
testing::StrictMock<MockListener> listener_;
std::map<std::vector<uint8_t>, std::vector<uint8_t>> mock_data_;
@@ -178,8 +185,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, MetadataLoad) {
.Times(1);
namespace_impl->PopulateFromMetadata(
- &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_),
- std::map<std::vector<uint8_t>, SessionStorageDataMap*>());
+ &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
blink::mojom::SessionStorageNamespacePtr ss_namespace;
namespace_impl->Bind(mojo::MakeRequest(&ss_namespace), kTestProcessIdOrigin1);
@@ -210,8 +216,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, MetadataLoadWithMapOperations) {
.Times(1);
namespace_impl->PopulateFromMetadata(
- &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_),
- std::map<std::vector<uint8_t>, SessionStorageDataMap*>());
+ &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
blink::mojom::SessionStorageNamespacePtr ss_namespace;
namespace_impl->Bind(mojo::MakeRequest(&ss_namespace), kTestProcessIdOrigin1);
@@ -250,8 +255,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, CloneBeforeBind) {
.Times(1);
namespace_impl1->PopulateFromMetadata(
- &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_),
- std::map<std::vector<uint8_t>, SessionStorageDataMap*>());
+ &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
blink::mojom::SessionStorageNamespacePtr ss_namespace1;
namespace_impl1->Bind(mojo::MakeRequest(&ss_namespace1),
@@ -306,8 +310,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, CloneAfterBind) {
.Times(1);
namespace_impl1->PopulateFromMetadata(
- &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_),
- std::map<std::vector<uint8_t>, SessionStorageDataMap*>());
+ &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
blink::mojom::SessionStorageNamespacePtr ss_namespace1;
namespace_impl1->Bind(mojo::MakeRequest(&ss_namespace1),
@@ -369,8 +372,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, RemoveOriginData) {
.Times(1);
namespace_impl->PopulateFromMetadata(
- &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_),
- std::map<std::vector<uint8_t>, SessionStorageDataMap*>());
+ &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
blink::mojom::SessionStorageNamespacePtr ss_namespace;
namespace_impl->Bind(mojo::MakeRequest(&ss_namespace), kTestProcessIdOrigin1);
@@ -416,8 +418,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, RemoveOriginDataWithoutBinding) {
.Times(1);
namespace_impl->PopulateFromMetadata(
- &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_),
- std::map<std::vector<uint8_t>, SessionStorageDataMap*>());
+ &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
base::RunLoop loop;
EXPECT_CALL(listener_, OnCommitResult(DatabaseError::OK))
@@ -441,8 +442,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, ProcessLockedToOtherOrigin) {
.Times(1);
namespace_impl->PopulateFromMetadata(
- &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_),
- std::map<std::vector<uint8_t>, SessionStorageDataMap*>());
+ &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
blink::mojom::SessionStorageNamespacePtr ss_namespace;
namespace_impl->Bind(mojo::MakeRequest(&ss_namespace), kTestProcessIdOrigin1);
@@ -467,8 +467,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, PurgeUnused) {
.Times(1);
namespace_impl->PopulateFromMetadata(
- &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_),
- std::map<std::vector<uint8_t>, SessionStorageDataMap*>());
+ &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
blink::mojom::SessionStorageNamespacePtr ss_namespace;
namespace_impl->Bind(mojo::MakeRequest(&ss_namespace), kTestProcessIdOrigin1);
@@ -499,8 +498,7 @@ TEST_F(SessionStorageNamespaceImplMojoTest, NamespaceBindingPerOrigin) {
.Times(1);
namespace_impl->PopulateFromMetadata(
- &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_),
- std::map<std::vector<uint8_t>, SessionStorageDataMap*>());
+ &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
blink::mojom::SessionStorageNamespacePtr ss_namespace_o1;
namespace_impl->Bind(mojo::MakeRequest(&ss_namespace_o1),
@@ -528,6 +526,45 @@ TEST_F(SessionStorageNamespaceImplMojoTest, NamespaceBindingPerOrigin) {
.Times(1);
namespaces_.clear();
}
-
} // namespace
+
+TEST_F(SessionStorageNamespaceImplMojoTest, ReopenClonedAreaAfterPurge) {
+ // Verifies that areas are kept alive after the area is unbound, and they
+ // are removed when PurgeUnboundWrappers() is called.
+ SessionStorageNamespaceImplMojo* namespace_impl =
+ CreateSessionStorageNamespaceImplMojo(test_namespace_id1_);
+
+ SessionStorageDataMap* data_map;
+ EXPECT_CALL(listener_,
+ OnDataMapCreation(StdStringToUint8Vector("0"), testing::_))
+ .WillOnce(testing::SaveArg<1>(&data_map));
+
+ namespace_impl->PopulateFromMetadata(
+ &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
+
+ blink::mojom::SessionStorageNamespacePtr ss_namespace;
+ namespace_impl->Bind(mojo::MakeRequest(&ss_namespace), kTestProcessIdOrigin1);
+
+ blink::mojom::StorageAreaAssociatedPtr leveldb_1;
+ ss_namespace->OpenArea(test_origin1_, mojo::MakeRequest(&leveldb_1));
+
+ // Save the data map, as if we did a clone:
+ data_maps_[data_map->map_data()->MapNumberAsBytes()] = data_map;
+
+ leveldb_1.reset();
+ namespace_impl->PurgeUnboundAreas();
+ EXPECT_FALSE(namespace_impl->HasAreaForOrigin(test_origin1_));
+
+ ss_namespace->OpenArea(test_origin1_, mojo::MakeRequest(&leveldb_1));
+ ss_namespace.FlushForTesting();
+
+ EXPECT_EQ(namespace_impl->origin_areas_[test_origin1_]->data_map(), data_map);
+
+ data_maps_.clear();
+
+ EXPECT_CALL(listener_, OnDataMapDestruction(StdStringToUint8Vector("0")))
+ .Times(1);
+
+ namespaces_.clear();
+}
} // namespace content
diff --git a/chromium/content/browser/dom_storage/storage_area_impl_unittest.cc b/chromium/content/browser/dom_storage/storage_area_impl_unittest.cc
index 4b0d1190af7..b858637ce97 100644
--- a/chromium/content/browser/dom_storage/storage_area_impl_unittest.cc
+++ b/chromium/content/browser/dom_storage/storage_area_impl_unittest.cc
@@ -9,14 +9,15 @@
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
+#include "base/task/post_task.h"
#include "base/task_runner_util.h"
-#include "base/task_scheduler/post_task.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread.h"
#include "components/services/leveldb/public/cpp/util.h"
#include "components/services/leveldb/public/interfaces/leveldb.mojom.h"
#include "content/browser/dom_storage/test/storage_area_test_util.h"
#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/test/barrier_builder.h"
#include "content/test/fake_leveldb_database.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
#include "mojo/public/cpp/bindings/strong_associated_binding.h"
@@ -26,9 +27,9 @@
namespace content {
namespace {
-using test::MakeSuccessCallback;
-using test::MakeGetAllCallback;
using test::GetAllCallback;
+using test::MakeGetAllCallback;
+using test::MakeSuccessCallback;
using CacheMode = StorageAreaImpl::CacheMode;
using DatabaseError = leveldb::mojom::DatabaseError;
@@ -43,53 +44,6 @@ std::vector<uint8_t> ToBytes(const std::string& input) {
return leveldb::StdStringToUint8Vector(input);
}
-class InternalIncrementalBarrier {
- public:
- InternalIncrementalBarrier(base::OnceClosure done_closure)
- : num_callbacks_left_(1), done_closure_(std::move(done_closure)) {}
-
- void Dec() {
- // This is the same as in BarrierClosure.
- DCHECK(!num_callbacks_left_.IsZero());
- if (!num_callbacks_left_.Decrement()) {
- base::OnceClosure done = std::move(done_closure_);
- delete this;
- std::move(done).Run();
- }
- }
-
- base::OnceClosure Inc() {
- num_callbacks_left_.Increment();
- return base::BindOnce(&InternalIncrementalBarrier::Dec,
- base::Unretained(this));
- }
-
- private:
- base::AtomicRefCount num_callbacks_left_;
- base::OnceClosure done_closure_;
-
- DISALLOW_COPY_AND_ASSIGN(InternalIncrementalBarrier);
-};
-
-// The callbacks returned by Get might get called after destruction of this
-// class (and thus the done_closure), so there needs to be an internal class
-// to hold the final callback & manage the refcount.
-class IncrementalBarrier {
- public:
- explicit IncrementalBarrier(base::OnceClosure done_closure)
- : internal_barrier_(
- new InternalIncrementalBarrier(std::move(done_closure))) {}
-
- ~IncrementalBarrier() { internal_barrier_->Dec(); }
-
- base::OnceClosure Get() { return internal_barrier_->Inc(); }
-
- private:
- InternalIncrementalBarrier* internal_barrier_; // self-deleting
-
- DISALLOW_COPY_AND_ASSIGN(IncrementalBarrier);
-};
-
class MockDelegate : public StorageAreaImpl::Delegate {
public:
MockDelegate() {}
@@ -278,6 +232,8 @@ class StorageAreaImplTest : public testing::Test,
area->ScheduleImmediateCommit();
loop.Run();
}
+
+ db_.FlushBindingsForTesting();
}
const std::vector<Observation>& observations() { return observations_; }
@@ -380,11 +336,12 @@ TEST_F(StorageAreaImplTest, GetFromPutOverwrite) {
std::vector<uint8_t> result;
bool get_success = false;
{
- IncrementalBarrier barrier(loop.QuitClosure());
- storage_area()->Put(key, value, test_value2_bytes_, test_source_,
- MakeSuccessCallback(barrier.Get(), &put_success));
- storage_area()->Get(key,
- MakeGetCallback(barrier.Get(), &get_success, &result));
+ BarrierBuilder barrier(loop.QuitClosure());
+ storage_area()->Put(
+ key, value, test_value2_bytes_, test_source_,
+ MakeSuccessCallback(barrier.AddClosure(), &put_success));
+ storage_area()->Get(
+ key, MakeGetCallback(barrier.AddClosure(), &get_success, &result));
}
loop.Run();
@@ -452,17 +409,17 @@ TEST_P(StorageAreaImplParamTest, CommitPutToDB) {
bool put_success2 = false;
bool put_success3 = false;
{
- IncrementalBarrier barrier(loop.QuitClosure());
-
- storage_area()->Put(ToBytes(key1), ToBytes(value1), test_value2_bytes_,
- test_source_,
- MakeSuccessCallback(barrier.Get(), &put_success1));
- storage_area()->Put(ToBytes(key2), ToBytes("old value"), base::nullopt,
- test_source_,
- MakeSuccessCallback(barrier.Get(), &put_success2));
- storage_area()->Put(ToBytes(key2), ToBytes(value2), ToBytes("old value"),
- test_source_,
- MakeSuccessCallback(barrier.Get(), &put_success3));
+ BarrierBuilder barrier(loop.QuitClosure());
+
+ storage_area()->Put(
+ ToBytes(key1), ToBytes(value1), test_value2_bytes_, test_source_,
+ MakeSuccessCallback(barrier.AddClosure(), &put_success1));
+ storage_area()->Put(
+ ToBytes(key2), ToBytes("old value"), base::nullopt, test_source_,
+ MakeSuccessCallback(barrier.AddClosure(), &put_success2));
+ storage_area()->Put(
+ ToBytes(key2), ToBytes(value2), ToBytes("old value"), test_source_,
+ MakeSuccessCallback(barrier.AddClosure(), &put_success3));
}
loop.Run();
@@ -875,16 +832,18 @@ TEST_F(StorageAreaImplTest, GetAllWhenCacheOnlyKeys) {
bool put_result1 = false;
bool put_result2 = false;
{
- IncrementalBarrier barrier(loop.QuitClosure());
+ BarrierBuilder barrier(loop.QuitClosure());
- storage_area()->Put(key, value, value2, test_source_,
- MakeSuccessCallback(barrier.Get(), &put_result1));
+ storage_area()->Put(
+ key, value, value2, test_source_,
+ MakeSuccessCallback(barrier.AddClosure(), &put_result1));
storage_area()->GetAll(
- GetAllCallback::CreateAndBind(&result, barrier.Get()),
+ GetAllCallback::CreateAndBind(&result, barrier.AddClosure()),
MakeGetAllCallback(&get_all_success, &data));
- storage_area()->Put(key, value2, value, test_source_,
- MakeSuccessCallback(barrier.Get(), &put_result2));
+ storage_area()->Put(
+ key, value2, value, test_source_,
+ MakeSuccessCallback(barrier.AddClosure(), &put_result2));
FlushAreaBinding();
}
@@ -944,10 +903,11 @@ TEST_F(StorageAreaImplTest, GetAllAfterSetCacheMode) {
bool get_all_callback_success = false;
bool delete_success = false;
{
- IncrementalBarrier barrier(loop.QuitClosure());
+ BarrierBuilder barrier(loop.QuitClosure());
- storage_area()->Put(key, value, value2, test_source_,
- MakeSuccessCallback(barrier.Get(), &put_success));
+ storage_area()->Put(
+ key, value, value2, test_source_,
+ MakeSuccessCallback(barrier.AddClosure(), &put_success));
// Put task triggers database upgrade, so there are no more changes
// to commit.
@@ -956,12 +916,13 @@ TEST_F(StorageAreaImplTest, GetAllAfterSetCacheMode) {
EXPECT_TRUE(storage_area_impl()->has_pending_load_tasks());
storage_area()->GetAll(
- GetAllCallback::CreateAndBind(&get_all_success, barrier.Get()),
+ GetAllCallback::CreateAndBind(&get_all_success, barrier.AddClosure()),
MakeGetAllCallback(&get_all_callback_success, &data));
// This Delete() should not affect the value returned by GetAll().
- storage_area()->Delete(key, value, test_source_,
- MakeSuccessCallback(barrier.Get(), &delete_success));
+ storage_area()->Delete(
+ key, value, test_source_,
+ MakeSuccessCallback(barrier.AddClosure(), &delete_success));
}
loop.Run();
@@ -1091,7 +1052,7 @@ TEST_P(StorageAreaImplParamTest, PrefixForking) {
bool put_success3 = false;
base::RunLoop loop;
{
- IncrementalBarrier barrier(loop.QuitClosure());
+ BarrierBuilder barrier(loop.QuitClosure());
// Create fork 1.
fork1 = storage_area_impl()->ForkToNewPrefix(test_copy_prefix1_,
@@ -1101,16 +1062,17 @@ TEST_P(StorageAreaImplParamTest, PrefixForking) {
// Note - these are 'skipping' the mojo layer, which is why the fork isn't
// scheduled.
fork1->Put(test_key2_bytes_, ToBytes(value4), test_value2_bytes_,
- test_source_, MakeSuccessCallback(barrier.Get(), &put_success1));
+ test_source_,
+ MakeSuccessCallback(barrier.AddClosure(), &put_success1));
fork2 =
fork1->ForkToNewPrefix(test_copy_prefix2_, &fork2_delegate, options);
fork1->Put(test_key2_bytes_, ToBytes(value5), ToBytes(value4), test_source_,
- MakeSuccessCallback(barrier.Get(), &put_success2));
+ MakeSuccessCallback(barrier.AddClosure(), &put_success2));
// Do a put on original and create fork 3, which is key-only.
- storage_area_impl()->Put(test_key1_bytes_, ToBytes(value3),
- test_value1_bytes_, test_source_,
- MakeSuccessCallback(barrier.Get(), &put_success3));
+ storage_area_impl()->Put(
+ test_key1_bytes_, ToBytes(value3), test_value1_bytes_, test_source_,
+ MakeSuccessCallback(barrier.AddClosure(), &put_success3));
fork3 = storage_area_impl()->ForkToNewPrefix(
test_copy_prefix3_, &fork3_delegate,
GetDefaultTestingOptions(CacheMode::KEYS_ONLY_WHEN_POSSIBLE));
@@ -1201,7 +1163,7 @@ TEST_F(StorageAreaImplTest, PrefixForkingPsuedoFuzzer) {
base::RunLoop loop;
{
- IncrementalBarrier barrier(loop.QuitClosure());
+ BarrierBuilder barrier(loop.QuitClosure());
for (int64_t i = 0; i < kTotalAreas; i++) {
FuzzState& state = states[i];
if (!areas[i]) {
@@ -1221,26 +1183,27 @@ TEST_F(StorageAreaImplTest, PrefixForkingPsuedoFuzzer) {
FuzzState old_state = state;
state.val1 = base::nullopt;
successes.push_back(false);
- areas[i]->Delete(kKey1Vec, old_state.val1, test_source_,
- MakeSuccessCallback(barrier.Get(), &successes.back()));
+ areas[i]->Delete(
+ kKey1Vec, old_state.val1, test_source_,
+ MakeSuccessCallback(barrier.AddClosure(), &successes.back()));
}
if (i % 4 == 0) {
FuzzState old_state = state;
state.val2 = base::make_optional<std::vector<uint8_t>>(
{static_cast<uint8_t>(i)});
successes.push_back(false);
- areas[i]->Put(kKey2Vec, state.val2.value(), old_state.val2,
- test_source_,
- MakeSuccessCallback(barrier.Get(), &successes.back()));
+ areas[i]->Put(
+ kKey2Vec, state.val2.value(), old_state.val2, test_source_,
+ MakeSuccessCallback(barrier.AddClosure(), &successes.back()));
}
if (i % 3 == 0) {
FuzzState old_state = state;
state.val1 = base::make_optional<std::vector<uint8_t>>(
{static_cast<uint8_t>(i + 5)});
successes.push_back(false);
- areas[i]->Put(kKey1Vec, state.val1.value(), old_state.val1,
- test_source_,
- MakeSuccessCallback(barrier.Get(), &successes.back()));
+ areas[i]->Put(
+ kKey1Vec, state.val1.value(), old_state.val1, test_source_,
+ MakeSuccessCallback(barrier.AddClosure(), &successes.back()));
}
if (i % 11 == 0) {
state.val1 = base::nullopt;
@@ -1248,7 +1211,7 @@ TEST_F(StorageAreaImplTest, PrefixForkingPsuedoFuzzer) {
successes.push_back(false);
areas[i]->DeleteAll(
test_source_,
- MakeSuccessCallback(barrier.Get(), &successes.back()));
+ MakeSuccessCallback(barrier.AddClosure(), &successes.back()));
}
if (i % 2 == 0 && forks + 1 < kTotalAreas) {
CacheMode mode = i % 3 == 0 ? CacheMode::KEYS_AND_VALUES
@@ -1264,9 +1227,9 @@ TEST_F(StorageAreaImplTest, PrefixForkingPsuedoFuzzer) {
state.val1 = base::make_optional<std::vector<uint8_t>>(
{static_cast<uint8_t>(i + 9)});
successes.push_back(false);
- areas[i]->Put(kKey1Vec, state.val1.value(), old_state.val1,
- test_source_,
- MakeSuccessCallback(barrier.Get(), &successes.back()));
+ areas[i]->Put(
+ kKey1Vec, state.val1.value(), old_state.val1, test_source_,
+ MakeSuccessCallback(barrier.AddClosure(), &successes.back()));
}
}
}
diff --git a/chromium/content/browser/download/download_browsertest.cc b/chromium/content/browser/download/download_browsertest.cc
index 58882960352..3ae60d75623 100644
--- a/chromium/content/browser/download/download_browsertest.cc
+++ b/chromium/content/browser/download/download_browsertest.cc
@@ -869,7 +869,7 @@ class DownloadContentTest : public ContentBrowserTest {
std::string file_contents;
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_during_test_verification;
+ base::ScopedAllowBlockingForTesting allow_blocking;
bool read = base::ReadFileToString(path, &file_contents);
EXPECT_TRUE(read) << "Failed reading file: " << path.value() << std::endl;
if (!read)
@@ -906,14 +906,14 @@ class DownloadContentTest : public ContentBrowserTest {
}
static bool PathExists(const base::FilePath& path) {
- base::ThreadRestrictions::ScopedAllowIO allow_io_during_test_verification;
+ base::ScopedAllowBlockingForTesting allow_blocking;
return base::PathExists(path);
}
static void ReadAndVerifyFileContents(int seed,
int64_t expected_size,
const base::FilePath& path) {
- base::ThreadRestrictions::ScopedAllowIO allow_io_during_test_verification;
+ base::ScopedAllowBlockingForTesting allow_blocking;
base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
ASSERT_TRUE(file.IsValid());
int64_t file_length = file.GetLength();
@@ -1812,7 +1812,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, RestartIfNoPartialFile) {
// Delete the intermediate file.
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_testing;
+ base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(PathExists(download->GetFullPath()));
ASSERT_TRUE(base::DeleteFile(download->GetFullPath(), false));
}
@@ -2360,7 +2360,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeRestoredDownload_NoHash) {
std::string output = TestDownloadHttpResponse::GetPatternBytes(
parameters.pattern_generator_seed, 0, kIntermediateSize);
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_test_setup;
+ base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_EQ(kIntermediateSize, base::WriteFile(intermediate_file_path,
output.data(), output.size()));
}
@@ -2413,7 +2413,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest,
std::string output = TestDownloadHttpResponse::GetPatternBytes(
parameters.pattern_generator_seed + 1, 0, kIntermediateSize);
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_test_setup;
+ base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_EQ(kIntermediateSize, base::WriteFile(intermediate_file_path,
output.data(), output.size()));
}
@@ -2467,7 +2467,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest,
std::string output = TestDownloadHttpResponse::GetPatternBytes(
parameters.pattern_generator_seed, 0, kIntermediateSize);
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_test_setup;
+ base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_EQ(kIntermediateSize, base::WriteFile(intermediate_file_path,
output.data(), output.size()));
}
@@ -2532,7 +2532,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeRestoredDownload_WrongHash) {
const int kIntermediateSize = 1331;
std::vector<char> buffer(kIntermediateSize);
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_test_setup;
+ base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_EQ(kIntermediateSize, base::WriteFile(intermediate_file_path,
buffer.data(), buffer.size()));
}
@@ -2614,7 +2614,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeRestoredDownload_ShortFile) {
std::string output = TestDownloadHttpResponse::GetPatternBytes(
parameters.pattern_generator_seed, 0, kIntermediateSize - 100);
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_test_setup;
+ base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_EQ(
kIntermediateSize - 100,
base::WriteFile(intermediate_file_path, output.data(), output.size()));
@@ -2687,7 +2687,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeRestoredDownload_LongFile) {
std::string output = TestDownloadHttpResponse::GetPatternBytes(
parameters.pattern_generator_seed, 0, kIntermediateSize + 100);
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_test_setup;
+ base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_EQ(
kIntermediateSize + 100,
base::WriteFile(intermediate_file_path, output.data(), output.size()));
@@ -3189,7 +3189,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTestWithMojoBlobURLs,
}
IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadAttributeSameSiteCookie) {
- base::ThreadRestrictions::ScopedAllowIO allow_io_during_test;
+ base::ScopedAllowBlockingForTesting allow_blocking;
net::EmbeddedTestServer test_server;
ASSERT_TRUE(test_server.InitializeAndListen());
diff --git a/chromium/content/browser/download/download_manager_impl.cc b/chromium/content/browser/download/download_manager_impl.cc
index f8c137fe6d7..37cabf2c9ff 100644
--- a/chromium/content/browser/download/download_manager_impl.cc
+++ b/chromium/content/browser/download/download_manager_impl.cc
@@ -23,8 +23,8 @@
#include "build/build_config.h"
#include "components/download/database/in_progress/download_entry.h"
#include "components/download/database/in_progress/in_progress_cache_impl.h"
-#include "components/download/database/switches.h"
#include "components/download/public/common/download_create_info.h"
+#include "components/download/public/common/download_features.h"
#include "components/download/public/common/download_file.h"
#include "components/download/public/common/download_interrupt_reasons.h"
#include "components/download/public/common/download_item_factory.h"
@@ -33,6 +33,7 @@
#include "components/download/public/common/download_stats.h"
#include "components/download/public/common/download_task_runner.h"
#include "components/download/public/common/download_url_loader_factory_getter.h"
+#include "components/download/public/common/download_url_loader_factory_getter_impl.h"
#include "components/download/public/common/download_url_parameters.h"
#include "components/download/public/common/download_utils.h"
#include "components/download/public/common/url_download_handler_factory.h"
@@ -41,9 +42,9 @@
#include "content/browser/devtools/render_frame_devtools_agent_host.h"
#include "content/browser/download/byte_stream_input_stream.h"
#include "content/browser/download/download_resource_handler.h"
-#include "content/browser/download/download_url_loader_factory_getter_impl.h"
#include "content/browser/download/download_utils.h"
#include "content/browser/download/file_download_url_loader_factory_getter.h"
+#include "content/browser/download/file_system_download_url_loader_factory_getter.h"
#include "content/browser/download/network_download_url_loader_factory_getter.h"
#include "content/browser/download/url_downloader.h"
#include "content/browser/download/url_downloader_factory.h"
@@ -296,15 +297,29 @@ DownloadManagerImpl::DownloadManagerImpl(BrowserContext* browser_context)
in_progress_cache_initialized_(false),
browser_context_(browser_context),
delegate_(nullptr),
+ in_progress_manager_(
+ browser_context_->RetriveInProgressDownloadManager()),
+ next_download_id_(download::DownloadItem::kInvalidId),
+ is_history_download_id_retrieved_(false),
weak_factory_(this) {
DCHECK(browser_context);
download::SetIOTaskRunner(
BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
download::UrlDownloadHandlerFactory::Install(new UrlDownloaderFactory());
- in_progress_manager_ = std::make_unique<download::InProgressDownloadManager>(
- this, IsOffTheRecord() ? base::FilePath() : browser_context_->GetPath(),
- base::BindRepeating(&IsOriginSecure));
+
+ if (!in_progress_manager_) {
+ in_progress_manager_ =
+ std::make_unique<download::InProgressDownloadManager>(
+ this,
+ IsOffTheRecord() ? base::FilePath() : browser_context_->GetPath(),
+ base::BindRepeating(&IsOriginSecure));
+ } else {
+ in_progress_manager_->set_delegate(this);
+ in_progress_manager_->set_download_start_observer(nullptr);
+ in_progress_manager_->set_is_origin_secure_cb(
+ base::BindRepeating(&IsOriginSecure));
+ }
in_progress_manager_->NotifyWhenInitialized(base::BindOnce(
&DownloadManagerImpl::OnInProgressDownloadManagerInitialized,
weak_factory_.GetWeakPtr()));
@@ -331,14 +346,43 @@ download::DownloadItemImpl* DownloadManagerImpl::CreateActiveItem(
return download;
}
-void DownloadManagerImpl::GetNextId(const DownloadIdCallback& callback) {
+void DownloadManagerImpl::GetNextId(GetNextIdCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (delegate_) {
- delegate_->GetNextId(callback);
+ if (IsNextIdInitialized()) {
+ std::move(callback).Run(next_download_id_++);
return;
}
- static uint32_t next_id = download::DownloadItem::kInvalidId + 1;
- callback.Run(next_id++);
+
+ id_callbacks_.emplace_back(
+ std::make_unique<GetNextIdCallback>(std::move(callback)));
+ // If we are first time here, call the delegate to get the next ID from
+ // history db.
+ if (!is_history_download_id_retrieved_ && id_callbacks_.size() == 1u) {
+ if (delegate_) {
+ delegate_->GetNextId(
+ base::BindRepeating(&DownloadManagerImpl::OnHistoryNextIdRetrived,
+ weak_factory_.GetWeakPtr()));
+ } else {
+ OnHistoryNextIdRetrived(download::DownloadItem::kInvalidId + 1);
+ }
+ }
+}
+
+void DownloadManagerImpl::SetNextId(uint32_t next_id) {
+ if (next_id > next_download_id_)
+ next_download_id_ = next_id;
+ if (!IsNextIdInitialized())
+ return;
+
+ for (auto& callback : id_callbacks_)
+ std::move(*callback).Run(next_download_id_++);
+ id_callbacks_.clear();
+}
+
+void DownloadManagerImpl::OnHistoryNextIdRetrived(uint32_t next_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ is_history_download_id_retrieved_ = true;
+ SetNextId(next_id);
}
void DownloadManagerImpl::DetermineDownloadTarget(
@@ -494,6 +538,7 @@ base::FilePath DownloadManagerImpl::GetDefaultDownloadDirectory() {
void DownloadManagerImpl::OnInProgressDownloadManagerInitialized() {
std::vector<std::unique_ptr<download::DownloadItemImpl>>
in_progress_downloads = in_progress_manager_->TakeInProgressDownloads();
+ uint32_t max_id = download::DownloadItem::kInvalidId;
for (auto& download : in_progress_downloads) {
DCHECK(!base::ContainsKey(downloads_by_guid_, download->GetGuid()));
DCHECK(!base::ContainsKey(downloads_, download->GetId()));
@@ -501,12 +546,16 @@ void DownloadManagerImpl::OnInProgressDownloadManagerInitialized() {
download::DownloadItemImpl* item = download.get();
item->SetDelegate(this);
downloads_by_guid_[download->GetGuid()] = item;
- downloads_[download->GetId()] = std::move(download);
+ uint32_t id = download->GetId();
+ downloads_[id] = std::move(download);
+ if (id > max_id)
+ max_id = id;
for (auto& observer : observers_)
observer.OnDownloadCreated(this, item);
DVLOG(20) << __func__ << "() download = " << item->DebugString(true);
}
PostInitialization(DOWNLOAD_INITIALIZATION_DEPENDENCY_IN_PROGRESS_CACHE);
+ SetNextId(max_id + 1);
}
void DownloadManagerImpl::StartDownloadItem(
@@ -522,10 +571,9 @@ void DownloadManagerImpl::StartDownloadItem(
std::move(callback).Run(std::move(info), download);
OnDownloadStarted(download, on_started);
} else {
- GetNextId(
- base::BindRepeating(&DownloadManagerImpl::CreateNewDownloadItemToStart,
- weak_factory_.GetWeakPtr(), base::Passed(&info),
- on_started, base::Passed(&callback)));
+ GetNextId(base::BindOnce(&DownloadManagerImpl::CreateNewDownloadItemToStart,
+ weak_factory_.GetWeakPtr(), std::move(info),
+ on_started, std::move(callback)));
}
}
@@ -578,8 +626,8 @@ void DownloadManagerImpl::CheckForHistoryFilesRemoval() {
void DownloadManagerImpl::OnHistoryQueryComplete(
base::OnceClosure load_history_downloads_cb) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- download::switches::kEnableDownloadDB) &&
+ if (base::FeatureList::IsEnabled(
+ download::features::kDownloadDBForNewDownloads) &&
!in_progress_cache_initialized_) {
load_history_downloads_cb_ = std::move(load_history_downloads_cb);
} else {
@@ -628,10 +676,10 @@ void DownloadManagerImpl::CreateSavePackageDownloadItem(
const DownloadItemImplCreated& item_created) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
GetNextId(
- base::Bind(&DownloadManagerImpl::CreateSavePackageDownloadItemWithId,
- weak_factory_.GetWeakPtr(), main_file_path, page_url,
- mime_type, render_process_id, render_frame_id,
- base::Passed(std::move(request_handle)), item_created));
+ base::BindOnce(&DownloadManagerImpl::CreateSavePackageDownloadItemWithId,
+ weak_factory_.GetWeakPtr(), main_file_path, page_url,
+ mime_type, render_process_id, render_frame_id,
+ std::move(request_handle), item_created));
}
void DownloadManagerImpl::CreateSavePackageDownloadItemWithId(
@@ -1118,7 +1166,7 @@ void DownloadManagerImpl::BeginResourceDownloadOnChecksComplete(
if (blob_url_loader_factory) {
DCHECK(params->url().SchemeIsBlob());
url_loader_factory_getter =
- base::MakeRefCounted<DownloadURLLoaderFactoryGetterImpl>(
+ base::MakeRefCounted<download::DownloadURLLoaderFactoryGetterImpl>(
blob_url_loader_factory->Clone());
} else if (params->url().SchemeIsFile()) {
url_loader_factory_getter =
@@ -1128,6 +1176,24 @@ void DownloadManagerImpl::BeginResourceDownloadOnChecksComplete(
url_loader_factory_getter =
base::MakeRefCounted<WebUIDownloadURLLoaderFactoryGetter>(
rfh, params->url());
+ } else if (rfh && params->url().SchemeIsFileSystem()) {
+ StoragePartitionImpl* storage_partition =
+ static_cast<StoragePartitionImpl*>(
+ BrowserContext::GetStoragePartitionForSite(browser_context_,
+ site_url));
+ std::string storage_domain;
+ auto* site_instance = rfh->GetSiteInstance();
+ if (site_instance) {
+ std::string partition_name;
+ bool in_memory;
+ GetContentClient()->browser()->GetStoragePartitionConfigForSite(
+ browser_context_, site_url, true, &storage_domain, &partition_name,
+ &in_memory);
+ }
+ url_loader_factory_getter =
+ base::MakeRefCounted<FileSystemDownloadURLLoaderFactoryGetter>(
+ params->url(), rfh, /*is_navigation=*/false,
+ storage_partition->GetFileSystemContext(), storage_domain);
} else {
StoragePartitionImpl* storage_partition =
static_cast<StoragePartitionImpl*>(
@@ -1198,7 +1264,11 @@ void DownloadManagerImpl::BeginDownloadInternal(
std::move(blob_data_handle),
browser_context_->GetResourceContext(), is_new_download,
weak_factory_.GetWeakPtr()));
- }
+ }
+}
+
+bool DownloadManagerImpl::IsNextIdInitialized() const {
+ return is_history_download_id_retrieved_ && in_progress_cache_initialized_;
}
} // namespace content
diff --git a/chromium/content/browser/download/download_manager_impl.h b/chromium/content/browser/download/download_manager_impl.h
index 4f07f57f252..5f53beb1236 100644
--- a/chromium/content/browser/download/download_manager_impl.h
+++ b/chromium/content/browser/download/download_manager_impl.h
@@ -214,9 +214,18 @@ class CONTENT_EXPORT DownloadManagerImpl
download::InProgressDownloadManager::StartDownloadItemCallback callback,
uint32_t id);
+ using GetNextIdCallback = base::OnceCallback<void(uint32_t)>;
// Called to get an ID for a new download. |callback| may be called
// synchronously.
- void GetNextId(const DownloadIdCallback& callback);
+ void GetNextId(GetNextIdCallback callback);
+
+ // Sets the |next_download_id_| if the |next_id| is larger. Runs all the
+ // |id_callbacks_| if both the ID from both history db and in-progress db
+ // are retrieved.
+ void SetNextId(uint32_t next_id);
+
+ // Called when the next ID from history db is retrieved.
+ void OnHistoryNextIdRetrived(uint32_t next_id);
// Create a new active item based on the info. Separate from
// StartDownload() for testing.
@@ -279,6 +288,9 @@ class CONTENT_EXPORT DownloadManagerImpl
const GURL& site_url,
bool is_download_allowed);
+ // Whether |next_download_id_| is initialized.
+ bool IsNextIdInitialized() const;
+
// Factory for creation of downloads items.
std::unique_ptr<download::DownloadItemFactory> item_factory_;
@@ -308,7 +320,7 @@ class CONTENT_EXPORT DownloadManagerImpl
bool in_progress_cache_initialized_;
// Observers that want to be notified of changes to the set of downloads.
- base::ObserverList<Observer> observers_;
+ base::ObserverList<Observer>::Unchecked observers_;
// Stores information about in-progress download items.
std::unique_ptr<download::DownloadItem::Observer>
@@ -329,6 +341,18 @@ class CONTENT_EXPORT DownloadManagerImpl
// Callback to run to load all history downloads.
base::OnceClosure load_history_downloads_cb_;
+ // The next download id to issue to new downloads. The |next_download_id_| can
+ // only be used when both history and in-progress db have provided their
+ // values.
+ uint32_t next_download_id_;
+
+ // Whether next download ID from history DB is being retrieved.
+ bool is_history_download_id_retrieved_;
+
+ // Callbacks to run once download ID is determined.
+ using IdCallbackVector = std::vector<std::unique_ptr<GetNextIdCallback>>;
+ IdCallbackVector id_callbacks_;
+
base::WeakPtrFactory<DownloadManagerImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(DownloadManagerImpl);
diff --git a/chromium/content/browser/download/download_manager_impl_unittest.cc b/chromium/content/browser/download/download_manager_impl_unittest.cc
index c4e5f80b78f..7df5b5b6539 100644
--- a/chromium/content/browser/download/download_manager_impl_unittest.cc
+++ b/chromium/content/browser/download/download_manager_impl_unittest.cc
@@ -522,6 +522,7 @@ TEST_F(DownloadManagerTest, StartDownload) {
std::unique_ptr<ByteStreamReader> stream(new MockByteStreamReader);
uint32_t local_id(5); // Random value
base::FilePath download_path(FILE_PATH_LITERAL("download/path"));
+ OnInProgressDownloadManagerInitialized();
EXPECT_FALSE(download_manager_->GetDownload(local_id));
diff --git a/chromium/content/browser/download/download_request_core.cc b/chromium/content/browser/download/download_request_core.cc
index fb6a33bcd83..a4cdc54c64b 100644
--- a/chromium/content/browser/download/download_request_core.cc
+++ b/chromium/content/browser/download/download_request_core.cc
@@ -245,7 +245,6 @@ bool DownloadRequestCore::OnResponseStarted(
const std::string& override_mime_type) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DVLOG(20) << __func__ << "() " << DebugString();
- download_start_time_ = base::TimeTicks::Now();
download::DownloadInterruptReason result =
request()->response_headers() ? download::HandleSuccessfulServerResponse(
@@ -361,7 +360,6 @@ bool DownloadRequestCore::OnReadCompleted(int bytes_read, bool* defer) {
if (!stream_writer_->Write(read_buffer_, bytes_read)) {
PauseRequest();
*defer = was_deferred_ = true;
- last_stream_pause_time_ = base::TimeTicks::Now();
}
read_buffer_ = nullptr; // Drop our reference.
@@ -411,10 +409,6 @@ void DownloadRequestCore::OnResponseCompleted(
request()->response_headers()->EnumerateHeader(nullptr, "Accept-Ranges",
&accept_ranges);
}
- download::RecordAcceptsRanges(accept_ranges, bytes_read_,
- has_strong_validators);
- download::RecordNetworkBlockage(base::TimeTicks::Now() - download_start_time_,
- total_pause_time_);
// Send the info down the stream. Conditional is in case we get
// OnResponseCompleted without OnResponseStarted.
@@ -462,10 +456,6 @@ void DownloadRequestCore::ResumeRequest() {
return;
was_deferred_ = false;
- if (!last_stream_pause_time_.is_null()) {
- total_pause_time_ += (base::TimeTicks::Now() - last_stream_pause_time_);
- last_stream_pause_time_ = base::TimeTicks();
- }
delegate_->OnReadyToRead();
}
diff --git a/chromium/content/browser/download/download_request_core.h b/chromium/content/browser/download/download_request_core.h
index 0fdd19edd45..0a4a2db6000 100644
--- a/chromium/content/browser/download/download_request_core.h
+++ b/chromium/content/browser/download/download_request_core.h
@@ -145,11 +145,6 @@ class CONTENT_EXPORT DownloadRequestCore
// URLRequest to fail and the associated download will be interrupted.
device::mojom::WakeLockPtr wake_lock_;
- // The following are used to collect stats.
- base::TimeTicks download_start_time_;
- base::TimeTicks last_stream_pause_time_;
- base::TimeDelta total_pause_time_;
-
int64_t bytes_read_;
int pause_count_;
diff --git a/chromium/content/browser/download/download_url_loader_factory_getter_impl.cc b/chromium/content/browser/download/download_url_loader_factory_getter_impl.cc
deleted file mode 100644
index e26386c8bb6..00000000000
--- a/chromium/content/browser/download/download_url_loader_factory_getter_impl.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/download/download_url_loader_factory_getter_impl.h"
-
-namespace content {
-
-DownloadURLLoaderFactoryGetterImpl::DownloadURLLoaderFactoryGetterImpl(
- std::unique_ptr<network::SharedURLLoaderFactoryInfo> url_loader_factory)
- : url_loader_factory_info_(std::move(url_loader_factory)) {}
-
-DownloadURLLoaderFactoryGetterImpl::~DownloadURLLoaderFactoryGetterImpl() =
- default;
-
-scoped_refptr<network::SharedURLLoaderFactory>
-DownloadURLLoaderFactoryGetterImpl::GetURLLoaderFactory() {
- if (!url_loader_factory_) {
- url_loader_factory_ = network::SharedURLLoaderFactory::Create(
- std::move(url_loader_factory_info_));
- }
- return url_loader_factory_;
-}
-
-} // namespace content
diff --git a/chromium/content/browser/download/download_url_loader_factory_getter_impl.h b/chromium/content/browser/download/download_url_loader_factory_getter_impl.h
deleted file mode 100644
index d002dbb1e14..00000000000
--- a/chromium/content/browser/download/download_url_loader_factory_getter_impl.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_URL_LOADER_FACTORY_GETTER_IMPL_H_
-#define CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_URL_LOADER_FACTORY_GETTER_IMPL_H_
-
-#include "components/download/public/common/download_url_loader_factory_getter.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-
-namespace content {
-
-// Class for retrieving a fixed SharedURLLoaderFactory.
-class DownloadURLLoaderFactoryGetterImpl
- : public download::DownloadURLLoaderFactoryGetter {
- public:
- explicit DownloadURLLoaderFactoryGetterImpl(
- std::unique_ptr<network::SharedURLLoaderFactoryInfo> url_loader_factory);
-
- // download::DownloadURLLoaderFactoryGetter implementation.
- scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
-
- protected:
- ~DownloadURLLoaderFactoryGetterImpl() override;
-
- private:
- // Only one of the following two members is ever set. Initially that would be
- // |url_loader_factory_info_|, but after GetURLLoaderFactory is called for the
- // first time instead |url_loader_factory_| will be set. This is safe because
- // GetURLLoaderFactory is always called from the same thread.
- std::unique_ptr<network::SharedURLLoaderFactoryInfo> url_loader_factory_info_;
- scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(DownloadURLLoaderFactoryGetterImpl);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_URL_LOADER_FACTORY_GETTER_IMPL_H_
diff --git a/chromium/content/browser/download/download_utils.cc b/chromium/content/browser/download/download_utils.cc
index fec2b6a861c..0fd9009103d 100644
--- a/chromium/content/browser/download/download_utils.cc
+++ b/chromium/content/browser/download/download_utils.cc
@@ -8,7 +8,7 @@
#include "base/process/process_handle.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/stringprintf.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "components/download/database/in_progress/download_entry.h"
#include "components/download/database/in_progress/in_progress_cache.h"
#include "components/download/public/common/download_create_info.h"
diff --git a/chromium/content/browser/download/file_download_url_loader_factory_getter.cc b/chromium/content/browser/download/file_download_url_loader_factory_getter.cc
index 973baed881d..86dfd9a6aee 100644
--- a/chromium/content/browser/download/file_download_url_loader_factory_getter.cc
+++ b/chromium/content/browser/download/file_download_url_loader_factory_getter.cc
@@ -4,8 +4,8 @@
#include "content/browser/download/file_download_url_loader_factory_getter.h"
-#include "base/task_scheduler/post_task.h"
-#include "base/task_scheduler/task_traits.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
#include "components/download/public/common/download_task_runner.h"
#include "content/browser/file_url_loader_factory.h"
#include "content/browser/url_loader_factory_getter.h"
@@ -33,7 +33,7 @@ FileDownloadURLLoaderFactoryGetter::GetURLLoaderFactory() {
mojo::MakeStrongBinding(
std::make_unique<FileURLLoaderFactory>(
profile_path_, base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::BACKGROUND,
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})),
MakeRequest(&url_loader_factory_ptr_info));
diff --git a/chromium/content/browser/download/file_system_download_url_loader_factory_getter.cc b/chromium/content/browser/download/file_system_download_url_loader_factory_getter.cc
new file mode 100644
index 00000000000..3c4780ec159
--- /dev/null
+++ b/chromium/content/browser/download/file_system_download_url_loader_factory_getter.cc
@@ -0,0 +1,52 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/download/file_system_download_url_loader_factory_getter.h"
+
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
+#include "components/download/public/common/download_task_runner.h"
+#include "content/browser/fileapi/file_system_url_loader_factory.h"
+#include "content/browser/url_loader_factory_getter.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/network/public/cpp/wrapper_shared_url_loader_factory.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+
+namespace content {
+
+FileSystemDownloadURLLoaderFactoryGetter::
+ FileSystemDownloadURLLoaderFactoryGetter(
+ const GURL& url,
+ RenderFrameHost* rfh,
+ bool is_navigation,
+ scoped_refptr<storage::FileSystemContext> file_system_context,
+ const std::string& storage_domain)
+ : rfh_(rfh),
+ is_navigation_(is_navigation),
+ file_system_context_(file_system_context),
+ storage_domain_(storage_domain) {
+ DCHECK(url.SchemeIs(url::kFileSystemScheme));
+ DCHECK(rfh);
+}
+
+FileSystemDownloadURLLoaderFactoryGetter::
+ ~FileSystemDownloadURLLoaderFactoryGetter() = default;
+
+scoped_refptr<network::SharedURLLoaderFactory>
+FileSystemDownloadURLLoaderFactoryGetter::GetURLLoaderFactory() {
+ DCHECK(download::GetIOTaskRunner()->BelongsToCurrentThread());
+
+ std::unique_ptr<network::mojom::URLLoaderFactory> factory =
+ CreateFileSystemURLLoaderFactory(rfh_, is_navigation_,
+ file_system_context_, storage_domain_);
+
+ network::mojom::URLLoaderFactoryPtrInfo url_loader_factory_ptr_info;
+ mojo::MakeStrongBinding(std::move(factory),
+ MakeRequest(&url_loader_factory_ptr_info));
+
+ return base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
+ std::move(url_loader_factory_ptr_info));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/download/file_system_download_url_loader_factory_getter.h b/chromium/content/browser/download/file_system_download_url_loader_factory_getter.h
new file mode 100644
index 00000000000..422a6e9ab2b
--- /dev/null
+++ b/chromium/content/browser/download/file_system_download_url_loader_factory_getter.h
@@ -0,0 +1,50 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_DOWNLOAD_FILE_SYSTEM_DOWNLOAD_URL_LOADER_FACTORY_GETTER_H_
+#define CONTENT_BROWSER_DOWNLOAD_FILE_SYSTEM_DOWNLOAD_URL_LOADER_FACTORY_GETTER_H_
+
+#include <string>
+
+#include "base/memory/scoped_refptr.h"
+#include "components/download/public/common/download_url_loader_factory_getter.h"
+#include "url/gurl.h"
+
+namespace storage {
+class FileSystemContext;
+}
+
+namespace content {
+
+class RenderFrameHost;
+
+// Class for retrieving the URLLoaderFactory for a file URL.
+class FileSystemDownloadURLLoaderFactoryGetter
+ : public download::DownloadURLLoaderFactoryGetter {
+ public:
+ FileSystemDownloadURLLoaderFactoryGetter(
+ const GURL& url,
+ RenderFrameHost* rfh,
+ bool is_navigation,
+ scoped_refptr<storage::FileSystemContext> file_system_context,
+ const std::string& storage_domain);
+
+ // download::DownloadURLLoaderFactoryGetter implementation.
+ scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
+
+ protected:
+ ~FileSystemDownloadURLLoaderFactoryGetter() override;
+
+ private:
+ RenderFrameHost* rfh_;
+ const bool is_navigation_;
+ scoped_refptr<storage::FileSystemContext> file_system_context_;
+ const std::string storage_domain_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileSystemDownloadURLLoaderFactoryGetter);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DOWNLOAD_FILE_SYSTEM_DOWNLOAD_URL_LOADER_FACTORY_GETTER_H_
diff --git a/chromium/content/browser/download/mhtml_generation_browsertest.cc b/chromium/content/browser/download/mhtml_generation_browsertest.cc
index 379cc3ac485..5d8e517f459 100644
--- a/chromium/content/browser/download/mhtml_generation_browsertest.cc
+++ b/chromium/content/browser/download/mhtml_generation_browsertest.cc
@@ -57,6 +57,7 @@ class FindTrackingDelegate : public WebContentsDelegate {
web_contents->SetDelegate(this);
blink::WebFindOptions options;
+ options.run_synchronously_for_testing = true;
options.match_case = false;
web_contents->Find(global_request_id++, base::UTF8ToUTF16(search_),
@@ -149,7 +150,7 @@ class MHTMLGenerationTest : public ContentBrowserTest {
}
int64_t ReadFileSizeFromDisk(base::FilePath path) {
- base::ThreadRestrictions::ScopedAllowIO allow_io_to_test_file_size;
+ base::ScopedAllowBlockingForTesting allow_blocking;
int64_t file_size;
if (!base::GetFileSize(path, &file_size)) return -1;
return file_size;
@@ -249,7 +250,7 @@ IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, GenerateMHTML) {
EXPECT_GT(ReadFileSizeFromDisk(path), 100); // Verify the actual file size.
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_content_verification;
+ base::ScopedAllowBlockingForTesting allow_blocking;
std::string mhtml;
ASSERT_TRUE(base::ReadFileToString(path, &mhtml));
EXPECT_THAT(mhtml,
@@ -411,7 +412,7 @@ IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, GenerateNonBinaryMHTMLWithImage) {
EXPECT_GT(ReadFileSizeFromDisk(path), 100); // Verify the actual file size.
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_content_verification;
+ base::ScopedAllowBlockingForTesting allow_blocking;
std::string mhtml;
ASSERT_TRUE(base::ReadFileToString(path, &mhtml));
EXPECT_THAT(mhtml, HasSubstr("Content-Transfer-Encoding: base64"));
@@ -438,7 +439,7 @@ IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, GenerateBinaryMHTMLWithImage) {
EXPECT_GT(ReadFileSizeFromDisk(path), 100); // Verify the actual file size.
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_content_verification;
+ base::ScopedAllowBlockingForTesting allow_blocking;
std::string mhtml;
ASSERT_TRUE(base::ReadFileToString(path, &mhtml));
EXPECT_THAT(mhtml, HasSubstr("Content-Transfer-Encoding: binary"));
@@ -460,7 +461,7 @@ IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, GenerateMHTMLIgnoreNoStore) {
std::string mhtml;
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_content_verification;
+ base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(base::ReadFileToString(path, &mhtml));
}
@@ -488,7 +489,7 @@ IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, GenerateMHTMLObeyNoStoreMainFrame) {
std::string mhtml;
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_content_verification;
+ base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(base::ReadFileToString(path, &mhtml));
}
@@ -519,7 +520,7 @@ IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest,
std::string mhtml;
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_content_verification;
+ base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(base::ReadFileToString(path, &mhtml));
}
@@ -546,7 +547,7 @@ IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, GenerateMHTMLObeyNoStoreSubFrame) {
std::string mhtml;
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_content_verification;
+ base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(base::ReadFileToString(path, &mhtml));
}
@@ -589,7 +590,7 @@ IN_PROC_BROWSER_TEST_F(
std::string mhtml;
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_content_verification;
+ base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(base::ReadFileToString(params.file_path, &mhtml));
}
}
@@ -616,7 +617,7 @@ IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest,
std::string mhtml;
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_content_verification;
+ base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(base::ReadFileToString(params.file_path, &mhtml));
}
}
@@ -657,7 +658,7 @@ IN_PROC_BROWSER_TEST_F(MHTMLGenerationSitePerProcessTest, GenerateMHTML) {
std::string mhtml;
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_content_verification;
+ base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(base::ReadFileToString(path, &mhtml));
}
@@ -686,7 +687,7 @@ IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, RemovePopupOverlay) {
std::string mhtml;
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_content_verification;
+ base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(base::ReadFileToString(path, &mhtml));
}
@@ -727,7 +728,7 @@ IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, GenerateMHTMLWithExtraData) {
std::string mhtml;
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_content_verification;
+ base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(base::ReadFileToString(path, &mhtml));
}
diff --git a/chromium/content/browser/download/save_package.cc b/chromium/content/browser/download/save_package.cc
index 0310f540c34..187d62297d0 100644
--- a/chromium/content/browser/download/save_package.cc
+++ b/chromium/content/browser/download/save_package.cc
@@ -263,7 +263,11 @@ void SavePackage::InternalInit() {
ukm_download_id_ = download::GetUniqueDownloadId();
download::DownloadUkmHelper::RecordDownloadStarted(
ukm_download_id_, ukm_source_id_, download::DownloadContent::TEXT,
- download::DownloadSource::UNKNOWN);
+ download::DownloadSource::UNKNOWN,
+ download::CheckDownloadConnectionSecurity(
+ web_contents()->GetLastCommittedURL(),
+ std::vector<GURL>{web_contents()->GetLastCommittedURL()}),
+ true /* is_same_host_download */);
}
bool SavePackage::Init(
diff --git a/chromium/content/browser/file_url_loader_factory.cc b/chromium/content/browser/file_url_loader_factory.cc
index 44eb522466d..ea4d8eee977 100644
--- a/chromium/content/browser/file_url_loader_factory.cc
+++ b/chromium/content/browser/file_url_loader_factory.cc
@@ -19,7 +19,7 @@
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "content/public/browser/content_browser_client.h"
@@ -86,6 +86,13 @@ enum class LinkFollowingPolicy {
kDoNotFollow,
};
+GURL AppendUrlSeparator(const GURL& url) {
+ std::string new_path = url.path() + '/';
+ GURL::Replacements replacements;
+ replacements.SetPathStr(new_path);
+ return url.ReplaceComponents(replacements);
+}
+
class FileURLDirectoryLoader
: public network::mojom::URLLoader,
public net::DirectoryLister::DirectoryListerDelegate {
@@ -321,7 +328,26 @@ class FileURLLoader : public network::mojom::URLLoader {
void FollowRedirect(const base::Optional<std::vector<std::string>>&
to_be_removed_request_headers,
const base::Optional<net::HttpRequestHeaders>&
- modified_request_headers) override {}
+ modified_request_headers) override {
+ std::unique_ptr<RedirectData> redirect_data = std::move(redirect_data_);
+ if (redirect_data->is_directory) {
+ FileURLDirectoryLoader::CreateAndStart(
+ redirect_data->profile_path, redirect_data->request,
+ binding_.Unbind(), client_.PassInterface(),
+ std::move(redirect_data->observer),
+ std::move(redirect_data->extra_response_headers));
+ } else {
+ FileURLLoader::CreateAndStart(
+ redirect_data->profile_path, redirect_data->request,
+ binding_.Unbind(), client_.PassInterface(),
+ redirect_data->directory_loading_policy,
+ redirect_data->file_access_policy,
+ redirect_data->link_following_policy,
+ std::move(redirect_data->observer),
+ std::move(redirect_data->extra_response_headers));
+ }
+ MaybeDeleteSelf();
+ }
void ProceedWithResponse() override {}
void SetPriority(net::RequestPriority priority,
int32_t intra_priority_value) override {}
@@ -329,6 +355,23 @@ class FileURLLoader : public network::mojom::URLLoader {
void ResumeReadingBodyFromNet() override {}
private:
+ // Used to save outstanding redirect data while waiting for FollowRedirect
+ // to be called. Values default to their most restrictive in case they are
+ // not set.
+ struct RedirectData {
+ bool is_directory = false;
+ base::FilePath profile_path;
+ network::ResourceRequest request;
+ network::mojom::URLLoaderRequest loader;
+ DirectoryLoadingPolicy directory_loading_policy =
+ DirectoryLoadingPolicy::kFail;
+ FileAccessPolicy file_access_policy = FileAccessPolicy::kRestricted;
+ LinkFollowingPolicy link_following_policy =
+ LinkFollowingPolicy::kDoNotFollow;
+ std::unique_ptr<FileURLLoaderObserver> observer;
+ scoped_refptr<net::HttpResponseHeaders> extra_response_headers;
+ };
+
FileURLLoader() : binding_(this) {}
~FileURLLoader() override = default;
@@ -349,62 +392,50 @@ class FileURLLoader : public network::mojom::URLLoader {
binding_.set_connection_error_handler(base::BindOnce(
&FileURLLoader::OnConnectionError, base::Unretained(this)));
- network::mojom::URLLoaderClientPtr client;
- client.Bind(std::move(client_info));
+ client_.Bind(std::move(client_info));
base::FilePath path;
if (!net::FileURLToFilePath(request.url, &path)) {
- client->OnComplete(network::URLLoaderCompletionStatus(net::ERR_FAILED));
- if (observer)
- observer->OnDoneReading();
+ OnClientComplete(net::ERR_FAILED, std::move(observer));
return;
}
base::File::Info info;
if (!base::GetFileInfo(path, &info)) {
- client->OnComplete(
- network::URLLoaderCompletionStatus(net::ERR_FILE_NOT_FOUND));
- if (observer)
- observer->OnDoneReading();
+ OnClientComplete(net::ERR_FILE_NOT_FOUND, std::move(observer));
return;
}
if (info.is_directory) {
if (directory_loading_policy == DirectoryLoadingPolicy::kFail) {
- client->OnComplete(
- network::URLLoaderCompletionStatus(net::ERR_FILE_NOT_FOUND));
- if (observer)
- observer->OnDoneReading();
+ OnClientComplete(net::ERR_FILE_NOT_FOUND, std::move(observer));
return;
}
DCHECK_EQ(directory_loading_policy,
DirectoryLoadingPolicy::kRespondWithListing);
- GURL directory_url = request.url;
- if (!path.EndsWithSeparator()) {
- // If the named path is a directory with no trailing slash, redirect to
- // the same path, but with a trailing slash.
- std::string new_path = directory_url.path() + '/';
- GURL::Replacements replacements;
- replacements.SetPathStr(new_path);
- directory_url = directory_url.ReplaceComponents(replacements);
-
- net::RedirectInfo redirect_info;
- redirect_info.new_method = "GET";
- redirect_info.status_code = 301;
- redirect_info.new_url = directory_url;
- head.encoded_data_length = 0;
- client->OnReceiveRedirect(redirect_info, head);
- }
+ net::RedirectInfo redirect_info;
+ redirect_info.new_method = "GET";
+ redirect_info.status_code = 301;
+ redirect_info.new_url = path.EndsWithSeparator()
+ ? request.url
+ : AppendUrlSeparator(request.url);
+ head.encoded_data_length = 0;
- // Restart the request with a directory loader.
- network::ResourceRequest new_request = request;
- new_request.url = directory_url;
- FileURLDirectoryLoader::CreateAndStart(
- profile_path, new_request, binding_.Unbind(), client.PassInterface(),
- std::move(observer), std::move(extra_response_headers));
- MaybeDeleteSelf();
+ redirect_data_ = std::make_unique<RedirectData>();
+ redirect_data_->is_directory = true;
+ redirect_data_->profile_path = std::move(profile_path);
+ redirect_data_->request = request;
+ redirect_data_->directory_loading_policy = directory_loading_policy;
+ redirect_data_->file_access_policy = file_access_policy;
+ redirect_data_->link_following_policy = link_following_policy;
+ redirect_data_->request.url = redirect_info.new_url;
+ redirect_data_->observer = std::move(observer);
+ redirect_data_->extra_response_headers =
+ std::move(extra_response_headers);
+
+ client_->OnReceiveRedirect(redirect_info, head);
return;
}
@@ -414,40 +445,48 @@ class FileURLLoader : public network::mojom::URLLoader {
base::LowerCaseEqualsASCII(path.Extension(), ".lnk") &&
base::win::ResolveShortcut(path, &shortcut_target, nullptr)) {
// Follow Windows shortcuts
+ redirect_data_ = std::make_unique<RedirectData>();
+ if (!base::GetFileInfo(shortcut_target, &info)) {
+ OnClientComplete(net::ERR_FILE_NOT_FOUND, std::move(observer));
+ return;
+ }
+
GURL new_url = net::FilePathToFileURL(shortcut_target);
+ if (info.is_directory && !path.EndsWithSeparator())
+ new_url = AppendUrlSeparator(new_url);
net::RedirectInfo redirect_info;
redirect_info.new_method = "GET";
redirect_info.status_code = 301;
redirect_info.new_url = new_url;
head.encoded_data_length = 0;
- client->OnReceiveRedirect(redirect_info, head);
-
- // Restart the request with the new URL.
- network::ResourceRequest new_request = request;
- new_request.url = redirect_info.new_url;
- return Start(profile_path, request, binding_.Unbind(),
- client.PassInterface(), directory_loading_policy,
- file_access_policy, link_following_policy,
- std::move(observer), std::move(extra_response_headers));
+
+ redirect_data_->is_directory = info.is_directory;
+ redirect_data_->profile_path = std::move(profile_path);
+ redirect_data_->request = request;
+ redirect_data_->directory_loading_policy = directory_loading_policy;
+ redirect_data_->file_access_policy = file_access_policy;
+ redirect_data_->link_following_policy = link_following_policy;
+ redirect_data_->request.url = redirect_info.new_url;
+ redirect_data_->observer = std::move(observer);
+ redirect_data_->extra_response_headers =
+ std::move(extra_response_headers);
+
+ client_->OnReceiveRedirect(redirect_info, head);
+ return;
}
#endif // defined(OS_WIN)
if (file_access_policy == FileAccessPolicy::kRestricted &&
!GetContentClient()->browser()->IsFileAccessAllowed(
path, base::MakeAbsoluteFilePath(path), profile_path)) {
- client->OnComplete(
- network::URLLoaderCompletionStatus(net::ERR_ACCESS_DENIED));
- if (observer)
- observer->OnDoneReading();
+ OnClientComplete(net::ERR_ACCESS_DENIED, std::move(observer));
return;
}
mojo::DataPipe pipe(kDefaultFileUrlPipeSize);
if (!pipe.consumer_handle.is_valid()) {
- client->OnComplete(network::URLLoaderCompletionStatus(net::ERR_FAILED));
- if (observer)
- observer->OnDoneReading();
+ OnClientComplete(net::ERR_FAILED, std::move(observer));
return;
}
@@ -466,7 +505,8 @@ class FileURLLoader : public network::mojom::URLLoader {
observer->OnDoneReading();
}
net::Error net_error = net::FileErrorToNetError(file.error_details());
- client->OnComplete(network::URLLoaderCompletionStatus(net_error));
+ client_->OnComplete(network::URLLoaderCompletionStatus(net_error));
+ client_.reset();
MaybeDeleteSelf();
return;
}
@@ -484,7 +524,9 @@ class FileURLLoader : public network::mojom::URLLoader {
observer->OnDoneReading();
}
net::Error net_error = net::FileErrorToNetError(read_error);
- client->OnComplete(network::URLLoaderCompletionStatus(net_error));
+ client_->OnComplete(network::URLLoaderCompletionStatus(net_error));
+ client_.reset();
+ MaybeDeleteSelf();
return;
} else if (observer) {
observer->OnBytesRead(initial_read_buffer, initial_read_result,
@@ -509,16 +551,17 @@ class FileURLLoader : public network::mojom::URLLoader {
}
if (fail) {
- client->OnComplete(network::URLLoaderCompletionStatus(
- net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
- if (observer)
- observer->OnDoneReading();
+ OnClientComplete(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE,
+ std::move(observer));
return;
}
}
size_t first_byte_to_send = 0;
size_t total_bytes_to_send = static_cast<size_t>(info.size);
+
+ total_bytes_written_ = static_cast<size_t>(info.size);
+
if (byte_range.IsValid()) {
first_byte_to_send =
static_cast<size_t>(byte_range.first_byte_position());
@@ -557,15 +600,15 @@ class FileURLLoader : public network::mojom::URLLoader {
? net::ForceSniffFileUrlsForHtml::kEnabled
: net::ForceSniffFileUrlsForHtml::kDisabled,
&head.mime_type);
+ head.did_mime_sniff = true;
}
if (head.headers) {
head.headers->AddHeader(
base::StringPrintf("%s: %s", net::HttpRequestHeaders::kContentType,
head.mime_type.c_str()));
}
- client->OnReceiveResponse(head);
- client->OnStartLoadingResponseBody(std::move(pipe.consumer_handle));
- client_ = std::move(client);
+ client_->OnReceiveResponse(head);
+ client_->OnStartLoadingResponseBody(std::move(pipe.consumer_handle));
if (total_bytes_to_send == 0) {
// There's definitely no more data, so we're already done.
@@ -594,6 +637,15 @@ class FileURLLoader : public network::mojom::URLLoader {
MaybeDeleteSelf();
}
+ void OnClientComplete(net::Error net_error,
+ std::unique_ptr<FileURLLoaderObserver> observer) {
+ client_->OnComplete(network::URLLoaderCompletionStatus(net_error));
+ client_.reset();
+ if (observer)
+ observer->OnDoneReading();
+ MaybeDeleteSelf();
+ }
+
void MaybeDeleteSelf() {
if (!binding_.is_bound() && !client_.is_bound())
delete this;
@@ -607,10 +659,15 @@ class FileURLLoader : public network::mojom::URLLoader {
if (observer)
observer->OnDoneReading();
- if (result == MOJO_RESULT_OK)
- client_->OnComplete(network::URLLoaderCompletionStatus(net::OK));
- else
+ if (result == MOJO_RESULT_OK) {
+ network::URLLoaderCompletionStatus status(net::OK);
+ status.encoded_data_length = total_bytes_written_;
+ status.encoded_body_length = total_bytes_written_;
+ status.decoded_body_length = total_bytes_written_;
+ client_->OnComplete(status);
+ } else {
client_->OnComplete(network::URLLoaderCompletionStatus(net::ERR_FAILED));
+ }
client_.reset();
MaybeDeleteSelf();
}
@@ -618,6 +675,12 @@ class FileURLLoader : public network::mojom::URLLoader {
std::unique_ptr<mojo::FileDataPipeProducer> data_producer_;
mojo::Binding<network::mojom::URLLoader> binding_;
network::mojom::URLLoaderClientPtr client_;
+ std::unique_ptr<RedirectData> redirect_data_;
+
+ // In case of successful loads, this holds the total of bytes written.
+ // It is used to set some of the URLLoaderCompletionStatus data passed back
+ // to the URLLoaderClients (eg SimpleURLLoader).
+ size_t total_bytes_written_ = 0;
DISALLOW_COPY_AND_ASSIGN(FileURLLoader);
};
@@ -640,8 +703,12 @@ void FileURLLoaderFactory::CreateLoaderAndStart(
network::mojom::URLLoaderClientPtr client,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
base::FilePath file_path;
- const bool is_file = net::FileURLToFilePath(request.url, &file_path);
- if (is_file && file_path.EndsWithSeparator() && file_path.IsAbsolute()) {
+ if (!net::FileURLToFilePath(request.url, &file_path)) {
+ client->OnComplete(
+ network::URLLoaderCompletionStatus(net::ERR_INVALID_URL));
+ return;
+ }
+ if (file_path.EndsWithSeparator() && file_path.IsAbsolute()) {
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&FileURLDirectoryLoader::CreateAndStart, profile_path_,
@@ -672,7 +739,7 @@ void CreateFileURLLoader(
std::unique_ptr<FileURLLoaderObserver> observer,
scoped_refptr<net::HttpResponseHeaders> extra_response_headers) {
auto task_runner = base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::BACKGROUND,
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
task_runner->PostTask(
FROM_HERE,
@@ -684,4 +751,12 @@ void CreateFileURLLoader(
std::move(extra_response_headers)));
}
+std::unique_ptr<network::mojom::URLLoaderFactory> CreateFileURLLoaderFactory(
+ const base::FilePath& profile_path) {
+ return std::make_unique<content::FileURLLoaderFactory>(
+ profile_path, base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
+}
+
} // namespace content
diff --git a/chromium/content/browser/fileapi/browser_file_system_helper.cc b/chromium/content/browser/fileapi/browser_file_system_helper.cc
index acf067a117b..7227c691e73 100644
--- a/chromium/content/browser/fileapi/browser_file_system_helper.cc
+++ b/chromium/content/browser/fileapi/browser_file_system_helper.cc
@@ -14,7 +14,7 @@
#include "base/files/file_path.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/task_scheduler/lazy_task_runner.h"
+#include "base/task/lazy_task_runner.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
diff --git a/chromium/content/browser/fileapi/file_system_chooser.cc b/chromium/content/browser/fileapi/file_system_chooser.cc
new file mode 100644
index 00000000000..0c8ae67d894
--- /dev/null
+++ b/chromium/content/browser/fileapi/file_system_chooser.cc
@@ -0,0 +1,105 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/fileapi/file_system_chooser.h"
+
+#include "base/bind.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/child_process_security_policy.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_client.h"
+#include "storage/browser/fileapi/isolated_context.h"
+#include "ui/shell_dialogs/select_file_policy.h"
+
+namespace content {
+
+// static
+void FileSystemChooser::CreateAndShow(
+ int render_process_id,
+ int frame_id,
+ ResultCallback callback,
+ scoped_refptr<base::TaskRunner> callback_runner) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ RenderFrameHost* rfh = RenderFrameHost::FromID(render_process_id, frame_id);
+ WebContents* web_contents = WebContents::FromRenderFrameHost(rfh);
+ auto* listener = new FileSystemChooser(render_process_id, std::move(callback),
+ std::move(callback_runner));
+ listener->dialog_ = ui::SelectFileDialog::Create(
+ listener,
+ GetContentClient()->browser()->CreateSelectFilePolicy(web_contents));
+ // TODO(https://crbug.com/878581): Better/more specific options to pass to
+ // SelectFile.
+ listener->dialog_->SelectFile(
+ ui::SelectFileDialog::SELECT_OPEN_FILE, /*title=*/base::string16(),
+ /*default_path=*/base::FilePath(), /*file_types=*/nullptr,
+ /*file_type_index=*/0,
+ /*default_extension=*/base::FilePath::StringType(),
+ web_contents ? web_contents->GetTopLevelNativeWindow() : nullptr,
+ /*params=*/nullptr);
+}
+
+FileSystemChooser::FileSystemChooser(
+ int render_process_id,
+ ResultCallback callback,
+ scoped_refptr<base::TaskRunner> callback_runner)
+ : render_process_id_(render_process_id),
+ callback_(std::move(callback)),
+ callback_runner_(std::move(callback_runner)) {}
+
+FileSystemChooser::~FileSystemChooser() {
+ if (dialog_)
+ dialog_->ListenerDestroyed();
+}
+
+void FileSystemChooser::FileSelected(const base::FilePath& path,
+ int index,
+ void* params) {
+ MultiFilesSelected({path}, params);
+}
+
+void FileSystemChooser::MultiFilesSelected(
+ const std::vector<base::FilePath>& files,
+ void* params) {
+ auto* isolated_context = storage::IsolatedContext::GetInstance();
+ DCHECK(isolated_context);
+
+ auto* security_policy = ChildProcessSecurityPolicy::GetInstance();
+ DCHECK(security_policy);
+
+ std::vector<blink::mojom::FileSystemEntryPtr> result;
+ result.reserve(files.size());
+ for (const auto& path : files) {
+ auto entry = blink::mojom::FileSystemEntry::New();
+ entry->file_system_id = isolated_context->RegisterFileSystemForPath(
+ storage::kFileSystemTypeNativeForPlatformApp, std::string(), path,
+ &entry->base_name);
+
+ // TODO(https://crbug.com/878585): Determine if we always want to grant
+ // write permission.
+ security_policy->GrantReadFileSystem(render_process_id_,
+ entry->file_system_id);
+ security_policy->GrantWriteFileSystem(render_process_id_,
+ entry->file_system_id);
+ security_policy->GrantDeleteFromFileSystem(render_process_id_,
+ entry->file_system_id);
+
+ result.push_back(std::move(entry));
+ }
+
+ callback_runner_->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback_), base::File::FILE_OK,
+ std::move(result)));
+ delete this;
+}
+
+void FileSystemChooser::FileSelectionCanceled(void* params) {
+ callback_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(callback_), base::File::FILE_ERROR_ABORT,
+ std::vector<blink::mojom::FileSystemEntryPtr>()));
+ delete this;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/fileapi/file_system_chooser.h b/chromium/content/browser/fileapi/file_system_chooser.h
new file mode 100644
index 00000000000..2283a6725e3
--- /dev/null
+++ b/chromium/content/browser/fileapi/file_system_chooser.h
@@ -0,0 +1,55 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_FILEAPI_FILE_SYSTEM_CHOOSER_H_
+#define CONTENT_BROWSER_FILEAPI_FILE_SYSTEM_CHOOSER_H_
+
+#include "base/files/file.h"
+#include "base/task_runner.h"
+#include "third_party/blink/public/mojom/filesystem/file_system.mojom.h"
+#include "ui/shell_dialogs/select_file_dialog.h"
+
+namespace content {
+
+// This is a ui::SelectFileDialog::Listener implementation that grants access to
+// the selected files to a specific renderer process on success, and then calls
+// a callback on a specific task runner. Furthermore the listener will delete
+// itself when any of its listener methods are called.
+// All of this class has to be called on the UI thread.
+class FileSystemChooser : public ui::SelectFileDialog::Listener {
+ public:
+ using ResultCallback =
+ base::OnceCallback<void(base::File::Error,
+ std::vector<blink::mojom::FileSystemEntryPtr>)>;
+
+ static void CreateAndShow(int render_process_id,
+ int frame_id,
+ ResultCallback callback,
+ scoped_refptr<base::TaskRunner> callback_runner);
+
+ FileSystemChooser(int render_process_id,
+ ResultCallback callback,
+ scoped_refptr<base::TaskRunner> callback_runner);
+
+ private:
+ ~FileSystemChooser() override;
+
+ // ui::SelectFileDialog::Listener:
+ void FileSelected(const base::FilePath& path,
+ int index,
+ void* params) override;
+ void MultiFilesSelected(const std::vector<base::FilePath>& files,
+ void* params) override;
+ void FileSelectionCanceled(void* params) override;
+
+ int render_process_id_;
+ ResultCallback callback_;
+ scoped_refptr<base::TaskRunner> callback_runner_;
+
+ scoped_refptr<ui::SelectFileDialog> dialog_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_FILEAPI_FILE_SYSTEM_CHOOSER_H_
diff --git a/chromium/content/browser/fileapi/file_system_manager_impl.cc b/chromium/content/browser/fileapi/file_system_manager_impl.cc
new file mode 100644
index 00000000000..e8b7272c921
--- /dev/null
+++ b/chromium/content/browser/fileapi/file_system_manager_impl.cc
@@ -0,0 +1,872 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/fileapi/file_system_manager_impl.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/metrics/user_metrics.h"
+#include "base/sequenced_task_runner.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "components/services/filesystem/public/interfaces/types.mojom.h"
+#include "content/browser/bad_message.h"
+#include "content/browser/blob_storage/chrome_blob_storage_context.h"
+#include "content/browser/child_process_security_policy_impl.h"
+#include "content/browser/fileapi/browser_file_system_helper.h"
+#include "content/browser/fileapi/file_system_chooser.h"
+#include "content/common/fileapi/webblob_messages.h"
+#include "content/public/browser/browser_thread.h"
+#include "ipc/ipc_platform_file.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "net/base/mime_util.h"
+#include "storage/browser/blob/blob_data_builder.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/blob/shareable_file_reference.h"
+#include "storage/browser/fileapi/file_observers.h"
+#include "storage/browser/fileapi/file_permission_policy.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_writer_impl.h"
+#include "storage/browser/fileapi/isolated_context.h"
+#include "storage/common/fileapi/file_system_info.h"
+#include "storage/common/fileapi/file_system_type_converters.h"
+#include "storage/common/fileapi/file_system_types.h"
+#include "storage/common/fileapi/file_system_util.h"
+#include "third_party/blink/public/common/features.h"
+#include "url/gurl.h"
+
+using storage::FileSystemFileUtil;
+using storage::FileSystemBackend;
+using storage::FileSystemOperation;
+using storage::FileSystemURL;
+using storage::BlobDataBuilder;
+using storage::BlobStorageContext;
+
+namespace content {
+
+namespace {
+
+void RevokeFilePermission(int child_id, const base::FilePath& path) {
+ ChildProcessSecurityPolicyImpl::GetInstance()->RevokeAllPermissionsForFile(
+ child_id, path);
+}
+
+} // namespace
+
+class FileSystemManagerImpl::FileSystemCancellableOperationImpl
+ : public blink::mojom::FileSystemCancellableOperation {
+ using OperationID = storage::FileSystemOperationRunner::OperationID;
+
+ public:
+ FileSystemCancellableOperationImpl(
+ OperationID id,
+ FileSystemManagerImpl* file_system_manager_impl)
+ : id_(id), file_system_manager_impl_(file_system_manager_impl) {}
+ ~FileSystemCancellableOperationImpl() override = default;
+
+ private:
+ void Cancel(CancelCallback callback) override {
+ file_system_manager_impl_->Cancel(id_, std::move(callback));
+ }
+
+ const OperationID id_;
+ // |file_system_manager_impl| owns |this| through a StrongBindingSet.
+ FileSystemManagerImpl* const file_system_manager_impl_;
+};
+
+class FileSystemManagerImpl::ReceivedSnapshotListenerImpl
+ : public blink::mojom::ReceivedSnapshotListener {
+ public:
+ ReceivedSnapshotListenerImpl(int snapshot_id,
+ FileSystemManagerImpl* file_system_manager_impl)
+ : snapshot_id_(snapshot_id),
+ file_system_manager_impl_(file_system_manager_impl) {}
+ ~ReceivedSnapshotListenerImpl() override = default;
+
+ private:
+ void DidReceiveSnapshotFile() override {
+ file_system_manager_impl_->DidReceiveSnapshotFile(snapshot_id_);
+ }
+
+ const int snapshot_id_;
+ // |file_system_manager_impl| owns |this| through a StrongBindingSet.
+ FileSystemManagerImpl* const file_system_manager_impl_;
+};
+
+struct FileSystemManagerImpl::WriteSyncCallbackEntry {
+ WriteSyncCallback callback;
+ int64_t bytes;
+
+ explicit WriteSyncCallbackEntry(WriteSyncCallback cb)
+ : callback(std::move(cb)), bytes(0) {}
+};
+
+struct FileSystemManagerImpl::ReadDirectorySyncCallbackEntry {
+ ReadDirectorySyncCallback callback;
+ std::vector<filesystem::mojom::DirectoryEntryPtr> entries;
+
+ explicit ReadDirectorySyncCallbackEntry(ReadDirectorySyncCallback cb)
+ : callback(std::move(cb)) {}
+};
+
+FileSystemManagerImpl::FileSystemManagerImpl(
+ int process_id,
+ storage::FileSystemContext* file_system_context,
+ scoped_refptr<ChromeBlobStorageContext> blob_storage_context)
+ : process_id_(process_id),
+ context_(file_system_context),
+ security_policy_(ChildProcessSecurityPolicyImpl::GetInstance()),
+ blob_storage_context_(blob_storage_context),
+ weak_factory_(this) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(context_);
+ DCHECK(blob_storage_context);
+ bindings_.set_connection_error_handler(base::BindRepeating(
+ &FileSystemManagerImpl::OnConnectionError, base::Unretained(this)));
+}
+
+FileSystemManagerImpl::~FileSystemManagerImpl() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+}
+
+base::WeakPtr<FileSystemManagerImpl> FileSystemManagerImpl::GetWeakPtr() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ return weak_factory_.GetWeakPtr();
+}
+
+void FileSystemManagerImpl::BindRequest(
+ blink::mojom::FileSystemManagerRequest request) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!operation_runner_)
+ operation_runner_ = context_->CreateFileSystemOperationRunner();
+ bindings_.AddBinding(this, std::move(request));
+}
+
+void FileSystemManagerImpl::Open(const GURL& origin_url,
+ blink::mojom::FileSystemType file_system_type,
+ OpenCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (file_system_type == blink::mojom::FileSystemType::kTemporary) {
+ RecordAction(base::UserMetricsAction("OpenFileSystemTemporary"));
+ } else if (file_system_type == blink::mojom::FileSystemType::kPersistent) {
+ RecordAction(base::UserMetricsAction("OpenFileSystemPersistent"));
+ }
+ context_->OpenFileSystem(
+ origin_url, mojo::ConvertTo<storage::FileSystemType>(file_system_type),
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ base::BindOnce(&FileSystemManagerImpl::DidOpenFileSystem, GetWeakPtr(),
+ std::move(callback)));
+};
+
+void FileSystemManagerImpl::ResolveURL(const GURL& filesystem_url,
+ ResolveURLCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ FileSystemURL url(context_->CrackURL(filesystem_url));
+ base::Optional<base::File::Error> opt_error = ValidateFileSystemURL(url);
+ if (opt_error) {
+ std::move(callback).Run(blink::mojom::FileSystemInfo::New(),
+ base::FilePath(), false, opt_error.value());
+ return;
+ }
+
+ if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
+ std::move(callback).Run(blink::mojom::FileSystemInfo::New(),
+ base::FilePath(), false,
+ base::File::FILE_ERROR_SECURITY);
+ return;
+ }
+
+ context_->ResolveURL(
+ url, base::BindOnce(&FileSystemManagerImpl::DidResolveURL, GetWeakPtr(),
+ std::move(callback)));
+}
+
+void FileSystemManagerImpl::Move(const GURL& src_path,
+ const GURL& dest_path,
+ MoveCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ FileSystemURL src_url(context_->CrackURL(src_path));
+ FileSystemURL dest_url(context_->CrackURL(dest_path));
+ base::Optional<base::File::Error> opt_error = ValidateFileSystemURL(src_url);
+ if (!opt_error)
+ opt_error = ValidateFileSystemURL(dest_url);
+ if (opt_error) {
+ std::move(callback).Run(opt_error.value());
+ return;
+ }
+ if (!security_policy_->CanReadFileSystemFile(process_id_, src_url) ||
+ !security_policy_->CanDeleteFileSystemFile(process_id_, src_url) ||
+ !security_policy_->CanCreateFileSystemFile(process_id_, dest_url)) {
+ std::move(callback).Run(base::File::FILE_ERROR_SECURITY);
+ return;
+ }
+
+ operation_runner()->Move(
+ src_url, dest_url, storage::FileSystemOperation::OPTION_NONE,
+ base::BindRepeating(&FileSystemManagerImpl::DidFinish, GetWeakPtr(),
+ base::Passed(&callback)));
+}
+
+void FileSystemManagerImpl::Copy(const GURL& src_path,
+ const GURL& dest_path,
+ CopyCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ FileSystemURL src_url(context_->CrackURL(src_path));
+ FileSystemURL dest_url(context_->CrackURL(dest_path));
+ base::Optional<base::File::Error> opt_error = ValidateFileSystemURL(src_url);
+ if (!opt_error)
+ opt_error = ValidateFileSystemURL(dest_url);
+ if (opt_error) {
+ std::move(callback).Run(opt_error.value());
+ return;
+ }
+ if (!security_policy_->CanReadFileSystemFile(process_id_, src_url) ||
+ !security_policy_->CanCopyIntoFileSystemFile(process_id_, dest_url)) {
+ std::move(callback).Run(base::File::FILE_ERROR_SECURITY);
+ return;
+ }
+
+ operation_runner()->Copy(
+ src_url, dest_url, storage::FileSystemOperation::OPTION_NONE,
+ FileSystemOperation::ERROR_BEHAVIOR_ABORT,
+ storage::FileSystemOperationRunner::CopyProgressCallback(),
+ base::BindRepeating(&FileSystemManagerImpl::DidFinish, GetWeakPtr(),
+ base::Passed(&callback)));
+}
+
+void FileSystemManagerImpl::Remove(const GURL& path,
+ bool recursive,
+ RemoveCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ FileSystemURL url(context_->CrackURL(path));
+ base::Optional<base::File::Error> opt_error = ValidateFileSystemURL(url);
+ if (opt_error) {
+ std::move(callback).Run(opt_error.value());
+ return;
+ }
+ if (!security_policy_->CanDeleteFileSystemFile(process_id_, url)) {
+ std::move(callback).Run(base::File::FILE_ERROR_SECURITY);
+ return;
+ }
+
+ operation_runner()->Remove(
+ url, recursive,
+ base::BindRepeating(&FileSystemManagerImpl::DidFinish, GetWeakPtr(),
+ base::Passed(&callback)));
+}
+
+void FileSystemManagerImpl::ReadMetadata(const GURL& path,
+ ReadMetadataCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ FileSystemURL url(context_->CrackURL(path));
+ base::Optional<base::File::Error> opt_error = ValidateFileSystemURL(url);
+ if (opt_error) {
+ std::move(callback).Run(base::File::Info(), opt_error.value());
+ return;
+ }
+ if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
+ std::move(callback).Run(base::File::Info(),
+ base::File::FILE_ERROR_SECURITY);
+ return;
+ }
+
+ operation_runner()->GetMetadata(
+ url,
+ FileSystemOperation::GET_METADATA_FIELD_IS_DIRECTORY |
+ FileSystemOperation::GET_METADATA_FIELD_SIZE |
+ FileSystemOperation::GET_METADATA_FIELD_LAST_MODIFIED,
+ base::BindRepeating(&FileSystemManagerImpl::DidGetMetadata, GetWeakPtr(),
+ base::Passed(&callback)));
+}
+
+void FileSystemManagerImpl::Create(const GURL& path,
+ bool exclusive,
+ bool is_directory,
+ bool recursive,
+ CreateCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ FileSystemURL url(context_->CrackURL(path));
+ base::Optional<base::File::Error> opt_error = ValidateFileSystemURL(url);
+ if (opt_error) {
+ std::move(callback).Run(opt_error.value());
+ return;
+ }
+ if (!security_policy_->CanCreateFileSystemFile(process_id_, url)) {
+ std::move(callback).Run(base::File::FILE_ERROR_SECURITY);
+ return;
+ }
+
+ if (is_directory) {
+ operation_runner()->CreateDirectory(
+ url, exclusive, recursive,
+ base::BindRepeating(&FileSystemManagerImpl::DidFinish, GetWeakPtr(),
+ base::Passed(&callback)));
+ } else {
+ operation_runner()->CreateFile(
+ url, exclusive,
+ base::BindRepeating(&FileSystemManagerImpl::DidFinish, GetWeakPtr(),
+ base::Passed(&callback)));
+ }
+}
+
+void FileSystemManagerImpl::Exists(const GURL& path,
+ bool is_directory,
+ ExistsCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ FileSystemURL url(context_->CrackURL(path));
+ base::Optional<base::File::Error> opt_error = ValidateFileSystemURL(url);
+ if (opt_error) {
+ std::move(callback).Run(opt_error.value());
+ return;
+ }
+ if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
+ std::move(callback).Run(base::File::FILE_ERROR_SECURITY);
+ return;
+ }
+
+ if (is_directory) {
+ operation_runner()->DirectoryExists(
+ url, base::BindRepeating(&FileSystemManagerImpl::DidFinish,
+ GetWeakPtr(), base::Passed(&callback)));
+ } else {
+ operation_runner()->FileExists(
+ url, base::BindRepeating(&FileSystemManagerImpl::DidFinish,
+ GetWeakPtr(), base::Passed(&callback)));
+ }
+}
+
+void FileSystemManagerImpl::ReadDirectory(
+ const GURL& path,
+ blink::mojom::FileSystemOperationListenerPtr listener) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ FileSystemURL url(context_->CrackURL(path));
+ base::Optional<base::File::Error> opt_error = ValidateFileSystemURL(url);
+ if (opt_error) {
+ listener->ErrorOccurred(opt_error.value());
+ return;
+ }
+ if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
+ listener->ErrorOccurred(base::File::FILE_ERROR_SECURITY);
+ return;
+ }
+
+ OperationListenerID listener_id = AddOpListener(std::move(listener));
+ operation_runner()->ReadDirectory(
+ url, base::BindRepeating(&FileSystemManagerImpl::DidReadDirectory,
+ GetWeakPtr(), listener_id));
+}
+
+void FileSystemManagerImpl::ReadDirectorySync(
+ const GURL& path,
+ ReadDirectorySyncCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ FileSystemURL url(context_->CrackURL(path));
+ base::Optional<base::File::Error> opt_error = ValidateFileSystemURL(url);
+ if (opt_error) {
+ std::move(callback).Run(std::vector<filesystem::mojom::DirectoryEntryPtr>(),
+ opt_error.value());
+ return;
+ }
+ if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
+ std::move(callback).Run(std::vector<filesystem::mojom::DirectoryEntryPtr>(),
+ base::File::FILE_ERROR_SECURITY);
+ return;
+ }
+
+ operation_runner()->ReadDirectory(
+ url, base::BindRepeating(
+ &FileSystemManagerImpl::DidReadDirectorySync, GetWeakPtr(),
+ base::Owned(
+ new ReadDirectorySyncCallbackEntry(std::move(callback)))));
+}
+
+void FileSystemManagerImpl::Write(
+ const GURL& file_path,
+ const std::string& blob_uuid,
+ int64_t position,
+ blink::mojom::FileSystemCancellableOperationRequest op_request,
+ blink::mojom::FileSystemOperationListenerPtr listener) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ FileSystemURL url(context_->CrackURL(file_path));
+ base::Optional<base::File::Error> opt_error = ValidateFileSystemURL(url);
+ if (opt_error) {
+ listener->ErrorOccurred(opt_error.value());
+ return;
+ }
+ if (!security_policy_->CanWriteFileSystemFile(process_id_, url)) {
+ listener->ErrorOccurred(base::File::FILE_ERROR_SECURITY);
+ return;
+ }
+ std::unique_ptr<storage::BlobDataHandle> blob =
+ blob_storage_context_->context()->GetBlobDataFromUUID(blob_uuid);
+
+ OperationListenerID listener_id = AddOpListener(std::move(listener));
+
+ OperationID op_id = operation_runner()->Write(
+ url, std::move(blob), position,
+ base::BindRepeating(&FileSystemManagerImpl::DidWrite, GetWeakPtr(),
+ listener_id));
+ cancellable_operations_.AddBinding(
+ std::make_unique<FileSystemCancellableOperationImpl>(op_id, this),
+ std::move(op_request));
+}
+
+void FileSystemManagerImpl::WriteSync(const GURL& file_path,
+ const std::string& blob_uuid,
+ int64_t position,
+ WriteSyncCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ FileSystemURL url(context_->CrackURL(file_path));
+ base::Optional<base::File::Error> opt_error = ValidateFileSystemURL(url);
+ if (opt_error) {
+ std::move(callback).Run(0, opt_error.value());
+ return;
+ }
+ if (!security_policy_->CanWriteFileSystemFile(process_id_, url)) {
+ std::move(callback).Run(0, base::File::FILE_ERROR_SECURITY);
+ return;
+ }
+ std::unique_ptr<storage::BlobDataHandle> blob =
+ blob_storage_context_->context()->GetBlobDataFromUUID(blob_uuid);
+
+ operation_runner()->Write(
+ url, std::move(blob), position,
+ base::BindRepeating(
+ &FileSystemManagerImpl::DidWriteSync, GetWeakPtr(),
+ base::Owned(new WriteSyncCallbackEntry(std::move(callback)))));
+}
+
+void FileSystemManagerImpl::Truncate(
+ const GURL& file_path,
+ int64_t length,
+ blink::mojom::FileSystemCancellableOperationRequest op_request,
+ TruncateCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ FileSystemURL url(context_->CrackURL(file_path));
+ base::Optional<base::File::Error> opt_error = ValidateFileSystemURL(url);
+ if (opt_error) {
+ std::move(callback).Run(opt_error.value());
+ return;
+ }
+ if (!security_policy_->CanWriteFileSystemFile(process_id_, url)) {
+ std::move(callback).Run(base::File::FILE_ERROR_SECURITY);
+ return;
+ }
+
+ OperationID op_id = operation_runner()->Truncate(
+ url, length,
+ base::BindRepeating(&FileSystemManagerImpl::DidFinish, GetWeakPtr(),
+ base::Passed(&callback)));
+ cancellable_operations_.AddBinding(
+ std::make_unique<FileSystemCancellableOperationImpl>(op_id, this),
+ std::move(op_request));
+}
+
+void FileSystemManagerImpl::TruncateSync(const GURL& file_path,
+ int64_t length,
+ TruncateSyncCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ FileSystemURL url(context_->CrackURL(file_path));
+ base::Optional<base::File::Error> opt_error = ValidateFileSystemURL(url);
+ if (opt_error) {
+ std::move(callback).Run(opt_error.value());
+ return;
+ }
+ if (!security_policy_->CanWriteFileSystemFile(process_id_, url)) {
+ std::move(callback).Run(base::File::FILE_ERROR_SECURITY);
+ return;
+ }
+
+ operation_runner()->Truncate(
+ url, length,
+ base::BindRepeating(&FileSystemManagerImpl::DidFinish, GetWeakPtr(),
+ base::Passed(&callback)));
+}
+
+void FileSystemManagerImpl::TouchFile(const GURL& path,
+ base::Time last_access_time,
+ base::Time last_modified_time,
+ TouchFileCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ FileSystemURL url(context_->CrackURL(path));
+ base::Optional<base::File::Error> opt_error = ValidateFileSystemURL(url);
+ if (opt_error) {
+ std::move(callback).Run(opt_error.value());
+ return;
+ }
+ if (!security_policy_->CanCreateFileSystemFile(process_id_, url)) {
+ std::move(callback).Run(base::File::FILE_ERROR_SECURITY);
+ return;
+ }
+
+ operation_runner()->TouchFile(
+ url, last_access_time, last_modified_time,
+ base::BindRepeating(&FileSystemManagerImpl::DidFinish, GetWeakPtr(),
+ base::Passed(&callback)));
+}
+
+void FileSystemManagerImpl::CreateSnapshotFile(
+ const GURL& file_path,
+ CreateSnapshotFileCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ FileSystemURL url(context_->CrackURL(file_path));
+
+ // Make sure if this file can be read by the renderer as this is
+ // called when the renderer is about to create a new File object
+ // (for reading the file).
+ base::Optional<base::File::Error> opt_error = ValidateFileSystemURL(url);
+ if (opt_error) {
+ std::move(callback).Run(base::File::Info(), base::FilePath(),
+ opt_error.value(), nullptr);
+ return;
+ }
+ if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
+ std::move(callback).Run(base::File::Info(), base::FilePath(),
+ base::File::FILE_ERROR_SECURITY, nullptr);
+ return;
+ }
+
+ FileSystemBackend* backend = context_->GetFileSystemBackend(url.type());
+ if (backend->SupportsStreaming(url)) {
+ operation_runner()->GetMetadata(
+ url,
+ FileSystemOperation::GET_METADATA_FIELD_IS_DIRECTORY |
+ FileSystemOperation::GET_METADATA_FIELD_SIZE |
+ FileSystemOperation::GET_METADATA_FIELD_LAST_MODIFIED,
+ base::BindRepeating(&FileSystemManagerImpl::DidGetMetadataForStreaming,
+ GetWeakPtr(), base::Passed(&callback)));
+ } else {
+ operation_runner()->CreateSnapshotFile(
+ url, base::BindRepeating(&FileSystemManagerImpl::DidCreateSnapshot,
+ GetWeakPtr(), base::Passed(&callback), url));
+ }
+}
+
+void FileSystemManagerImpl::GetPlatformPath(const GURL& path,
+ GetPlatformPathCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ base::FilePath platform_path;
+ context_->default_file_task_runner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&FileSystemManagerImpl::GetPlatformPathOnFileThread, path,
+ process_id_, base::Unretained(context_), GetWeakPtr(),
+ std::move(callback)));
+}
+
+void FileSystemManagerImpl::CreateWriter(const GURL& file_path,
+ CreateWriterCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ FileSystemURL url(context_->CrackURL(file_path));
+ base::Optional<base::File::Error> opt_error = ValidateFileSystemURL(url);
+ if (opt_error) {
+ std::move(callback).Run(opt_error.value(), nullptr);
+ return;
+ }
+ if (!security_policy_->CanWriteFileSystemFile(process_id_, url)) {
+ std::move(callback).Run(base::File::FILE_ERROR_SECURITY, nullptr);
+ return;
+ }
+
+ blink::mojom::FileWriterPtr writer;
+ mojo::MakeStrongBinding(std::make_unique<storage::FileWriterImpl>(
+ url, context_->CreateFileSystemOperationRunner(),
+ blob_storage_context_->context()->AsWeakPtr()),
+ MakeRequest(&writer));
+ std::move(callback).Run(base::File::FILE_OK, std::move(writer));
+}
+
+void FileSystemManagerImpl::ChooseEntry(int32_t render_frame_id,
+ ChooseEntryCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!base::FeatureList::IsEnabled(blink::features::kWritableFilesAPI)) {
+ bindings_.ReportBadMessage("FSMI_WRITABLE_FILES_DISABLED");
+ return;
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&FileSystemChooser::CreateAndShow, process_id_,
+ render_frame_id, std::move(callback),
+ BrowserThread::GetTaskRunnerForThread(BrowserThread::IO)));
+}
+
+void FileSystemManagerImpl::Cancel(
+ OperationID op_id,
+ FileSystemCancellableOperationImpl::CancelCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ operation_runner()->Cancel(
+ op_id, base::BindRepeating(&FileSystemManagerImpl::DidFinish,
+ GetWeakPtr(), base::Passed(&callback)));
+}
+
+void FileSystemManagerImpl::DidReceiveSnapshotFile(int snapshot_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ in_transit_snapshot_files_.Remove(snapshot_id);
+}
+
+void FileSystemManagerImpl::OnConnectionError() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (bindings_.empty()) {
+ in_transit_snapshot_files_.Clear();
+ operation_runner_.reset();
+ }
+}
+
+void FileSystemManagerImpl::DidFinish(
+ base::OnceCallback<void(base::File::Error)> callback,
+ base::File::Error error_code) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ std::move(callback).Run(error_code);
+}
+
+void FileSystemManagerImpl::DidGetMetadata(ReadMetadataCallback callback,
+ base::File::Error result,
+ const base::File::Info& info) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ std::move(callback).Run(info, result);
+}
+
+void FileSystemManagerImpl::DidGetMetadataForStreaming(
+ CreateSnapshotFileCallback callback,
+ base::File::Error result,
+ const base::File::Info& info) {
+ // For now, streaming Blobs are implemented as a successful snapshot file
+ // creation with an empty path.
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ std::move(callback).Run(info, base::FilePath(), result, nullptr);
+}
+
+void FileSystemManagerImpl::DidReadDirectory(
+ OperationListenerID listener_id,
+ base::File::Error result,
+ std::vector<filesystem::mojom::DirectoryEntry> entries,
+ bool has_more) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ blink::mojom::FileSystemOperationListener* listener =
+ GetOpListener(listener_id);
+ if (!listener)
+ return;
+ if (result != base::File::FILE_OK) {
+ DCHECK(!has_more);
+ listener->ErrorOccurred(result);
+ RemoveOpListener(listener_id);
+ return;
+ }
+ std::vector<filesystem::mojom::DirectoryEntryPtr> entry_struct_ptrs;
+ for (const auto& entry : entries) {
+ entry_struct_ptrs.emplace_back(
+ filesystem::mojom::DirectoryEntry::New(entry));
+ }
+ listener->ResultsRetrieved(std::move(entry_struct_ptrs), has_more);
+ if (!has_more)
+ RemoveOpListener(listener_id);
+}
+
+void FileSystemManagerImpl::DidReadDirectorySync(
+ ReadDirectorySyncCallbackEntry* callback_entry,
+ base::File::Error result,
+ std::vector<filesystem::mojom::DirectoryEntry> entries,
+ bool has_more) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ for (const auto& entry : entries) {
+ callback_entry->entries.emplace_back(
+ filesystem::mojom::DirectoryEntry::New(std::move(entry)));
+ }
+ if (result != base::File::FILE_OK || !has_more) {
+ std::move(callback_entry->callback)
+ .Run(std::move(callback_entry->entries), result);
+ }
+}
+
+void FileSystemManagerImpl::DidWrite(OperationListenerID listener_id,
+ base::File::Error result,
+ int64_t bytes,
+ bool complete) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ blink::mojom::FileSystemOperationListener* listener =
+ GetOpListener(listener_id);
+ if (!listener)
+ return;
+ if (result == base::File::FILE_OK) {
+ listener->DidWrite(bytes, complete);
+ if (complete)
+ RemoveOpListener(listener_id);
+ } else {
+ listener->ErrorOccurred(result);
+ RemoveOpListener(listener_id);
+ }
+}
+
+void FileSystemManagerImpl::DidWriteSync(WriteSyncCallbackEntry* entry,
+ base::File::Error result,
+ int64_t bytes,
+ bool complete) {
+ entry->bytes += bytes;
+ if (complete || result != base::File::FILE_OK)
+ std::move(entry->callback).Run(entry->bytes, result);
+}
+
+void FileSystemManagerImpl::DidOpenFileSystem(
+ OpenCallback callback,
+ const GURL& root,
+ const std::string& filesystem_name,
+ base::File::Error result) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(root.is_valid() || result != base::File::FILE_OK);
+ std::move(callback).Run(filesystem_name, root, result);
+ // For OpenFileSystem we do not create a new operation, so no unregister here.
+}
+
+void FileSystemManagerImpl::DidResolveURL(
+ ResolveURLCallback callback,
+ base::File::Error result,
+ const storage::FileSystemInfo& info,
+ const base::FilePath& file_path,
+ storage::FileSystemContext::ResolvedEntryType type) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (result == base::File::FILE_OK &&
+ type == storage::FileSystemContext::RESOLVED_ENTRY_NOT_FOUND)
+ result = base::File::FILE_ERROR_NOT_FOUND;
+
+ std::move(callback).Run(
+ mojo::ConvertTo<blink::mojom::FileSystemInfoPtr>(info), file_path,
+ type == storage::FileSystemContext::RESOLVED_ENTRY_DIRECTORY, result);
+ // For ResolveURL we do not create a new operation, so no unregister here.
+}
+
+void FileSystemManagerImpl::DidCreateSnapshot(
+ CreateSnapshotFileCallback callback,
+ const storage::FileSystemURL& url,
+ base::File::Error result,
+ const base::File::Info& info,
+ const base::FilePath& platform_path,
+ scoped_refptr<storage::ShareableFileReference> /* unused */) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (result != base::File::FILE_OK) {
+ std::move(callback).Run(base::File::Info(), base::FilePath(), result,
+ nullptr);
+ return;
+ }
+
+ scoped_refptr<storage::ShareableFileReference> file_ref =
+ storage::ShareableFileReference::Get(platform_path);
+ if (!security_policy_->CanReadFile(process_id_, platform_path)) {
+ // Give per-file read permission to the snapshot file if it hasn't it yet.
+ // In order for the renderer to be able to read the file via File object,
+ // it must be granted per-file read permission for the file's platform
+ // path. By now, it has already been verified that the renderer has
+ // sufficient permissions to read the file, so giving per-file permission
+ // here must be safe.
+ security_policy_->GrantReadFile(process_id_, platform_path);
+
+ // Revoke all permissions for the file when the last ref of the file
+ // is dropped.
+ if (!file_ref.get()) {
+ // Create a reference for temporary permission handling.
+ file_ref = storage::ShareableFileReference::GetOrCreate(
+ platform_path,
+ storage::ShareableFileReference::DONT_DELETE_ON_FINAL_RELEASE,
+ context_->default_file_task_runner());
+ }
+ file_ref->AddFinalReleaseCallback(
+ base::BindOnce(&RevokeFilePermission, process_id_));
+ }
+
+ if (file_ref.get()) {
+ // This ref is held until DidReceiveSnapshotFile is called.
+ int request_id = in_transit_snapshot_files_.Add(file_ref);
+ blink::mojom::ReceivedSnapshotListenerPtr listener_ptr;
+ snapshot_listeners_.AddBinding(
+ std::make_unique<ReceivedSnapshotListenerImpl>(request_id, this),
+ mojo::MakeRequest<blink::mojom::ReceivedSnapshotListener>(
+ &listener_ptr));
+ // Return the file info and platform_path.
+ std::move(callback).Run(info, platform_path, result,
+ std::move(listener_ptr));
+ return;
+ }
+
+ // Return the file info and platform_path.
+ std::move(callback).Run(info, platform_path, result, nullptr);
+}
+
+void FileSystemManagerImpl::DidGetPlatformPath(GetPlatformPathCallback callback,
+ base::FilePath platform_path) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ std::move(callback).Run(platform_path);
+}
+
+// static
+void FileSystemManagerImpl::GetPlatformPathOnFileThread(
+ const GURL& path,
+ int process_id,
+ storage::FileSystemContext* context,
+ base::WeakPtr<FileSystemManagerImpl> file_system_manager,
+ GetPlatformPathCallback callback) {
+ base::FilePath platform_path;
+ SyncGetPlatformPath(context, process_id, path, &platform_path);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&FileSystemManagerImpl::DidGetPlatformPath,
+ file_system_manager, std::move(callback), platform_path));
+}
+
+base::Optional<base::File::Error> FileSystemManagerImpl::ValidateFileSystemURL(
+ const storage::FileSystemURL& url) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!FileSystemURLIsValid(context_, url))
+ return base::File::FILE_ERROR_INVALID_URL;
+
+ // Deny access to files in PluginPrivate FileSystem from JavaScript.
+ // TODO(nhiroki): Move this filter somewhere else since this is not for
+ // validation.
+ if (url.type() == storage::kFileSystemTypePluginPrivate)
+ return base::File::FILE_ERROR_SECURITY;
+
+ return base::nullopt;
+}
+
+FileSystemManagerImpl::OperationListenerID FileSystemManagerImpl::AddOpListener(
+ blink::mojom::FileSystemOperationListenerPtr listener) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ int op_id = next_operation_listener_id_++;
+ listener.set_connection_error_handler(
+ base::BindOnce(&FileSystemManagerImpl::OnConnectionErrorForOpListeners,
+ base::Unretained(this), op_id));
+ op_listeners_[op_id] = std::move(listener);
+ return op_id;
+}
+
+void FileSystemManagerImpl::RemoveOpListener(OperationListenerID listener_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(op_listeners_.find(listener_id) != op_listeners_.end());
+ op_listeners_.erase(listener_id);
+}
+
+blink::mojom::FileSystemOperationListener* FileSystemManagerImpl::GetOpListener(
+ OperationListenerID listener_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (op_listeners_.find(listener_id) == op_listeners_.end())
+ return nullptr;
+ return &*op_listeners_[listener_id];
+}
+
+void FileSystemManagerImpl::OnConnectionErrorForOpListeners(
+ OperationListenerID listener_id) {
+ RemoveOpListener(listener_id);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/fileapi/file_system_manager_impl.h b/chromium/content/browser/fileapi/file_system_manager_impl.h
new file mode 100644
index 00000000000..f5e4cbf7f4c
--- /dev/null
+++ b/chromium/content/browser/fileapi/file_system_manager_impl.h
@@ -0,0 +1,237 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_FILEAPI_FILE_SYSTEM_MANAGER_IMPL_H_
+#define CONTENT_BROWSER_FILEAPI_FILE_SYSTEM_MANAGER_IMPL_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/containers/hash_tables.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/shared_memory.h"
+#include "components/services/filesystem/public/interfaces/types.mojom.h"
+#include "content/browser/streams/stream.h"
+#include "content/browser/streams/stream_context.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/browser_message_filter.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/interface_ptr_set.h"
+#include "mojo/public/cpp/bindings/strong_binding_set.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_operation_runner.h"
+#include "storage/common/fileapi/file_system_types.h"
+#include "third_party/blink/public/mojom/filesystem/file_system.mojom.h"
+
+class GURL;
+
+namespace base {
+class FilePath;
+class Time;
+} // namespace base
+
+namespace storage {
+class FileSystemURL;
+class FileSystemOperationRunner;
+struct FileSystemInfo;
+class ShareableFileReference;
+} // namespace storage
+
+namespace content {
+class ChildProcessSecurityPolicyImpl;
+class ChromeBlobStorageContext;
+
+// All methods for this class are expected to be called on the IO thread,
+// except for the constructor. The destructor must also be called on the IO
+// thread as weak refs are created on that thread. A single instance of this
+// class is owned by RenderProcessHostImpl.
+class CONTENT_EXPORT FileSystemManagerImpl
+ : public blink::mojom::FileSystemManager {
+ public:
+ // Used by the renderer process host on the UI thread.
+ FileSystemManagerImpl(
+ int process_id,
+ storage::FileSystemContext* file_system_context,
+ scoped_refptr<ChromeBlobStorageContext> blob_storage_context);
+ ~FileSystemManagerImpl() override;
+ base::WeakPtr<FileSystemManagerImpl> GetWeakPtr();
+
+ void BindRequest(blink::mojom::FileSystemManagerRequest request);
+
+ // blink::mojom::FileSystem
+ void Open(const GURL& origin_url,
+ blink::mojom::FileSystemType file_system_type,
+ OpenCallback callback) override;
+ void ResolveURL(const GURL& filesystem_url,
+ ResolveURLCallback callback) override;
+ void Move(const GURL& src_path,
+ const GURL& dest_path,
+ MoveCallback callback) override;
+ void Copy(const GURL& src_path,
+ const GURL& dest_path,
+ CopyCallback callback) override;
+ void Remove(const GURL& path,
+ bool recursive,
+ RemoveCallback callback) override;
+ void ReadMetadata(const GURL& path, ReadMetadataCallback callback) override;
+ void Create(const GURL& path,
+ bool exclusive,
+ bool is_directory,
+ bool recursive,
+ CreateCallback callback) override;
+ void Exists(const GURL& path,
+ bool is_directory,
+ ExistsCallback callback) override;
+ void ReadDirectory(
+ const GURL& path,
+ blink::mojom::FileSystemOperationListenerPtr listener) override;
+ void ReadDirectorySync(const GURL& path,
+ ReadDirectorySyncCallback callback) override;
+ void Write(const GURL& file_path,
+ const std::string& blob_uuid,
+ int64_t position,
+ blink::mojom::FileSystemCancellableOperationRequest op_request,
+ blink::mojom::FileSystemOperationListenerPtr listener) override;
+ void WriteSync(const GURL& file_path,
+ const std::string& blob_uuid,
+ int64_t position,
+ WriteSyncCallback callback) override;
+ void Truncate(const GURL& file_path,
+ int64_t length,
+ blink::mojom::FileSystemCancellableOperationRequest op_request,
+ TruncateCallback callback) override;
+ void TruncateSync(const GURL& file_path,
+ int64_t length,
+ TruncateSyncCallback callback) override;
+ void TouchFile(const GURL& path,
+ base::Time last_access_time,
+ base::Time last_modified_time,
+ TouchFileCallback callback) override;
+ void CreateSnapshotFile(const GURL& file_path,
+ CreateSnapshotFileCallback callback) override;
+ void GetPlatformPath(const GURL& file_path,
+ GetPlatformPathCallback callback) override;
+ void CreateWriter(const GURL& file_path,
+ CreateWriterCallback callback) override;
+ void ChooseEntry(int32_t render_frame_id,
+ ChooseEntryCallback callback) override;
+
+ private:
+ class FileSystemCancellableOperationImpl;
+ class ReceivedSnapshotListenerImpl;
+ using OperationID = storage::FileSystemOperationRunner::OperationID;
+ using OperationListenerID = int;
+ struct WriteSyncCallbackEntry;
+ struct ReadDirectorySyncCallbackEntry;
+
+ void Cancel(
+ OperationID op_id,
+ blink::mojom::FileSystemCancellableOperation::CancelCallback callback);
+ void DidReceiveSnapshotFile(int snapshot_id);
+ void OnConnectionError();
+
+ // Callback functions to be used when each file operation is finished.
+ void DidFinish(base::OnceCallback<void(base::File::Error)> callback,
+ base::File::Error error_code);
+ void DidGetMetadata(ReadMetadataCallback callback,
+ base::File::Error result,
+ const base::File::Info& info);
+ void DidGetMetadataForStreaming(CreateSnapshotFileCallback callback,
+ base::File::Error result,
+ const base::File::Info& info);
+ void DidReadDirectory(OperationListenerID listener_id,
+ base::File::Error result,
+ std::vector<filesystem::mojom::DirectoryEntry> entries,
+ bool has_more);
+ void DidReadDirectorySync(
+ ReadDirectorySyncCallbackEntry* callback_entry,
+ base::File::Error result,
+ std::vector<filesystem::mojom::DirectoryEntry> entries,
+ bool has_more);
+ void DidWrite(OperationListenerID listener_id,
+ base::File::Error result,
+ int64_t bytes,
+ bool complete);
+ void DidWriteSync(WriteSyncCallbackEntry* entry,
+ base::File::Error result,
+ int64_t bytes,
+ bool complete);
+ void DidOpenFileSystem(OpenCallback callback,
+ const GURL& root,
+ const std::string& filesystem_name,
+ base::File::Error result);
+ void DidResolveURL(ResolveURLCallback callback,
+ base::File::Error result,
+ const storage::FileSystemInfo& info,
+ const base::FilePath& file_path,
+ storage::FileSystemContext::ResolvedEntryType type);
+ void DidCreateSnapshot(
+ CreateSnapshotFileCallback callback,
+ const storage::FileSystemURL& url,
+ base::File::Error result,
+ const base::File::Info& info,
+ const base::FilePath& platform_path,
+ scoped_refptr<storage::ShareableFileReference> file_ref);
+ void DidGetPlatformPath(GetPlatformPathCallback callback,
+ base::FilePath platform_path);
+
+ static void GetPlatformPathOnFileThread(
+ const GURL& path,
+ int process_id,
+ storage::FileSystemContext* context,
+ base::WeakPtr<FileSystemManagerImpl> file_system_manager,
+ GetPlatformPathCallback callback);
+ // Returns an error if |url| is invalid.
+ base::Optional<base::File::Error> ValidateFileSystemURL(
+ const storage::FileSystemURL& url);
+
+ storage::FileSystemOperationRunner* operation_runner() {
+ return operation_runner_.get();
+ }
+
+ OperationListenerID AddOpListener(
+ blink::mojom::FileSystemOperationListenerPtr listener);
+ void RemoveOpListener(OperationListenerID listener_id);
+ blink::mojom::FileSystemOperationListener* GetOpListener(
+ OperationListenerID listener_id);
+ void OnConnectionErrorForOpListeners(OperationListenerID listener_id);
+
+ const int process_id_;
+ storage::FileSystemContext* const context_;
+ ChildProcessSecurityPolicyImpl* const security_policy_;
+ const scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
+ std::unique_ptr<storage::FileSystemOperationRunner> operation_runner_;
+
+ mojo::BindingSet<blink::mojom::FileSystemManager> bindings_;
+ mojo::StrongBindingSet<blink::mojom::FileSystemCancellableOperation>
+ cancellable_operations_;
+ mojo::StrongBindingSet<blink::mojom::ReceivedSnapshotListener>
+ snapshot_listeners_;
+
+ std::unordered_map<OperationListenerID,
+ blink::mojom::FileSystemOperationListenerPtr>
+ op_listeners_;
+ OperationListenerID next_operation_listener_id_ = 1;
+
+ // Used to keep snapshot files alive while a DidCreateSnapshot
+ // is being sent to the renderer.
+ base::IDMap<scoped_refptr<storage::ShareableFileReference>>
+ in_transit_snapshot_files_;
+
+ base::WeakPtrFactory<FileSystemManagerImpl> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileSystemManagerImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_FILEAPI_FILE_SYSTEM_MANAGER_IMPL_H_
diff --git a/chromium/content/browser/fileapi/file_system_operation_runner_unittest.cc b/chromium/content/browser/fileapi/file_system_operation_runner_unittest.cc
index 68bc445357a..8b520d24936 100644
--- a/chromium/content/browser/fileapi/file_system_operation_runner_unittest.cc
+++ b/chromium/content/browser/fileapi/file_system_operation_runner_unittest.cc
@@ -8,9 +8,9 @@
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
#include "base/run_loop.h"
-#include "base/task_scheduler/post_task.h"
-#include "base/task_scheduler/task_scheduler.h"
-#include "base/task_scheduler/task_traits.h"
+#include "base/task/post_task.h"
+#include "base/task/task_scheduler/task_scheduler.h"
+#include "base/task/task_traits.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_restrictions.h"
#include "base/threading/thread_task_runner_handle.h"
diff --git a/chromium/content/browser/fileapi/file_system_url_loader_factory.cc b/chromium/content/browser/fileapi/file_system_url_loader_factory.cc
index 7ef37b18b9f..3e55c0fa785 100644
--- a/chromium/content/browser/fileapi/file_system_url_loader_factory.cc
+++ b/chromium/content/browser/fileapi/file_system_url_loader_factory.cc
@@ -15,8 +15,8 @@
#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/stringprintf.h"
-#include "base/task_scheduler/post_task.h"
-#include "base/task_scheduler/task_traits.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
#include "build/build_config.h"
#include "components/services/filesystem/public/interfaces/types.mojom.h"
#include "content/browser/child_process_security_policy_impl.h"
@@ -446,14 +446,6 @@ class FileSystemFileURLLoader : public FileSystemEntryURLLoader {
original_request_.url.ReplaceComponents(replacements);
head_.encoded_data_length = 0;
client_->OnReceiveRedirect(redirect_info, head_);
-
- // Restart the request with a directory loader.
- network::ResourceRequest new_request = original_request_;
- new_request.url = redirect_info.new_url;
- FileSystemDirectoryURLLoader::CreateAndStart(
- new_request, binding_.Unbind(), client_.PassInterface(),
- std::move(params_), io_task_runner_);
- MaybeDeleteSelf();
return;
}
@@ -522,6 +514,7 @@ class FileSystemFileURLLoader : public FileSystemEntryURLLoader {
SniffMimeType(file_data_->data(), result, url_.ToGURL(), type_hint,
net::ForceSniffFileUrlsForHtml::kDisabled,
&head_.mime_type);
+ head_.did_mime_sniff = true;
}
client_->OnReceiveResponse(head_);
diff --git a/chromium/content/browser/fileapi/file_system_url_loader_factory_browsertest.cc b/chromium/content/browser/fileapi/file_system_url_loader_factory_browsertest.cc
index 82cfc2765d2..980fddbef0f 100644
--- a/chromium/content/browser/fileapi/file_system_url_loader_factory_browsertest.cc
+++ b/chromium/content/browser/fileapi/file_system_url_loader_factory_browsertest.cc
@@ -739,6 +739,7 @@ IN_PROC_BROWSER_TEST_F(FileSystemURLLoaderFactoryTest, FileGetMimeType) {
EXPECT_TRUE(client->has_received_completion());
EXPECT_EQ(mime_type_direct, client->response_head().mime_type);
+ EXPECT_TRUE(client->response_head().did_mime_sniff);
}
IN_PROC_BROWSER_TEST_F(FileSystemURLLoaderFactoryTest, FileIncognito) {
diff --git a/chromium/content/browser/fileapi/fileapi_message_filter.cc b/chromium/content/browser/fileapi/fileapi_message_filter.cc
deleted file mode 100644
index 1e427681d69..00000000000
--- a/chromium/content/browser/fileapi/fileapi_message_filter.cc
+++ /dev/null
@@ -1,642 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/fileapi/fileapi_message_filter.h"
-
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/metrics/user_metrics.h"
-#include "base/sequenced_task_runner.h"
-#include "base/strings/string_util.h"
-#include "base/threading/thread.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
-#include "components/services/filesystem/public/interfaces/types.mojom.h"
-#include "content/browser/bad_message.h"
-#include "content/browser/blob_storage/chrome_blob_storage_context.h"
-#include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/fileapi/browser_file_system_helper.h"
-#include "content/common/fileapi/file_system_messages.h"
-#include "content/common/fileapi/webblob_messages.h"
-#include "content/public/browser/browser_thread.h"
-#include "ipc/ipc_platform_file.h"
-#include "net/base/mime_util.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "storage/browser/blob/blob_data_builder.h"
-#include "storage/browser/blob/blob_storage_context.h"
-#include "storage/browser/blob/shareable_file_reference.h"
-#include "storage/browser/fileapi/file_observers.h"
-#include "storage/browser/fileapi/file_permission_policy.h"
-#include "storage/browser/fileapi/file_system_context.h"
-#include "storage/browser/fileapi/isolated_context.h"
-#include "storage/common/fileapi/file_system_info.h"
-#include "storage/common/fileapi/file_system_types.h"
-#include "storage/common/fileapi/file_system_util.h"
-#include "url/gurl.h"
-
-using storage::FileSystemFileUtil;
-using storage::FileSystemBackend;
-using storage::FileSystemOperation;
-using storage::FileSystemURL;
-using storage::BlobDataBuilder;
-using storage::BlobStorageContext;
-
-namespace content {
-
-namespace {
-
-const uint32_t kFileApiFilteredMessageClasses[] = {FileSystemMsgStart,
- BlobMsgStart};
-
-void RevokeFilePermission(int child_id, const base::FilePath& path) {
- ChildProcessSecurityPolicyImpl::GetInstance()->RevokeAllPermissionsForFile(
- child_id, path);
-}
-
-} // namespace
-
-FileAPIMessageFilter::FileAPIMessageFilter(
- int process_id,
- net::URLRequestContextGetter* request_context_getter,
- storage::FileSystemContext* file_system_context,
- ChromeBlobStorageContext* blob_storage_context)
- : BrowserMessageFilter(kFileApiFilteredMessageClasses,
- arraysize(kFileApiFilteredMessageClasses)),
- process_id_(process_id),
- context_(file_system_context),
- security_policy_(ChildProcessSecurityPolicyImpl::GetInstance()),
- request_context_getter_(request_context_getter),
- request_context_(nullptr),
- blob_storage_context_(blob_storage_context) {
- DCHECK(context_);
- DCHECK(request_context_getter_.get());
- DCHECK(blob_storage_context);
-}
-
-FileAPIMessageFilter::FileAPIMessageFilter(
- int process_id,
- net::URLRequestContext* request_context,
- storage::FileSystemContext* file_system_context,
- ChromeBlobStorageContext* blob_storage_context)
- : BrowserMessageFilter(kFileApiFilteredMessageClasses,
- arraysize(kFileApiFilteredMessageClasses)),
- process_id_(process_id),
- context_(file_system_context),
- security_policy_(ChildProcessSecurityPolicyImpl::GetInstance()),
- request_context_(request_context),
- blob_storage_context_(blob_storage_context) {
- DCHECK(context_);
- DCHECK(request_context_);
- DCHECK(blob_storage_context);
-}
-
-void FileAPIMessageFilter::OnChannelConnected(int32_t peer_pid) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- if (request_context_getter_.get()) {
- DCHECK(!request_context_);
- request_context_ = request_context_getter_->GetURLRequestContext();
- request_context_getter_ = nullptr;
- DCHECK(request_context_);
- }
-
- operation_runner_ = context_->CreateFileSystemOperationRunner();
-}
-
-void FileAPIMessageFilter::OnChannelClosing() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- in_transit_snapshot_files_.clear();
-
- operation_runner_.reset();
- operations_.clear();
-}
-
-base::TaskRunner* FileAPIMessageFilter::OverrideTaskRunnerForMessage(
- const IPC::Message& message) {
- if (message.type() == FileSystemHostMsg_SyncGetPlatformPath::ID)
- return context_->default_file_task_runner();
- return nullptr;
-}
-
-bool FileAPIMessageFilter::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(FileAPIMessageFilter, message)
- IPC_MESSAGE_HANDLER(FileSystemHostMsg_OpenFileSystem, OnOpenFileSystem)
- IPC_MESSAGE_HANDLER(FileSystemHostMsg_ResolveURL, OnResolveURL)
- IPC_MESSAGE_HANDLER(FileSystemHostMsg_Move, OnMove)
- IPC_MESSAGE_HANDLER(FileSystemHostMsg_Copy, OnCopy)
- IPC_MESSAGE_HANDLER(FileSystemHostMsg_Remove, OnRemove)
- IPC_MESSAGE_HANDLER(FileSystemHostMsg_ReadMetadata, OnReadMetadata)
- IPC_MESSAGE_HANDLER(FileSystemHostMsg_Create, OnCreate)
- IPC_MESSAGE_HANDLER(FileSystemHostMsg_Exists, OnExists)
- IPC_MESSAGE_HANDLER(FileSystemHostMsg_ReadDirectory, OnReadDirectory)
- IPC_MESSAGE_HANDLER(FileSystemHostMsg_Write, OnWrite)
- IPC_MESSAGE_HANDLER(FileSystemHostMsg_Truncate, OnTruncate)
- IPC_MESSAGE_HANDLER(FileSystemHostMsg_TouchFile, OnTouchFile)
- IPC_MESSAGE_HANDLER(FileSystemHostMsg_CancelWrite, OnCancel)
- IPC_MESSAGE_HANDLER(FileSystemHostMsg_CreateSnapshotFile,
- OnCreateSnapshotFile)
- IPC_MESSAGE_HANDLER(FileSystemHostMsg_DidReceiveSnapshotFile,
- OnDidReceiveSnapshotFile)
- IPC_MESSAGE_HANDLER(FileSystemHostMsg_SyncGetPlatformPath,
- OnSyncGetPlatformPath)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-FileAPIMessageFilter::~FileAPIMessageFilter() {}
-
-void FileAPIMessageFilter::OnOpenFileSystem(int request_id,
- const GURL& origin_url,
- storage::FileSystemType type) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (type == storage::kFileSystemTypeTemporary) {
- RecordAction(base::UserMetricsAction("OpenFileSystemTemporary"));
- } else if (type == storage::kFileSystemTypePersistent) {
- RecordAction(base::UserMetricsAction("OpenFileSystemPersistent"));
- }
- storage::OpenFileSystemMode mode =
- storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT;
- context_->OpenFileSystem(
- origin_url, type, mode,
- base::BindOnce(&FileAPIMessageFilter::DidOpenFileSystem, this,
- request_id));
-}
-
-void FileAPIMessageFilter::OnResolveURL(
- int request_id,
- const GURL& filesystem_url) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- FileSystemURL url(context_->CrackURL(filesystem_url));
- if (!ValidateFileSystemURL(request_id, url))
- return;
- if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
- Send(new FileSystemMsg_DidFail(request_id,
- base::File::FILE_ERROR_SECURITY));
- return;
- }
-
- context_->ResolveURL(url, base::BindOnce(&FileAPIMessageFilter::DidResolveURL,
- this, request_id));
-}
-
-void FileAPIMessageFilter::OnMove(
- int request_id, const GURL& src_path, const GURL& dest_path) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- FileSystemURL src_url(context_->CrackURL(src_path));
- FileSystemURL dest_url(context_->CrackURL(dest_path));
- if (!ValidateFileSystemURL(request_id, src_url) ||
- !ValidateFileSystemURL(request_id, dest_url)) {
- return;
- }
- if (!security_policy_->CanReadFileSystemFile(process_id_, src_url) ||
- !security_policy_->CanDeleteFileSystemFile(process_id_, src_url) ||
- !security_policy_->CanCreateFileSystemFile(process_id_, dest_url)) {
- Send(new FileSystemMsg_DidFail(request_id,
- base::File::FILE_ERROR_SECURITY));
- return;
- }
-
- operations_[request_id] = operation_runner()->Move(
- src_url,
- dest_url,
- storage::FileSystemOperation::OPTION_NONE,
- base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
-}
-
-void FileAPIMessageFilter::OnCopy(
- int request_id, const GURL& src_path, const GURL& dest_path) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- FileSystemURL src_url(context_->CrackURL(src_path));
- FileSystemURL dest_url(context_->CrackURL(dest_path));
- if (!ValidateFileSystemURL(request_id, src_url) ||
- !ValidateFileSystemURL(request_id, dest_url)) {
- return;
- }
- if (!security_policy_->CanReadFileSystemFile(process_id_, src_url) ||
- !security_policy_->CanCopyIntoFileSystemFile(process_id_, dest_url)) {
- Send(new FileSystemMsg_DidFail(request_id,
- base::File::FILE_ERROR_SECURITY));
- return;
- }
-
- operations_[request_id] = operation_runner()->Copy(
- src_url, dest_url, storage::FileSystemOperation::OPTION_NONE,
- FileSystemOperation::ERROR_BEHAVIOR_ABORT,
- storage::FileSystemOperationRunner::CopyProgressCallback(),
- base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
-}
-
-void FileAPIMessageFilter::OnRemove(
- int request_id, const GURL& path, bool recursive) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- FileSystemURL url(context_->CrackURL(path));
- if (!ValidateFileSystemURL(request_id, url))
- return;
- if (!security_policy_->CanDeleteFileSystemFile(process_id_, url)) {
- Send(new FileSystemMsg_DidFail(request_id,
- base::File::FILE_ERROR_SECURITY));
- return;
- }
-
- operations_[request_id] = operation_runner()->Remove(
- url, recursive,
- base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
-}
-
-void FileAPIMessageFilter::OnReadMetadata(
- int request_id, const GURL& path) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- FileSystemURL url(context_->CrackURL(path));
- if (!ValidateFileSystemURL(request_id, url))
- return;
- if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
- Send(new FileSystemMsg_DidFail(request_id,
- base::File::FILE_ERROR_SECURITY));
- return;
- }
-
- operations_[request_id] = operation_runner()->GetMetadata(
- url, FileSystemOperation::GET_METADATA_FIELD_IS_DIRECTORY |
- FileSystemOperation::GET_METADATA_FIELD_SIZE |
- FileSystemOperation::GET_METADATA_FIELD_LAST_MODIFIED,
- base::Bind(&FileAPIMessageFilter::DidGetMetadata, this, request_id));
-}
-
-void FileAPIMessageFilter::OnCreate(
- int request_id, const GURL& path, bool exclusive,
- bool is_directory, bool recursive) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- FileSystemURL url(context_->CrackURL(path));
- if (!ValidateFileSystemURL(request_id, url))
- return;
- if (!security_policy_->CanCreateFileSystemFile(process_id_, url)) {
- Send(new FileSystemMsg_DidFail(request_id,
- base::File::FILE_ERROR_SECURITY));
- return;
- }
-
- if (is_directory) {
- operations_[request_id] = operation_runner()->CreateDirectory(
- url, exclusive, recursive,
- base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
- } else {
- operations_[request_id] = operation_runner()->CreateFile(
- url, exclusive,
- base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
- }
-}
-
-void FileAPIMessageFilter::OnExists(
- int request_id, const GURL& path, bool is_directory) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- FileSystemURL url(context_->CrackURL(path));
- if (!ValidateFileSystemURL(request_id, url))
- return;
- if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
- Send(new FileSystemMsg_DidFail(request_id,
- base::File::FILE_ERROR_SECURITY));
- return;
- }
-
- if (is_directory) {
- operations_[request_id] = operation_runner()->DirectoryExists(
- url,
- base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
- } else {
- operations_[request_id] = operation_runner()->FileExists(
- url,
- base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
- }
-}
-
-void FileAPIMessageFilter::OnReadDirectory(
- int request_id, const GURL& path) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- FileSystemURL url(context_->CrackURL(path));
- if (!ValidateFileSystemURL(request_id, url))
- return;
- if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
- Send(new FileSystemMsg_DidFail(request_id,
- base::File::FILE_ERROR_SECURITY));
- return;
- }
-
- operations_[request_id] = operation_runner()->ReadDirectory(
- url, base::BindRepeating(&FileAPIMessageFilter::DidReadDirectory, this,
- request_id));
-}
-
-void FileAPIMessageFilter::OnWrite(int request_id,
- const GURL& path,
- const std::string& blob_uuid,
- int64_t offset) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!request_context_) {
- // We can't write w/o a request context, trying to do so will crash.
- NOTREACHED();
- return;
- }
-
- FileSystemURL url(context_->CrackURL(path));
- if (!ValidateFileSystemURL(request_id, url))
- return;
- if (!security_policy_->CanWriteFileSystemFile(process_id_, url)) {
- Send(new FileSystemMsg_DidFail(request_id,
- base::File::FILE_ERROR_SECURITY));
- return;
- }
-
- std::unique_ptr<storage::BlobDataHandle> blob =
- blob_storage_context_->context()->GetBlobDataFromUUID(blob_uuid);
-
- operations_[request_id] = operation_runner()->Write(
- request_context_, url, std::move(blob), offset,
- base::Bind(&FileAPIMessageFilter::DidWrite, this, request_id));
-}
-
-void FileAPIMessageFilter::OnTruncate(int request_id,
- const GURL& path,
- int64_t length) {
- FileSystemURL url(context_->CrackURL(path));
- if (!ValidateFileSystemURL(request_id, url))
- return;
- if (!security_policy_->CanWriteFileSystemFile(process_id_, url)) {
- Send(new FileSystemMsg_DidFail(request_id,
- base::File::FILE_ERROR_SECURITY));
- return;
- }
-
- operations_[request_id] = operation_runner()->Truncate(
- url, length,
- base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
-}
-
-void FileAPIMessageFilter::OnTouchFile(
- int request_id,
- const GURL& path,
- const base::Time& last_access_time,
- const base::Time& last_modified_time) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- FileSystemURL url(context_->CrackURL(path));
- if (!ValidateFileSystemURL(request_id, url))
- return;
- if (!security_policy_->CanCreateFileSystemFile(process_id_, url)) {
- Send(new FileSystemMsg_DidFail(request_id,
- base::File::FILE_ERROR_SECURITY));
- return;
- }
-
- operations_[request_id] = operation_runner()->TouchFile(
- url, last_access_time, last_modified_time,
- base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
-}
-
-void FileAPIMessageFilter::OnCancel(
- int request_id,
- int request_id_to_cancel) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- OperationsMap::iterator found = operations_.find(request_id_to_cancel);
- if (found != operations_.end()) {
- // The cancel will eventually send both the write failure and the cancel
- // success.
- operation_runner()->Cancel(
- found->second,
- base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
- } else {
- // The write already finished; report that we failed to stop it.
- Send(new FileSystemMsg_DidFail(
- request_id, base::File::FILE_ERROR_INVALID_OPERATION));
- }
-}
-
-void FileAPIMessageFilter::OnSyncGetPlatformPath(
- const GURL& path, base::FilePath* platform_path) {
- SyncGetPlatformPath(context_, process_id_, path, platform_path);
-}
-
-void FileAPIMessageFilter::OnCreateSnapshotFile(
- int request_id, const GURL& path) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- FileSystemURL url(context_->CrackURL(path));
-
- // Make sure if this file can be read by the renderer as this is
- // called when the renderer is about to create a new File object
- // (for reading the file).
- if (!ValidateFileSystemURL(request_id, url))
- return;
- if (!security_policy_->CanReadFileSystemFile(process_id_, url)) {
- Send(new FileSystemMsg_DidFail(request_id,
- base::File::FILE_ERROR_SECURITY));
- return;
- }
-
- FileSystemBackend* backend = context_->GetFileSystemBackend(url.type());
- if (backend->SupportsStreaming(url)) {
- operations_[request_id] = operation_runner()->GetMetadata(
- url, FileSystemOperation::GET_METADATA_FIELD_IS_DIRECTORY |
- FileSystemOperation::GET_METADATA_FIELD_SIZE |
- FileSystemOperation::GET_METADATA_FIELD_LAST_MODIFIED,
- base::Bind(&FileAPIMessageFilter::DidGetMetadataForStreaming, this,
- request_id));
- } else {
- operations_[request_id] = operation_runner()->CreateSnapshotFile(
- url,
- base::Bind(&FileAPIMessageFilter::DidCreateSnapshot,
- this, request_id, url));
- }
-}
-
-void FileAPIMessageFilter::OnDidReceiveSnapshotFile(int request_id) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- in_transit_snapshot_files_.erase(request_id);
-}
-
-void FileAPIMessageFilter::DidFinish(int request_id,
- base::File::Error result) {
- if (result == base::File::FILE_OK)
- Send(new FileSystemMsg_DidSucceed(request_id));
- else
- Send(new FileSystemMsg_DidFail(request_id, result));
- operations_.erase(request_id);
-}
-
-void FileAPIMessageFilter::DidGetMetadata(
- int request_id,
- base::File::Error result,
- const base::File::Info& info) {
- if (result == base::File::FILE_OK)
- Send(new FileSystemMsg_DidReadMetadata(request_id, info));
- else
- Send(new FileSystemMsg_DidFail(request_id, result));
- operations_.erase(request_id);
-}
-
-void FileAPIMessageFilter::DidGetMetadataForStreaming(
- int request_id,
- base::File::Error result,
- const base::File::Info& info) {
- if (result == base::File::FILE_OK) {
- // For now, streaming Blobs are implemented as a successful snapshot file
- // creation with an empty path.
- Send(new FileSystemMsg_DidCreateSnapshotFile(request_id, info,
- base::FilePath()));
- } else {
- Send(new FileSystemMsg_DidFail(request_id, result));
- }
- operations_.erase(request_id);
-}
-
-void FileAPIMessageFilter::DidReadDirectory(
- int request_id,
- base::File::Error result,
- std::vector<filesystem::mojom::DirectoryEntry> entries,
- bool has_more) {
- if (result == base::File::FILE_OK) {
- if (!entries.empty() || !has_more)
- Send(new FileSystemMsg_DidReadDirectory(request_id, std::move(entries),
- has_more));
- } else {
- DCHECK(!has_more);
- Send(new FileSystemMsg_DidFail(request_id, result));
- }
- if (!has_more)
- operations_.erase(request_id);
-}
-
-void FileAPIMessageFilter::DidWrite(int request_id,
- base::File::Error result,
- int64_t bytes,
- bool complete) {
- if (result == base::File::FILE_OK) {
- Send(new FileSystemMsg_DidWrite(request_id, bytes, complete));
- if (complete)
- operations_.erase(request_id);
- } else {
- Send(new FileSystemMsg_DidFail(request_id, result));
- operations_.erase(request_id);
- }
-}
-
-void FileAPIMessageFilter::DidOpenFileSystem(int request_id,
- const GURL& root,
- const std::string& filesystem_name,
- base::File::Error result) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (result == base::File::FILE_OK) {
- DCHECK(root.is_valid());
- Send(new FileSystemMsg_DidOpenFileSystem(
- request_id, filesystem_name, root));
- } else {
- Send(new FileSystemMsg_DidFail(request_id, result));
- }
- // For OpenFileSystem we do not create a new operation, so no unregister here.
-}
-
-void FileAPIMessageFilter::DidResolveURL(
- int request_id,
- base::File::Error result,
- const storage::FileSystemInfo& info,
- const base::FilePath& file_path,
- storage::FileSystemContext::ResolvedEntryType type) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (result == base::File::FILE_OK &&
- type == storage::FileSystemContext::RESOLVED_ENTRY_NOT_FOUND)
- result = base::File::FILE_ERROR_NOT_FOUND;
-
- if (result == base::File::FILE_OK) {
- DCHECK(info.root_url.is_valid());
- Send(new FileSystemMsg_DidResolveURL(
- request_id,
- info,
- file_path,
- type == storage::FileSystemContext::RESOLVED_ENTRY_DIRECTORY));
- } else {
- Send(new FileSystemMsg_DidFail(request_id, result));
- }
- // For ResolveURL we do not create a new operation, so no unregister here.
-}
-
-void FileAPIMessageFilter::DidCreateSnapshot(
- int request_id,
- const storage::FileSystemURL& url,
- base::File::Error result,
- const base::File::Info& info,
- const base::FilePath& platform_path,
- scoped_refptr<storage::ShareableFileReference> /* unused */) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- operations_.erase(request_id);
-
- if (result != base::File::FILE_OK) {
- Send(new FileSystemMsg_DidFail(request_id, result));
- return;
- }
-
- scoped_refptr<storage::ShareableFileReference> file_ref =
- storage::ShareableFileReference::Get(platform_path);
- if (!security_policy_->CanReadFile(process_id_, platform_path)) {
- // Give per-file read permission to the snapshot file if it hasn't it yet.
- // In order for the renderer to be able to read the file via File object,
- // it must be granted per-file read permission for the file's platform
- // path. By now, it has already been verified that the renderer has
- // sufficient permissions to read the file, so giving per-file permission
- // here must be safe.
- security_policy_->GrantReadFile(process_id_, platform_path);
-
- // Revoke all permissions for the file when the last ref of the file
- // is dropped.
- if (!file_ref.get()) {
- // Create a reference for temporary permission handling.
- file_ref = storage::ShareableFileReference::GetOrCreate(
- platform_path,
- storage::ShareableFileReference::DONT_DELETE_ON_FINAL_RELEASE,
- context_->default_file_task_runner());
- }
- file_ref->AddFinalReleaseCallback(
- base::BindOnce(&RevokeFilePermission, process_id_));
- }
-
- if (file_ref.get()) {
- // This ref is held until OnDidReceiveSnapshotFile is called.
- in_transit_snapshot_files_[request_id] = file_ref;
- }
-
- // Return the file info and platform_path.
- Send(new FileSystemMsg_DidCreateSnapshotFile(
- request_id, info, platform_path));
-}
-
-bool FileAPIMessageFilter::ValidateFileSystemURL(
- int request_id,
- const storage::FileSystemURL& url) {
- if (!FileSystemURLIsValid(context_, url)) {
- Send(new FileSystemMsg_DidFail(request_id,
- base::File::FILE_ERROR_INVALID_URL));
- return false;
- }
-
- // Deny access to files in PluginPrivate FileSystem from JavaScript.
- // TODO(nhiroki): Move this filter somewhere else since this is not for
- // validation.
- if (url.type() == storage::kFileSystemTypePluginPrivate) {
- Send(new FileSystemMsg_DidFail(request_id,
- base::File::FILE_ERROR_SECURITY));
- return false;
- }
-
- return true;
-}
-
-} // namespace content
diff --git a/chromium/content/browser/fileapi/fileapi_message_filter.h b/chromium/content/browser/fileapi/fileapi_message_filter.h
deleted file mode 100644
index 7188c686f4d..00000000000
--- a/chromium/content/browser/fileapi/fileapi_message_filter.h
+++ /dev/null
@@ -1,194 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_FILEAPI_FILEAPI_MESSAGE_FILTER_H_
-#define CONTENT_BROWSER_FILEAPI_FILEAPI_MESSAGE_FILTER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/containers/hash_tables.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/shared_memory.h"
-#include "components/services/filesystem/public/interfaces/types.mojom.h"
-#include "content/browser/streams/stream.h"
-#include "content/browser/streams/stream_context.h"
-#include "content/common/content_export.h"
-#include "content/public/browser/browser_message_filter.h"
-#include "storage/browser/fileapi/file_system_context.h"
-#include "storage/browser/fileapi/file_system_operation_runner.h"
-#include "storage/common/fileapi/file_system_types.h"
-
-class GURL;
-
-namespace base {
-class FilePath;
-class Time;
-}
-
-namespace storage {
-class FileSystemURL;
-class FileSystemOperationRunner;
-struct FileSystemInfo;
-}
-
-namespace net {
-class URLRequestContext;
-class URLRequestContextGetter;
-} // namespace net
-
-namespace storage {
-class ShareableFileReference;
-}
-
-namespace content {
-class ChildProcessSecurityPolicyImpl;
-class ChromeBlobStorageContext;
-
-// TODO(tyoshino): Factor out code except for IPC gluing from
-// FileAPIMessageFilter into separate classes. See crbug.com/263741.
-class CONTENT_EXPORT FileAPIMessageFilter : public BrowserMessageFilter {
- public:
- // Used by the renderer process host on the UI thread.
- FileAPIMessageFilter(int process_id,
- net::URLRequestContextGetter* request_context_getter,
- storage::FileSystemContext* file_system_context,
- ChromeBlobStorageContext* blob_storage_context);
- // Used by the worker process host on the IO thread.
- FileAPIMessageFilter(int process_id,
- net::URLRequestContext* request_context,
- storage::FileSystemContext* file_system_context,
- ChromeBlobStorageContext* blob_storage_context);
-
- // BrowserMessageFilter implementation.
- void OnChannelConnected(int32_t peer_pid) override;
- void OnChannelClosing() override;
- base::TaskRunner* OverrideTaskRunnerForMessage(
- const IPC::Message& message) override;
- bool OnMessageReceived(const IPC::Message& message) override;
-
- protected:
- ~FileAPIMessageFilter() override;
-
- private:
- typedef storage::FileSystemOperationRunner::OperationID OperationID;
-
- void OnOpenFileSystem(int request_id,
- const GURL& origin_url,
- storage::FileSystemType type);
- void OnResolveURL(int request_id,
- const GURL& filesystem_url);
- void OnMove(int request_id,
- const GURL& src_path,
- const GURL& dest_path);
- void OnCopy(int request_id,
- const GURL& src_path,
- const GURL& dest_path);
- void OnRemove(int request_id, const GURL& path, bool recursive);
- void OnReadMetadata(int request_id, const GURL& path);
- void OnCreate(int request_id,
- const GURL& path,
- bool exclusive,
- bool is_directory,
- bool recursive);
- void OnExists(int request_id, const GURL& path, bool is_directory);
- void OnReadDirectory(int request_id, const GURL& path);
- void OnWrite(int request_id,
- const GURL& path,
- const std::string& blob_uuid,
- int64_t offset);
- void OnTruncate(int request_id, const GURL& path, int64_t length);
- void OnTouchFile(int request_id,
- const GURL& path,
- const base::Time& last_access_time,
- const base::Time& last_modified_time);
- void OnCancel(int request_id, int request_to_cancel);
- void OnSyncGetPlatformPath(const GURL& path,
- base::FilePath* platform_path);
- void OnCreateSnapshotFile(int request_id,
- const GURL& path);
- void OnDidReceiveSnapshotFile(int request_id);
-
- // Callback functions to be used when each file operation is finished.
- void DidFinish(int request_id, base::File::Error result);
- void DidGetMetadata(int request_id,
- base::File::Error result,
- const base::File::Info& info);
- void DidGetMetadataForStreaming(int request_id,
- base::File::Error result,
- const base::File::Info& info);
- void DidReadDirectory(int request_id,
- base::File::Error result,
- std::vector<filesystem::mojom::DirectoryEntry> entries,
- bool has_more);
- void DidWrite(int request_id,
- base::File::Error result,
- int64_t bytes,
- bool complete);
- void DidOpenFileSystem(int request_id,
- const GURL& root,
- const std::string& filesystem_name,
- base::File::Error result);
- void DidResolveURL(int request_id,
- base::File::Error result,
- const storage::FileSystemInfo& info,
- const base::FilePath& file_path,
- storage::FileSystemContext::ResolvedEntryType type);
- void DidCreateSnapshot(
- int request_id,
- const storage::FileSystemURL& url,
- base::File::Error result,
- const base::File::Info& info,
- const base::FilePath& platform_path,
- scoped_refptr<storage::ShareableFileReference> file_ref);
-
- // Sends a FileSystemMsg_DidFail and returns false if |url| is invalid.
- bool ValidateFileSystemURL(int request_id, const storage::FileSystemURL& url);
-
- storage::FileSystemOperationRunner* operation_runner() {
- return operation_runner_.get();
- }
-
- int process_id_;
-
- storage::FileSystemContext* context_;
- ChildProcessSecurityPolicyImpl* security_policy_;
-
- // Keeps map from request_id to OperationID for ongoing operations.
- // (Primarily for Cancel operation)
- typedef std::map<int, OperationID> OperationsMap;
- OperationsMap operations_;
-
- // The getter holds the context until OnChannelConnected() can be called from
- // the IO thread, which will extract the net::URLRequestContext from it.
- scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
- net::URLRequestContext* request_context_;
-
- scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
-
- std::unique_ptr<storage::FileSystemOperationRunner> operation_runner_;
-
- // Keep track of stream URLs registered in this process. Need to unregister
- // all of them when the renderer process dies.
- base::hash_set<std::string> stream_urls_;
-
- // Used to keep snapshot files alive while a DidCreateSnapshot
- // is being sent to the renderer.
- std::map<int, scoped_refptr<storage::ShareableFileReference> >
- in_transit_snapshot_files_;
-
- DISALLOW_COPY_AND_ASSIGN(FileAPIMessageFilter);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_FILEAPI_FILEAPI_MESSAGE_FILTER_H_
diff --git a/chromium/content/browser/fileapi/fileapi_message_filter_unittest.cc b/chromium/content/browser/fileapi/fileapi_message_filter_unittest.cc
deleted file mode 100644
index c996e7c34e2..00000000000
--- a/chromium/content/browser/fileapi/fileapi_message_filter_unittest.cc
+++ /dev/null
@@ -1,129 +0,0 @@
-// 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 "content/browser/fileapi/fileapi_message_filter.h"
-
-#include <stddef.h>
-
-#include <string>
-#include <vector>
-
-#include "base/memory/ref_counted.h"
-#include "base/memory/shared_memory.h"
-#include "base/process/process_handle.h"
-#include "base/run_loop.h"
-#include "content/browser/blob_storage/chrome_blob_storage_context.h"
-#include "content/browser/child_process_security_policy_impl.h"
-#include "content/common/fileapi/file_system_messages.h"
-#include "content/common/fileapi/webblob_messages.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/storage_partition.h"
-#include "content/public/common/common_param_traits.h"
-#include "content/public/test/mock_render_process_host.h"
-#include "content/public/test/test_browser_context.h"
-#include "content/public/test/test_browser_thread.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "net/base/io_buffer.h"
-#include "storage/browser/blob/blob_storage_context.h"
-#include "storage/browser/fileapi/file_system_context.h"
-#include "storage/browser/test/test_file_system_context.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-
-class FileAPIMessageFilterTest : public testing::Test {
- public:
- FileAPIMessageFilterTest()
- : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {
- }
-
- protected:
- void SetUp() override {
- file_system_context_ =
- CreateFileSystemContextForTesting(nullptr, base::FilePath());
-
- for (const storage::FileSystemType& type :
- file_system_context_->GetFileSystemTypes()) {
- ChildProcessSecurityPolicyImpl::GetInstance()
- ->RegisterFileSystemPermissionPolicy(
- type, storage::FileSystemContext::GetPermissionPolicy(type));
- }
-
- blob_storage_context_ = ChromeBlobStorageContext::GetFor(&browser_context_);
-
- filter_ = new FileAPIMessageFilter(
- 0 /* process_id */,
- BrowserContext::GetDefaultStoragePartition(&browser_context_)
- ->GetURLRequestContext(),
- file_system_context_.get(), blob_storage_context_);
-
- // Complete initialization.
- base::RunLoop().RunUntilIdle();
- }
-
- TestBrowserThreadBundle browser_thread_bundle_;
- TestBrowserContext browser_context_;
- scoped_refptr<storage::FileSystemContext> file_system_context_;
- ChromeBlobStorageContext* blob_storage_context_;
-
- scoped_refptr<FileAPIMessageFilter> filter_;
-};
-
-TEST_F(FileAPIMessageFilterTest, CloseChannelWithInflightRequest) {
- scoped_refptr<FileAPIMessageFilter> filter(new FileAPIMessageFilter(
- 0 /* process_id */,
- BrowserContext::GetDefaultStoragePartition(&browser_context_)
- ->GetURLRequestContext(),
- file_system_context_.get(),
- ChromeBlobStorageContext::GetFor(&browser_context_)));
- filter->OnChannelConnected(0);
-
- // Complete initialization.
- base::RunLoop().RunUntilIdle();
-
- int request_id = 0;
- const GURL kUrl("filesystem:http://example.com/temporary/foo");
- FileSystemHostMsg_ReadMetadata read_metadata(request_id++, kUrl);
- EXPECT_TRUE(filter->OnMessageReceived(read_metadata));
-
- // Close the filter while it has inflight request.
- filter->OnChannelClosing();
-
- // This shouldn't cause DCHECK failure.
- base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(FileAPIMessageFilterTest, MultipleFilters) {
- scoped_refptr<FileAPIMessageFilter> filter1(new FileAPIMessageFilter(
- 0 /* process_id */,
- BrowserContext::GetDefaultStoragePartition(&browser_context_)
- ->GetURLRequestContext(),
- file_system_context_.get(),
- ChromeBlobStorageContext::GetFor(&browser_context_)));
- scoped_refptr<FileAPIMessageFilter> filter2(new FileAPIMessageFilter(
- 1 /* process_id */,
- BrowserContext::GetDefaultStoragePartition(&browser_context_)
- ->GetURLRequestContext(),
- file_system_context_.get(),
- ChromeBlobStorageContext::GetFor(&browser_context_)));
- filter1->OnChannelConnected(0);
- filter2->OnChannelConnected(1);
-
- // Complete initialization.
- base::RunLoop().RunUntilIdle();
-
- int request_id = 0;
- const GURL kUrl("filesystem:http://example.com/temporary/foo");
- FileSystemHostMsg_ReadMetadata read_metadata(request_id++, kUrl);
- EXPECT_TRUE(filter1->OnMessageReceived(read_metadata));
-
- // Close the other filter before the request for filter1 is processed.
- filter2->OnChannelClosing();
-
- // This shouldn't cause DCHECK failure.
- base::RunLoop().RunUntilIdle();
-}
-
-} // namespace content
diff --git a/chromium/content/browser/find_in_page_client.cc b/chromium/content/browser/find_in_page_client.cc
new file mode 100644
index 00000000000..7812fe0c923
--- /dev/null
+++ b/chromium/content/browser/find_in_page_client.cc
@@ -0,0 +1,67 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/find_in_page_client.h"
+
+#include "content/browser/find_request_manager.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
+
+namespace content {
+
+FindInPageClient::FindInPageClient(FindRequestManager* find_request_manager,
+ RenderFrameHostImpl* rfh)
+ : frame_(rfh), find_request_manager_(find_request_manager), binding_(this) {
+ blink::mojom::FindInPageClientPtr client;
+ binding_.Bind(MakeRequest(&client));
+ frame_->GetFindInPage()->SetClient(std::move(client));
+}
+
+FindInPageClient::~FindInPageClient() {}
+
+void FindInPageClient::SetNumberOfMatches(
+ int request_id,
+ unsigned int number_of_matches,
+ blink::mojom::FindMatchUpdateType update_type) {
+ if (find_request_manager_->ShouldIgnoreReply(frame_, request_id))
+ return;
+ const int old_matches = number_of_matches_;
+ number_of_matches_ = number_of_matches;
+ find_request_manager_->UpdatedFrameNumberOfMatches(frame_, old_matches,
+ number_of_matches);
+ HandleUpdateType(request_id, update_type);
+}
+
+void FindInPageClient::SetActiveMatch(
+ int request_id,
+ const gfx::Rect& active_match_rect,
+ int active_match_ordinal,
+ blink::mojom::FindMatchUpdateType update_type) {
+ if (find_request_manager_->ShouldIgnoreReply(frame_, request_id))
+ return;
+ find_request_manager_->SetActiveMatchRect(active_match_rect);
+ find_request_manager_->SetActiveMatchOrdinal(frame_, request_id,
+ active_match_ordinal);
+ HandleUpdateType(request_id, update_type);
+}
+
+void FindInPageClient::ActivateNearestFindResult(int request_id,
+ const gfx::PointF& point) {
+ frame_->GetFindInPage()->ActivateNearestFindResult(request_id, point);
+}
+
+void FindInPageClient::HandleUpdateType(
+ int request_id,
+ blink::mojom::FindMatchUpdateType update_type) {
+ // If this is the final update for this frame, it might be the final update
+ // for the find request out of all the frames, so we need to handle it.
+ // Otherwise just notify directly while saying this is not the final update
+ // for the request.
+ if (update_type == blink::mojom::FindMatchUpdateType::kFinalUpdate)
+ find_request_manager_->HandleFinalUpdateForFrame(frame_, request_id);
+ else
+ find_request_manager_->NotifyFindReply(request_id,
+ false /* final_update */);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/find_in_page_client.h b/chromium/content/browser/find_in_page_client.h
new file mode 100644
index 00000000000..083e457cf6a
--- /dev/null
+++ b/chromium/content/browser/find_in_page_client.h
@@ -0,0 +1,54 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_FIND_IN_PAGE_CLIENT_H_
+#define CONTENT_BROWSER_FIND_IN_PAGE_CLIENT_H_
+
+#include "mojo/public/cpp/bindings/binding.h"
+#include "third_party/blink/public/mojom/frame/find_in_page.mojom.h"
+
+namespace content {
+
+class RenderFrameHostImpl;
+class FindRequestManager;
+
+// Per-frame client of FindInPage, owned by FindRequestManager.
+// Keeps track of the current match count for the frame.
+class FindInPageClient final : public blink::mojom::FindInPageClient {
+ public:
+ FindInPageClient(FindRequestManager* find_request_manager,
+ RenderFrameHostImpl* rfh);
+
+ ~FindInPageClient() override;
+
+ void ActivateNearestFindResult(int request_id, const gfx::PointF& point);
+
+ // Current number of matches for this frame.
+ int number_of_matches() { return number_of_matches_; }
+
+ // blink::mojom::FindInPageClient overrides
+
+ void SetNumberOfMatches(int request_id,
+ unsigned int current_number_of_matches,
+ blink::mojom::FindMatchUpdateType update_type) final;
+
+ void SetActiveMatch(int request_id,
+ const gfx::Rect& active_match_rect,
+ int active_match_ordinal,
+ blink::mojom::FindMatchUpdateType update_type) final;
+
+ private:
+ void HandleUpdateType(int request_id,
+ blink::mojom::FindMatchUpdateType update_type);
+ RenderFrameHostImpl* const frame_;
+ FindRequestManager* const find_request_manager_;
+ mojo::Binding<blink::mojom::FindInPageClient> binding_;
+ int number_of_matches_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(FindInPageClient);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_FIND_IN_PAGE_CLIENT_H_
diff --git a/chromium/content/browser/find_request_manager.cc b/chromium/content/browser/find_request_manager.cc
index 34c5307b0fa..9ae22e14473 100644
--- a/chromium/content/browser/find_request_manager.cc
+++ b/chromium/content/browser/find_request_manager.cc
@@ -7,9 +7,9 @@
#include <algorithm>
#include "base/containers/queue.h"
+#include "content/browser/find_in_page_client.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/common/associated_interface_provider_impl.h"
#include "content/common/frame_messages.h"
#include "content/public/browser/guest_mode.h"
#include "third_party/blink/public/mojom/frame/find_in_page.mojom.h"
@@ -288,86 +288,23 @@ void FindRequestManager::StopFinding(StopFindAction action) {
#endif
}
-void FindRequestManager::OnFindReply(RenderFrameHostImpl* rfh,
- int request_id,
- int number_of_matches,
- const gfx::Rect& selection_rect,
- int active_match_ordinal,
- bool final_update) {
+bool FindRequestManager::ShouldIgnoreReply(RenderFrameHostImpl* rfh,
+ int request_id) {
// Ignore stale replies from abandoned find sessions or dead frames.
- if (current_session_id_ == kInvalidId ||
- request_id < current_session_id_ ||
- !CheckFrame(rfh)) {
- return;
- }
-
- // Update the stored find results.
-
- DCHECK_GE(number_of_matches, -1);
- DCHECK_GE(active_match_ordinal, -1);
-
- // Check for an update to the number of matches.
- if (number_of_matches != -1) {
- DCHECK_GE(number_of_matches, 0);
- auto matches_per_frame_it = matches_per_frame_.find(rfh);
- if (int matches_delta = number_of_matches - matches_per_frame_it->second) {
- // Increment the global number of matches by the number of additional
- // matches found for this frame.
- number_of_matches_ += matches_delta;
- matches_per_frame_it->second = number_of_matches;
-
- // All matches may have been removed since the last find reply.
- if (rfh == active_frame_ && !number_of_matches)
- relative_active_match_ordinal_ = 0;
-
- // The active match ordinal may need updating since the number of matches
- // before the active match may have changed.
- if (rfh != active_frame_ || !number_of_matches)
- UpdateActiveMatchOrdinal();
- }
- }
-
- // Check for an update to the selection rect.
- if (!selection_rect.IsEmpty())
- selection_rect_ = selection_rect;
-
- // Check for an update to the active match ordinal.
- if (active_match_ordinal > 0) {
- if (rfh == active_frame_) {
- active_match_ordinal_ +=
- active_match_ordinal - relative_active_match_ordinal_;
- relative_active_match_ordinal_ = active_match_ordinal;
- } else {
- if (active_frame_) {
- // The new active match is in a different frame than the previous, so
- // the previous active frame needs to be informed (to clear its active
- // match highlighting).
- ClearActiveFindMatch();
- }
- active_frame_ = rfh;
- relative_active_match_ordinal_ = active_match_ordinal;
- UpdateActiveMatchOrdinal();
- }
- if (pending_active_match_ordinal_ && request_id == current_request_.id)
- pending_active_match_ordinal_ = false;
- AdvanceQueue(request_id);
- }
-
- if (!final_update) {
- NotifyFindReply(request_id, false /* final_update */);
- return;
- }
+ return current_session_id_ == kInvalidId ||
+ request_id < current_session_id_ || !CheckFrame(rfh);
+}
+void FindRequestManager::HandleFinalUpdateForFrame(RenderFrameHostImpl* rfh,
+ int request_id) {
// This is the final update for this frame for the current find operation.
-
pending_initial_replies_.erase(rfh);
if (request_id == current_session_id_ && !pending_initial_replies_.empty()) {
NotifyFindReply(request_id, false /* final_update */);
return;
}
- // This is the final update for the current find operation.
-
+ // This is the final update for all frames for the current find operation.
if (request_id == current_request_.id && request_id != current_session_id_) {
DCHECK(current_request_.options.find_next);
DCHECK_EQ(pending_find_next_reply_, rfh);
@@ -377,17 +314,61 @@ void FindRequestManager::OnFindReply(RenderFrameHostImpl* rfh,
FinalUpdateReceived(request_id, rfh);
}
-void FindRequestManager::OnActivateNearestFindResultReply(
- RenderFrameHostImpl* rfh,
- int request_id,
- const gfx::Rect& active_match_rect,
- int number_of_matches,
- int active_match_ordinal,
- bool final_update) {
- if (active_match_ordinal > 0)
- contents_->SetFocusedFrame(rfh->frame_tree_node(), rfh->GetSiteInstance());
- OnFindReply(rfh, request_id, number_of_matches, active_match_rect,
- active_match_ordinal, final_update);
+void FindRequestManager::UpdatedFrameNumberOfMatches(RenderFrameHostImpl* rfh,
+ unsigned int old_count,
+ unsigned int new_count) {
+ if (old_count == new_count)
+ return;
+
+ // Change the number of matches for this frame in the global count.
+ number_of_matches_ -= old_count;
+ number_of_matches_ += new_count;
+
+ // All matches may have been removed since the last find reply.
+ if (rfh == active_frame_ && !new_count)
+ relative_active_match_ordinal_ = 0;
+
+ // The active match ordinal may need updating since the number of matches
+ // before the active match may have changed.
+ UpdateActiveMatchOrdinal();
+}
+
+void FindRequestManager::SetActiveMatchRect(
+ const gfx::Rect& active_match_rect) {
+ selection_rect_ = active_match_rect;
+}
+
+void FindRequestManager::SetActiveMatchOrdinal(RenderFrameHostImpl* rfh,
+ int request_id,
+ int active_match_ordinal) {
+ if (active_match_ordinal > 0) {
+ // Call SetFocusedFrame on the WebContents associated with |rfh| (which
+ // might not be the same as |contents_|, as a WebContents might have
+ // inner WebContents). We need to focus on the frame where the active
+ // match is in, which should be in the |rfh|'s associated WebContents.
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(WebContents::FromRenderFrameHost(rfh));
+ web_contents->SetFocusedFrame(rfh->frame_tree_node(),
+ rfh->GetSiteInstance());
+ }
+ if (rfh == active_frame_) {
+ active_match_ordinal_ +=
+ active_match_ordinal - relative_active_match_ordinal_;
+ relative_active_match_ordinal_ = active_match_ordinal;
+ } else {
+ if (active_frame_) {
+ // The new active match is in a different frame than the previous, so
+ // the previous active frame needs to be informed (to clear its active
+ // match highlighting).
+ ClearActiveFindMatch();
+ }
+ active_frame_ = rfh;
+ relative_active_match_ordinal_ = active_match_ordinal;
+ UpdateActiveMatchOrdinal();
+ }
+ if (pending_active_match_ordinal_ && request_id == current_request_.id)
+ pending_active_match_ordinal_ = false;
+ AdvanceQueue(request_id);
}
void FindRequestManager::RemoveFrame(RenderFrameHost* rfh) {
@@ -396,10 +377,10 @@ void FindRequestManager::RemoveFrame(RenderFrameHost* rfh) {
// If matches are counted for the frame that is being removed, decrement the
// match total before erasing that entry.
- auto it = matches_per_frame_.find(rfh);
- if (it != matches_per_frame_.end()) {
- number_of_matches_ -= it->second;
- matches_per_frame_.erase(it);
+ auto it = find_in_page_clients_.find(rfh);
+ if (it != find_in_page_clients_.end()) {
+ number_of_matches_ -= it->second->number_of_matches();
+ find_in_page_clients_.erase(it);
}
// Update the active match ordinal, since it may have changed.
@@ -547,7 +528,7 @@ void FindRequestManager::Reset(const FindRequest& initial_request) {
pending_initial_replies_.clear();
pending_find_next_reply_ = nullptr;
pending_active_match_ordinal_ = true;
- matches_per_frame_.clear();
+ find_in_page_clients_.clear();
number_of_matches_ = 0;
active_frame_ = nullptr;
relative_active_match_ordinal_ = 0;
@@ -580,7 +561,7 @@ void FindRequestManager::FindInternal(const FindRequest& request) {
if (!target_rfh || !CheckFrame(target_rfh))
target_rfh = GetInitialFrame(request.options.forward);
- SendFindIPC(request, target_rfh);
+ SendFindRequest(request, target_rfh);
current_request_ = request;
pending_active_match_ordinal_ = true;
return;
@@ -607,8 +588,8 @@ void FindRequestManager::AdvanceQueue(int request_id) {
FindInternal(find_request_queue_.front());
}
-void FindRequestManager::SendFindIPC(const FindRequest& request,
- RenderFrameHost* rfh) {
+void FindRequestManager::SendFindRequest(const FindRequest& request,
+ RenderFrameHost* rfh) {
DCHECK(CheckFrame(rfh));
DCHECK(rfh->IsRenderFrameLive());
@@ -617,8 +598,15 @@ void FindRequestManager::SendFindIPC(const FindRequest& request,
else
pending_initial_replies_.insert(rfh);
- rfh->Send(new FrameMsg_Find(rfh->GetRoutingID(), request.id,
- request.search_text, request.options));
+ blink::mojom::FindOptionsPtr options(blink::mojom::FindOptions::New());
+ options->forward = request.options.forward;
+ options->match_case = request.options.match_case;
+ options->find_next = request.options.find_next;
+ options->force = request.options.force;
+ options->run_synchronously_for_testing =
+ request.options.run_synchronously_for_testing;
+ static_cast<RenderFrameHostImpl*>(rfh)->GetFindInPage()->Find(
+ request.id, base::UTF16ToUTF8(request.search_text), std::move(options));
}
void FindRequestManager::NotifyFindReply(int request_id, bool final_update) {
@@ -659,7 +647,8 @@ RenderFrameHost* FindRequestManager::Traverse(RenderFrameHost* from_rfh,
if (!CheckFrame(node->current_frame_host()))
continue;
RenderFrameHost* current_rfh = node->current_frame_host();
- if (!matches_only || matches_per_frame_.find(current_rfh)->second ||
+ if (!matches_only ||
+ find_in_page_clients_.find(current_rfh)->second->number_of_matches() ||
pending_initial_replies_.count(current_rfh)) {
// Note that if there is still a pending reply expected for this frame,
// then it may have unaccounted matches and will not be skipped via
@@ -680,17 +669,18 @@ void FindRequestManager::AddFrame(RenderFrameHost* rfh, bool force) {
// A frame that is already being searched should not normally be added again.
DCHECK(force || !CheckFrame(rfh));
- matches_per_frame_[rfh] = 0;
+ find_in_page_clients_[rfh] = std::make_unique<FindInPageClient>(
+ this, static_cast<RenderFrameHostImpl*>(rfh));
FindRequest request = current_request_;
request.id = current_session_id_;
request.options.find_next = false;
request.options.force = force;
- SendFindIPC(request, rfh);
+ SendFindRequest(request, rfh);
}
bool FindRequestManager::CheckFrame(RenderFrameHost* rfh) const {
- return rfh && matches_per_frame_.count(rfh);
+ return rfh && find_in_page_clients_.count(rfh);
}
void FindRequestManager::UpdateActiveMatchOrdinal() {
@@ -709,7 +699,7 @@ void FindRequestManager::UpdateActiveMatchOrdinal() {
false /* forward */,
true /* matches_only */,
false /* wrap */)) != nullptr) {
- active_match_ordinal_ += matches_per_frame_[frame];
+ active_match_ordinal_ += find_in_page_clients_[frame]->number_of_matches();
}
active_match_ordinal_ += relative_active_match_ordinal_;
}
@@ -751,7 +741,8 @@ void FindRequestManager::FinalUpdateReceived(int request_id,
} else {
// Otherwise, the first frame with matches will have the active match.
target_rfh = GetInitialFrame(current_request_.options.forward);
- if (!CheckFrame(target_rfh) || !matches_per_frame_[target_rfh]) {
+ if (!CheckFrame(target_rfh) ||
+ !find_in_page_clients_[target_rfh]->number_of_matches()) {
target_rfh = Traverse(target_rfh,
current_request_.options.forward,
true /* matches_only */,
@@ -765,7 +756,7 @@ void FindRequestManager::FinalUpdateReceived(int request_id,
NotifyFindReply(request_id, false /* final_update */);
current_request_.options.find_next = true;
- SendFindIPC(current_request_, target_rfh);
+ SendFindRequest(current_request_, target_rfh);
}
#if defined(OS_ANDROID)
@@ -778,14 +769,10 @@ void FindRequestManager::RemoveNearestFindResultPendingReply(
activate_.pending_replies.erase(it);
if (activate_.pending_replies.empty() &&
CheckFrame(activate_.nearest_frame)) {
- // Lifetime of FindRequestManager > activate_.nearest_frame > Mojo
- // connection, so it's safe to bind |this| and |activate_.nearest_frame|
- activate_.nearest_frame->GetFindInPage()->ActivateNearestFindResult(
- activate_.point,
- base::BindOnce(&FindRequestManager::OnActivateNearestFindResultReply,
- base::Unretained(this),
- base::Unretained(activate_.nearest_frame),
- current_session_id_));
+ const auto client_it = find_in_page_clients_.find(activate_.nearest_frame);
+ if (client_it != find_in_page_clients_.end())
+ client_it->second->ActivateNearestFindResult(current_session_id_,
+ activate_.point);
}
}
diff --git a/chromium/content/browser/find_request_manager.h b/chromium/content/browser/find_request_manager.h
index ae95c1325af..62050f4611a 100644
--- a/chromium/content/browser/find_request_manager.h
+++ b/chromium/content/browser/find_request_manager.h
@@ -20,6 +20,7 @@
namespace content {
+class FindInPageClient;
class RenderFrameHost;
class RenderFrameHostImpl;
class WebContentsImpl;
@@ -46,22 +47,29 @@ class CONTENT_EXPORT FindRequestManager {
// activated, cleared, or remain highlighted.
void StopFinding(StopFindAction action);
- // Called when a reply is received from a frame with the results from a
- // find request.
- void OnFindReply(RenderFrameHostImpl* rfh,
- int request_id,
- int number_of_matches,
- const gfx::Rect& selection_rect,
- int active_match_ordinal,
- bool final_update);
-
- // Called when a reply for ActivateNearestFindResult is received.
- void OnActivateNearestFindResultReply(RenderFrameHostImpl* rfh,
- int request_id,
- const gfx::Rect& active_match_rect,
- int number_of_matches,
- int active_match_ordinal,
- bool final_update);
+ // Handles the final update from |rfh| for the find request with id
+ // |request_id|.
+ void HandleFinalUpdateForFrame(RenderFrameHostImpl* rfh, int request_id);
+
+ // The number of matches on |rfh| has changed from |old_count| to |new_count|.
+ // This method updates the total number of matches and also updates
+ // |active_match_ordinal_| accordingly.
+ void UpdatedFrameNumberOfMatches(RenderFrameHostImpl* rfh,
+ unsigned int old_count,
+ unsigned int new_count);
+
+ bool ShouldIgnoreReply(RenderFrameHostImpl* rfh, int request_id);
+
+ void SetActiveMatchRect(const gfx::Rect& active_match_rect);
+
+ void SetActiveMatchOrdinal(RenderFrameHostImpl* rfh,
+ int request_id,
+ int active_match_ordinal);
+
+ // Sends the find results (as they currently are) to the WebContents.
+ // |final_update| is true if we have received all of the updates from
+ // every frame for this request.
+ void NotifyFindReply(int request_id, bool final_update);
// Removes a frame from the set of frames being searched. This should be
// called whenever a frame is discovered to no longer exist.
@@ -128,12 +136,9 @@ class CONTENT_EXPORT FindRequestManager {
// with ID |request_id|. Advances the |find_request_queue_| if appropriate.
void AdvanceQueue(int request_id);
- // Sends a find IPC containing the find request |request| to the RenderFrame
- // associated with |rfh|.
- void SendFindIPC(const FindRequest& request, RenderFrameHost* rfh);
-
- // Sends the find results (as they currently are) to the WebContents.
- void NotifyFindReply(int request_id, bool final_update);
+ // Sends find request |request| through mojo to the RenderFrame associated
+ // with |rfh|.
+ void SendFindRequest(const FindRequest& request, RenderFrameHost* rfh);
// Returns the initial frame in search order. This will be either the first
// frame, if searching forward, or the last frame, if searching backward.
@@ -283,10 +288,11 @@ class CONTENT_EXPORT FindRequestManager {
// |current_request_.id| (the latest request).
bool pending_active_match_ordinal_;
- // The number of matches found in each frame. There will necessarily be
+ // The FindInPageClient associated with each frame. There will necessarily be
// entries in this map for every frame that is being (or has been) searched in
// the current find session, and no other frames.
- std::unordered_map<RenderFrameHost*, int> matches_per_frame_;
+ std::unordered_map<RenderFrameHost*, std::unique_ptr<FindInPageClient>>
+ find_in_page_clients_;
// The total number of matches found in the current find-in-page session. This
// should always be equal to the sum of all the entries in
diff --git a/chromium/content/browser/find_request_manager_browsertest.cc b/chromium/content/browser/find_request_manager_browsertest.cc
index f0d21d59c56..0217e5ac7d0 100644
--- a/chromium/content/browser/find_request_manager_browsertest.cc
+++ b/chromium/content/browser/find_request_manager_browsertest.cc
@@ -168,6 +168,7 @@ IN_PROC_BROWSER_TEST_P(FindRequestManagerTest, MAYBE(Basic)) {
MakeChildFrameCrossProcess();
blink::WebFindOptions options;
+ options.run_synchronously_for_testing = true;
Find("result", options);
delegate()->WaitForFinalReply();
@@ -251,6 +252,7 @@ IN_PROC_BROWSER_TEST_P(FindRequestManagerTest, ScrollAndZoomIntoView) {
// Search for a result further down in the iframe.
blink::WebFindOptions options;
+ options.run_synchronously_for_testing = true;
Find("result 17", options);
delegate()->WaitForFinalReply();
@@ -312,6 +314,7 @@ IN_PROC_BROWSER_TEST_P(FindRequestManagerTest, MAYBE(CharacterByCharacter)) {
MakeChildFrameCrossProcess();
blink::WebFindOptions default_options;
+ default_options.run_synchronously_for_testing = true;
Find("r", default_options);
Find("re", default_options);
Find("res", default_options);
@@ -336,6 +339,7 @@ IN_PROC_BROWSER_TEST_P(FindRequestManagerTest, DISABLED_RapidFire) {
MakeChildFrameCrossProcess();
blink::WebFindOptions options;
+ options.run_synchronously_for_testing = true;
Find("result", options);
options.find_next = true;
@@ -356,6 +360,7 @@ IN_PROC_BROWSER_TEST_P(FindRequestManagerTest, DISABLED_RemoveFrame) {
LoadMultiFramePage(2 /* height */, GetParam() /* cross_process */);
blink::WebFindOptions options;
+ options.run_synchronously_for_testing = true;
Find("result", options);
delegate()->WaitForFinalReply();
options.find_next = true;
@@ -389,6 +394,7 @@ IN_PROC_BROWSER_TEST_P(FindRequestManagerTest, DISABLED_AddFrame) {
LoadMultiFramePage(2 /* height */, GetParam() /* cross_process */);
blink::WebFindOptions options;
+ options.run_synchronously_for_testing = true;
Find("result", options);
options.find_next = true;
Find("result", options);
@@ -428,6 +434,7 @@ IN_PROC_BROWSER_TEST_F(FindRequestManagerTest, MAYBE(AddFrameAfterNoMatches)) {
EXPECT_TRUE(navigation_observer.last_navigation_succeeded());
blink::WebFindOptions default_options;
+ default_options.run_synchronously_for_testing = true;
Find("result", default_options);
delegate()->WaitForFinalReply();
@@ -460,6 +467,7 @@ IN_PROC_BROWSER_TEST_P(FindRequestManagerTest, MAYBE(NavigateFrame)) {
LoadMultiFramePage(2 /* height */, GetParam() /* cross_process */);
blink::WebFindOptions options;
+ options.run_synchronously_for_testing = true;
Find("result", options);
options.find_next = true;
options.forward = false;
@@ -508,6 +516,7 @@ IN_PROC_BROWSER_TEST_F(FindRequestManagerTest, MAYBE(HiddenFrame)) {
LoadAndWait("/find_in_hidden_frame.html");
blink::WebFindOptions default_options;
+ default_options.run_synchronously_for_testing = true;
Find("hello", default_options);
delegate()->WaitForFinalReply();
FindResults results = delegate()->GetFindResults();
@@ -522,6 +531,7 @@ IN_PROC_BROWSER_TEST_P(FindRequestManagerTest, MAYBE(FindNewMatches)) {
LoadAndWait("/find_in_dynamic_page.html");
blink::WebFindOptions options;
+ options.run_synchronously_for_testing = true;
Find("result", options);
options.find_next = true;
Find("result", options);
@@ -548,7 +558,8 @@ IN_PROC_BROWSER_TEST_P(FindRequestManagerTest, MAYBE(FindNewMatches)) {
// TODO(crbug.com/615291): These tests frequently fail on Android.
// TODO(crbug.com/779912): Flaky timeout on Win7 (dbg).
-#if defined(OS_ANDROID) || (defined(OS_WIN) && !defined(NDEBUG))
+// TODO(crbug.com/875306): Flaky on Win10.
+#if defined(OS_ANDROID) || defined(OS_WIN)
#define MAYBE_FindInPage_Issue627799 DISABLED_FindInPage_Issue627799
#else
#define MAYBE_FindInPage_Issue627799 FindInPage_Issue627799
@@ -558,6 +569,7 @@ IN_PROC_BROWSER_TEST_F(FindRequestManagerTest, MAYBE_FindInPage_Issue627799) {
LoadAndWait("/find_in_long_page.html");
blink::WebFindOptions options;
+ options.run_synchronously_for_testing = true;
Find("42", options);
delegate()->WaitForFinalReply();
@@ -589,6 +601,7 @@ IN_PROC_BROWSER_TEST_F(FindRequestManagerTest, MAYBE(FindInPage_Issue644448)) {
EXPECT_TRUE(navigation_observer.last_navigation_succeeded());
blink::WebFindOptions default_options;
+ default_options.run_synchronously_for_testing = true;
Find("result", default_options);
delegate()->WaitForFinalReply();
@@ -617,6 +630,7 @@ IN_PROC_BROWSER_TEST_F(FindRequestManagerTest, MAYBE(FindMatchRects)) {
LoadAndWait("/find_in_page.html");
blink::WebFindOptions default_options;
+ default_options.run_synchronously_for_testing = true;
Find("result", default_options);
delegate()->WaitForFinalReply();
EXPECT_EQ(19, delegate()->GetFindResults().number_of_matches);
@@ -699,6 +713,7 @@ IN_PROC_BROWSER_TEST_F(FindRequestManagerTest,
LoadAndWait("/find_in_page.html");
blink::WebFindOptions default_options;
+ default_options.run_synchronously_for_testing = true;
Find("result", default_options);
delegate()->WaitForFinalReply();
EXPECT_EQ(19, delegate()->GetFindResults().number_of_matches);
diff --git a/chromium/content/browser/font_unique_name_lookup/OWNERS b/chromium/content/browser/font_unique_name_lookup/OWNERS
new file mode 100644
index 00000000000..58196726758
--- /dev/null
+++ b/chromium/content/browser/font_unique_name_lookup/OWNERS
@@ -0,0 +1,3 @@
+drott@chromium.org
+
+# COMPONENT: Blink>Fonts
diff --git a/chromium/content/browser/font_unique_name_lookup/font_unique_name_browsertest.cc b/chromium/content/browser/font_unique_name_lookup/font_unique_name_browsertest.cc
new file mode 100644
index 00000000000..4708110a0f7
--- /dev/null
+++ b/chromium/content/browser/font_unique_name_lookup/font_unique_name_browsertest.cc
@@ -0,0 +1,140 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/stl_util.h"
+#include "base/test/scoped_feature_list.h"
+#include "build/build_config.h"
+#include "content/browser/devtools/protocol/devtools_protocol_test_support.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/common/content_features.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/test_navigation_observer.h"
+#include "content/shell/browser/shell.h"
+
+namespace content {
+namespace {
+
+const char* kExpectedFontFamilyNames[] = {"AndroidClock",
+ "Roboto",
+ "Droid Sans Mono",
+ "Roboto",
+ "Noto Color Emoji",
+ "Noto Sans Bengali",
+ "Noto Sans Bengali",
+ "Noto Sans Bengali UI",
+ "Noto Sans Bengali UI",
+ "Noto Sans Devanagari",
+ "Noto Sans Devanagari",
+ "Noto Sans Devanagari UI",
+ "Noto Sans Devanagari UI",
+ "Noto Sans Kannada",
+ "Noto Sans Kannada",
+ "Noto Sans Kannada UI",
+ "Noto Sans Kannada UI",
+ "Noto Sans Lao",
+ "Noto Sans Lao",
+ "Noto Sans Lao UI",
+ "Noto Sans Lao UI",
+ "Noto Sans Malayalam",
+ "Noto Sans Malayalam",
+ "Noto Sans Malayalam UI",
+ "Noto Sans Malayalam UI",
+ "Noto Sans Tamil",
+ "Noto Sans Tamil",
+ "Noto Sans Tamil UI",
+ "Noto Sans Tamil UI",
+ "Noto Sans Telugu",
+ "Noto Sans Telugu",
+ "Noto Sans Telugu UI",
+ "Noto Sans Telugu UI",
+ "Noto Sans Thai",
+ "Noto Sans Thai",
+ "Noto Sans Thai UI",
+ "Noto Sans Thai UI",
+ "Roboto",
+ "Roboto Condensed",
+ "Roboto Condensed",
+ "Roboto Condensed",
+ "Roboto Condensed",
+ "Roboto"};
+
+} // namespace
+
+class FontUniqueNameBrowserTest : public DevToolsProtocolTest {
+ public:
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ feature_list_.InitAndEnableFeature(features::kFontSrcLocalMatching);
+ }
+
+ void LoadAndWait(const std::string& url) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ TestNavigationObserver navigation_observer(
+ static_cast<WebContentsImpl*>(shell()->web_contents()));
+ NavigateToURL(shell(), embedded_test_server()->GetURL("a.com", url));
+ ASSERT_TRUE(navigation_observer.last_navigation_succeeded());
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+};
+
+#if defined(OS_ANDROID)
+#define MAYBE_ContentLocalFontsMatching ContentLocalFontsMatching
+#else
+#define MAYBE_ContentLocalFontsMatching DISABLED_ContentLocalFontsMatching
+#endif
+IN_PROC_BROWSER_TEST_F(FontUniqueNameBrowserTest,
+ MAYBE_ContentLocalFontsMatching) {
+ LoadAndWait("/font_src_local_matching.html");
+ Attach();
+
+ base::Value* dom_enable_result = SendCommand("DOM.enable", nullptr, true);
+ ASSERT_TRUE(dom_enable_result);
+
+ base::Value* css_enable_result = SendCommand("CSS.enable", nullptr, true);
+ ASSERT_TRUE(css_enable_result);
+
+ unsigned num_added_nodes = static_cast<unsigned>(
+ content::EvalJs(shell(), "addTestNodes()").ExtractInt());
+ ASSERT_EQ(num_added_nodes, base::size(kExpectedFontFamilyNames));
+
+ std::unique_ptr<base::DictionaryValue> params =
+ std::make_unique<base::DictionaryValue>();
+ params->SetInteger("depth", 0);
+ base::Value* result = SendCommand("DOM.getDocument", std::move(params));
+ result = result->FindPath({"root", "nodeId"});
+ ASSERT_TRUE(result);
+ ASSERT_TRUE(result->is_int());
+
+ params.reset(new base::DictionaryValue());
+ params->SetInteger("nodeId", result->GetInt());
+ params->SetString("selector", ".testnode");
+ result = SendCommand("DOM.querySelectorAll", std::move(params));
+ // This needs a Clone() because node_list otherwise gets invalid after the
+ // next SendCommand call.
+ base::Value node_list =
+ result->FindKeyOfType("nodeIds", base::Value::Type::LIST)->Clone();
+ std::vector<base::Value>& nodes_vector = node_list.GetList();
+ ASSERT_EQ(nodes_vector.size(), num_added_nodes);
+ ASSERT_EQ(nodes_vector.size(), base::size(kExpectedFontFamilyNames));
+ for (size_t i = 0; i < nodes_vector.size(); ++i) {
+ base::Value& nodeId = nodes_vector[i];
+ params.reset(new base::DictionaryValue());
+ params->SetInteger("nodeId", nodeId.GetInt());
+ base::Value* font_info =
+ SendCommand("CSS.getPlatformFontsForNode", std::move(params));
+ ASSERT_TRUE(font_info->is_dict());
+ base::Value* font_list = font_info->FindKey("fonts");
+ ASSERT_TRUE(font_list->is_list());
+ base::Value& first_font_info = font_list->GetList()[0];
+ ASSERT_TRUE(first_font_info.is_dict());
+ base::Value* first_font_name = first_font_info.FindKey("familyName");
+ ASSERT_TRUE(first_font_name->is_string());
+ ASSERT_GT(first_font_name->GetString().size(), 0u);
+ ASSERT_EQ(first_font_name->GetString(), kExpectedFontFamilyNames[i]);
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/font_unique_name_lookup/font_unique_name_lookup.cc b/chromium/content/browser/font_unique_name_lookup/font_unique_name_lookup.cc
new file mode 100644
index 00000000000..5199a965cee
--- /dev/null
+++ b/chromium/content/browser/font_unique_name_lookup/font_unique_name_lookup.cc
@@ -0,0 +1,347 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/font_unique_name_lookup/font_unique_name_lookup.h"
+
+#include "base/android/build_info.h"
+#include "base/files/file.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/no_destructor.h"
+#include "base/path_service.h"
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/blink/public/common/font_unique_name_lookup/font_unique_name_table.pb.h"
+#include "third_party/blink/public/common/font_unique_name_lookup/icu_fold_case_util.h"
+
+#include <set>
+#include <vector>
+#include "third_party/icu/source/common/unicode/unistr.h"
+
+#include FT_TRUETYPE_IDS_H
+
+namespace {
+
+using namespace ::icu_62;
+
+const char kProtobufFilename[] = "font_unique_name_table.pb";
+static const char* const kAndroidFontPaths[] = {"/system/fonts",
+ "/vendor/fonts"};
+
+bool SfntNameIsEnglish(const FT_SfntName& sfnt_name) {
+ if (sfnt_name.platform_id == TT_PLATFORM_MICROSOFT)
+ return sfnt_name.language_id == TT_MS_LANGID_ENGLISH_UNITED_STATES;
+ if (sfnt_name.platform_id == TT_PLATFORM_MACINTOSH)
+ return sfnt_name.language_id == TT_MAC_LANGID_ENGLISH;
+ return false;
+}
+
+// Convenience scoped wrapper for FT_Face instances. Takes care of handling
+// FreeType memory by calling FT_Done_Face on destruction.
+class ScopedFtFace {
+ public:
+ // Create a new FT_Face instance that will be wrapped by this object.
+ // Call IsValid() after construction to check for errors.
+ // |library| is the parent FT_Library instance, |font_path| the input font
+ // file path, and |ttc_index| the font file index (for TrueType collections).
+ ScopedFtFace(FT_Library library,
+ const std::string& font_path,
+ int32_t ttc_index)
+ : ft_face_(nullptr),
+ ft_error_(
+ FT_New_Face(library, font_path.c_str(), ttc_index, &ft_face_)) {}
+
+ // Destructor will destroy the FT_Face instance automatically.
+ ~ScopedFtFace() {
+ if (IsValid()) {
+ FT_Done_Face(ft_face_);
+ }
+ }
+
+ // Returns true iff instance is valid, i.e. construction did not fail.
+ bool IsValid() const { return ft_error_ == FT_Err_Ok; }
+
+ // Return FreeType error code from construction.
+ FT_Error error() const { return ft_error_; }
+
+ // Returns FT_Face value.
+ FT_Face get() const { return ft_face_; }
+
+ private:
+ FT_Face ft_face_ = nullptr;
+ FT_Error ft_error_ = FT_Err_Ok;
+};
+
+} // namespace
+
+namespace content {
+
+class PlatformFontUniqueNameLookup : public FontUniqueNameLookup {
+ public:
+ PlatformFontUniqueNameLookup() : FontUniqueNameLookup(GetCacheDirectory()) {
+ // Error from LoadFromFile() is ignored: Loading the cache file could be
+ // recovered from by rebuilding the font table. UpdateTableIfNeeded() checks
+ // whether the internal base::MappedReadOnlyRegion has a size, which it
+ // doesn't if the LoadFromFile() failed. If it doesn't have a size, the
+ // table is rebuild by calling UpdateTable().
+ LoadFromFile();
+ if (UpdateTableIfNeeded()) {
+ // TODO(drott): Add UMA histograms for recording cache read and write
+ // failures.
+ PersistToFile();
+ }
+ }
+
+ private:
+ static base::FilePath GetCacheDirectory() {
+ base::FilePath cache_directory;
+ base::PathService::Get(base::DIR_CACHE, &cache_directory);
+ return cache_directory;
+ }
+};
+
+FontUniqueNameLookup& FontUniqueNameLookup::GetInstance() {
+ static base::NoDestructor<PlatformFontUniqueNameLookup> sInstance;
+ return *sInstance.get();
+}
+
+FontUniqueNameLookup::FontUniqueNameLookup(FontUniqueNameLookup&&) = default;
+
+FontUniqueNameLookup::FontUniqueNameLookup(
+ const base::FilePath& cache_directory)
+ : cache_directory_(cache_directory) {
+ if (!DirectoryExists(cache_directory_) ||
+ !base::PathIsWritable(cache_directory_)) {
+ DCHECK(false) << "Error accessing cache directory for writing: "
+ << cache_directory_.value();
+ cache_directory_ = base::FilePath();
+ }
+ FT_Init_FreeType(&ft_library_);
+}
+
+FontUniqueNameLookup::~FontUniqueNameLookup() {
+ FT_Done_FreeType(ft_library_);
+}
+
+base::ReadOnlySharedMemoryRegion
+FontUniqueNameLookup::GetUniqueNameTableAsSharedMemoryRegion() const {
+ return proto_storage_.region.Duplicate();
+}
+
+bool FontUniqueNameLookup::IsValid() {
+ return proto_storage_.IsValid() && proto_storage_.mapping.size();
+}
+
+bool FontUniqueNameLookup::UpdateTableIfNeeded() {
+ blink::FontUniqueNameTable font_table;
+ bool update_needed =
+ !proto_storage_.IsValid() || !proto_storage_.mapping.size() ||
+ !font_table.ParseFromArray(proto_storage_.mapping.memory(),
+ proto_storage_.mapping.size()) ||
+ font_table.stored_for_android_build_fp() != GetAndroidBuildFingerprint();
+ if (update_needed)
+ UpdateTable();
+ return update_needed;
+}
+
+bool FontUniqueNameLookup::UpdateTable() {
+ std::vector<std::string> font_files_to_index = GetFontFilePaths();
+
+ blink::FontUniqueNameTable font_table;
+ font_table.set_stored_for_android_build_fp(GetAndroidBuildFingerprint());
+ for (const auto& font_file : font_files_to_index) {
+ int32_t number_of_faces = NumberOfFacesInFontFile(font_file);
+ for (int32_t i = 0; i < number_of_faces; ++i) {
+ if (!IndexFile(font_table.add_font_entries(), font_file, i)) {
+ // TODO(drott): Track file scanning failures in UMA.
+ font_table.mutable_font_entries()->RemoveLast();
+ }
+ }
+ }
+
+ proto_storage_ =
+ base::ReadOnlySharedMemoryRegion::Create(font_table.ByteSizeLong());
+ if (!IsValid())
+ return false;
+
+ if (!font_table.SerializeToArray(proto_storage_.mapping.memory(),
+ proto_storage_.mapping.size())) {
+ proto_storage_ = base::MappedReadOnlyRegion();
+ return false;
+ }
+ return true;
+}
+
+bool FontUniqueNameLookup::LoadFromFile() {
+ // Reset to empty to ensure IsValid() is false if reading fails.
+ proto_storage_ = base::MappedReadOnlyRegion();
+ base::File table_cache_file(
+ TableCacheFilePath(),
+ base::File::FLAG_OPEN | base::File::Flags::FLAG_READ);
+ if (!table_cache_file.IsValid())
+ return false;
+ proto_storage_ =
+ base::ReadOnlySharedMemoryRegion::Create(table_cache_file.GetLength());
+ if (!IsValid())
+ return false;
+ int read_result = table_cache_file.Read(
+ 0, static_cast<char*>(proto_storage_.mapping.memory()),
+ table_cache_file.GetLength());
+ // If no bytes were read or Read() returned -1 we are not able to reconstruct
+ // a font table from the cached file.
+ if (read_result <= 0) {
+ proto_storage_ = base::MappedReadOnlyRegion();
+ return false;
+ }
+
+ blink::FontUniqueNameTable font_table;
+ if (!font_table.ParseFromArray(proto_storage_.mapping.memory(),
+ proto_storage_.mapping.size())) {
+ proto_storage_ = base::MappedReadOnlyRegion();
+ return false;
+ }
+
+ return true;
+}
+
+bool FontUniqueNameLookup::PersistToFile() {
+ DCHECK(IsValid());
+ if (!IsValid())
+ return false;
+ base::File table_cache_file(
+ TableCacheFilePath(),
+ base::File::FLAG_CREATE_ALWAYS | base::File::Flags::FLAG_WRITE);
+ if (!table_cache_file.IsValid())
+ return false;
+ if (table_cache_file.Write(
+ 0, static_cast<char*>(proto_storage_.mapping.memory()),
+ proto_storage_.mapping.size()) == -1) {
+ table_cache_file.SetLength(0);
+ proto_storage_ = base::MappedReadOnlyRegion();
+ return false;
+ }
+ return true;
+}
+
+base::FilePath FontUniqueNameLookup::TableCacheFilePath() {
+ return base::FilePath(
+ cache_directory_.Append(base::FilePath(kProtobufFilename)));
+}
+
+bool FontUniqueNameLookup::IndexFile(
+ blink::FontUniqueNameTable_FontUniqueNameEntry* font_entry,
+ const std::string& font_file_path,
+ uint32_t ttc_index) {
+ ScopedFtFace face(ft_library_, font_file_path.c_str(), ttc_index);
+ if (!face.IsValid()) {
+ LOG(ERROR) << "Unable to open font file for indexing: "
+ << font_file_path.c_str()
+ << " - FreeType FT_Error code: " << face.error();
+ return false;
+ }
+
+ if (!FT_Get_Sfnt_Name_Count(face.get())) {
+ LOG(ERROR) << "Zero name table entries in font file: "
+ << font_file_path.c_str();
+ return false;
+ }
+
+ // Get file attributes
+ base::File font_file_for_info(
+ base::FilePath(font_file_path.c_str()),
+ base::File::FLAG_OPEN | base::File::Flags::FLAG_READ);
+ if (!font_file_for_info.IsValid()) {
+ LOG(ERROR) << "Unable to open font file: " << font_file_path.c_str();
+ return false;
+ }
+ base::File::Info font_file_info;
+ if (!font_file_for_info.GetInfo(&font_file_info)) {
+ LOG(ERROR) << "Unable to get font file attributes for: "
+ << font_file_path.c_str();
+ return false;
+ }
+ font_entry->set_file_path(font_file_path);
+ font_entry->set_ttc_index(ttc_index);
+
+ for (size_t i = 0; i < FT_Get_Sfnt_Name_Count(face.get()); ++i) {
+ FT_SfntName sfnt_name;
+ if (FT_Get_Sfnt_Name(face.get(), i, &sfnt_name) != 0) {
+ LOG(ERROR) << "Unable to retrieve Sfnt Name table for font file: "
+ << font_file_path.c_str();
+ return false;
+ }
+
+ if (!SfntNameIsEnglish(sfnt_name))
+ continue;
+
+ std::string sfnt_name_string = "";
+ std::string codepage_name;
+ // Codepage names from http://demo.icu-project.org/icu-bin/convexp
+ if (sfnt_name.platform_id == TT_PLATFORM_MICROSOFT &&
+ sfnt_name.encoding_id == TT_MS_ID_UNICODE_CS) {
+ codepage_name = "UTF16-BE";
+ } else if (sfnt_name.platform_id == TT_PLATFORM_MACINTOSH &&
+ sfnt_name.encoding_id == TT_MAC_ID_ROMAN) {
+ codepage_name = "macintosh";
+ }
+ UnicodeString sfnt_name_unicode(reinterpret_cast<char*>(sfnt_name.string),
+ sfnt_name.string_len,
+ codepage_name.c_str());
+ if (sfnt_name_unicode.isBogus())
+ return false;
+ // Firefox performs case insensitive matching for src: local().
+ sfnt_name_unicode.foldCase();
+ sfnt_name_unicode.toUTF8String(sfnt_name_string);
+
+ switch (sfnt_name.name_id) {
+ case TT_NAME_ID_PS_NAME:
+ font_entry->set_postscript_name(blink::IcuFoldCase(sfnt_name_string));
+ break;
+ case TT_NAME_ID_FULL_NAME:
+ font_entry->set_full_name(blink::IcuFoldCase(sfnt_name_string));
+ break;
+ default:
+ break;
+ }
+ }
+ return true;
+}
+
+int32_t FontUniqueNameLookup::NumberOfFacesInFontFile(
+ const std::string& font_filename) const {
+ // According to FreeType documentation calling FT_Open_Face with a negative
+ // index value allows us to probe how many fonts can be found in a font file
+ // (which can be a single font ttf or a TrueType collection (.ttc).
+ ScopedFtFace probe_face(ft_library_, font_filename.c_str(), -1);
+ if (!probe_face.IsValid())
+ return 0;
+ return probe_face.get()->num_faces;
+}
+
+std::string FontUniqueNameLookup::GetAndroidBuildFingerprint() const {
+ return android_build_fingerprint_for_testing_.size()
+ ? android_build_fingerprint_for_testing_
+ : base::android::BuildInfo::GetInstance()->android_build_fp();
+}
+
+std::vector<std::string> FontUniqueNameLookup::GetFontFilePaths() const {
+ if (font_file_paths_for_testing_.size())
+ return font_file_paths_for_testing_;
+ std::vector<std::string> font_files;
+ for (const char* font_dir_path : kAndroidFontPaths) {
+ base::FileEnumerator files_enumerator(
+ base::MakeAbsoluteFilePath(base::FilePath(font_dir_path)), true,
+ base::FileEnumerator::FILES);
+ for (base::FilePath name = files_enumerator.Next(); !name.empty();
+ name = files_enumerator.Next()) {
+ if (name.Extension() == ".ttf" || name.Extension() == ".ttc" ||
+ name.Extension() == ".otf") {
+ font_files.push_back(name.value());
+ }
+ }
+ }
+ return font_files;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/font_unique_name_lookup/font_unique_name_lookup.h b/chromium/content/browser/font_unique_name_lookup/font_unique_name_lookup.h
new file mode 100644
index 00000000000..5cf38306c49
--- /dev/null
+++ b/chromium/content/browser/font_unique_name_lookup/font_unique_name_lookup.h
@@ -0,0 +1,138 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_FONT_UNIQUE_NAME_LOOKUP_FONT_UNIQUE_NAME_LOOKUP_H_
+#define CONTENT_BROWSER_FONT_UNIQUE_NAME_LOOKUP_FONT_UNIQUE_NAME_LOOKUP_H_
+
+#include "base/files/file_path.h"
+#include "base/memory/read_only_shared_memory_region.h"
+#include "content/common/content_export.h"
+
+#include <ft2build.h>
+#include FT_SYSTEM_H
+#include FT_TRUETYPE_TABLES_H
+#include FT_SFNT_NAMES_H
+
+#include <string>
+
+namespace blink {
+class FontUniqueNameTable_FontUniqueNameEntry;
+}
+
+namespace content {
+
+// Scans a set of font files for the full font name and postscript name
+// information in the name table and builds a Protobuf lookup structure from
+// it. The protobuf can be persisted to disk to the Android cache directory, and
+// it can be read from disk as well. Provides the lookup structure as a
+// ReadOnlySharedMemoryRegion. Performing lookup on it is done through
+// FontTableMatcher.
+class CONTENT_EXPORT FontUniqueNameLookup {
+ public:
+ FontUniqueNameLookup() = delete;
+
+ // Retrieve an initialized instance of FontUniqueNameLookup that has read the
+ // table from cache if there was one, updated the lookup table if needed
+ // (i.e. if there was an Android firmware update) from the standard Android
+ // font directories, and written the updated lookup table back to file. It is
+ // ready to use with FontTableMatcher.
+ static FontUniqueNameLookup& GetInstance();
+
+ // Construct a FontUniqueNameLookup given a cache directory path
+ // |cache_directory| to persist the internal lookup table, a
+ // FontFilesCollector to enumerate font files and a BuildFingerprintProvider
+ // to access the Android build fingerprint.
+ FontUniqueNameLookup(const base::FilePath& cache_directory);
+ ~FontUniqueNameLookup();
+
+ // Default move contructor.
+ FontUniqueNameLookup(FontUniqueNameLookup&&);
+ // Default move assigment operator.
+ FontUniqueNameLookup& operator=(FontUniqueNameLookup&&) = default;
+
+ // Return a ReadOnlySharedMemoryRegion to access the serialized form of the
+ // current lookup table. To be used with FontTableMatcher.
+ base::ReadOnlySharedMemoryRegion GetUniqueNameTableAsSharedMemoryRegion()
+ const;
+
+ // Returns true if an up-to-date, consistent font table is present.
+ bool IsValid();
+
+ // If an Android firmware update was detected by checking
+ // BuildFingerprintProvider, call UpdateTable(). Do not use this method.
+ // Instead, call GetInstance() to get an initialized instance. Publicly
+ // exposed for testing.
+ bool UpdateTableIfNeeded();
+ // Rescan the files returned by the FontFilesCollector and rebuild the lookup
+ // table by indexing them. Do not use this method. Instead, call GetInstance()
+ // to get an initialized instance. Returns true if instance is valid after
+ // updating, returns false if an error occured in acquiring memory or
+ // serializing the scanned files to the shared memory region. Publicly exposed
+ // for testing.
+ bool UpdateTable();
+ // Try to find a serialized lookup table in the directory specified at
+ // construction and load it into memory. Do not use this method. Instead, call
+ // GetInstance() to get an initialized instance. Publicly exposed for testing.
+ bool LoadFromFile();
+ // Serialize the current lookup table into a file in the the cache directory
+ // specified at construction time. If an up to date table is present and
+ // persisting fails, discard the internal table, as it might be that we were
+ // not able to update the file the previous time. Do not use this
+ // method. Instead, call GetInstance() to get an initialized
+ // instance. Publicly exposed for testing.
+ bool PersistToFile();
+
+ // Override the internal font files enumeration with an explicit set of fonts
+ // to be scanned in |font_file_paths|. Only used for testing.
+ void SetFontFilePathsForTesting(
+ const std::vector<std::string> font_file_paths) {
+ font_file_paths_for_testing_ = font_file_paths;
+ }
+
+ // Override the Android build fingerprint for testing.
+ void SetAndroidBuildFingerprintForTesting(
+ const std::string& build_fingerprint_override) {
+ android_build_fingerprint_for_testing_ = build_fingerprint_override;
+ }
+
+ // Returns the storage location of the table cache protobuf file.
+ base::FilePath TableCacheFilePathForTesting() {
+ return TableCacheFilePath();
+ };
+
+ private:
+ // Scan the font file at |font_file_path| and given |ttc_index| and extract
+ // full font name and postscript name from the font and store it into the
+ // font_index_entry protobuf object.
+ bool IndexFile(
+ blink::FontUniqueNameTable_FontUniqueNameEntry* font_index_entry,
+ const std::string& font_file_path,
+ uint32_t ttc_index);
+ // For a TrueType font collection, determine how many font faces are
+ // available in a file.
+ int32_t NumberOfFacesInFontFile(const std::string& font_filename) const;
+
+ // If an Android build fingerprint override is set through
+ // SetAndroidBuildFingerprint() return that, otherwise return the actual
+ // platform's Android build fingerprint.
+ std::string GetAndroidBuildFingerprint() const;
+
+ // If an override is set through SetFontFilePathsForTesting() return those
+ // fonts, otherwise enumerate font files in the the Android platform font
+ // directories.
+ std::vector<std::string> GetFontFilePaths() const;
+
+ base::FilePath TableCacheFilePath();
+
+ base::FilePath cache_directory_;
+ FT_Library ft_library_;
+ base::MappedReadOnlyRegion proto_storage_;
+
+ std::string android_build_fingerprint_for_testing_ = "";
+ std::vector<std::string> font_file_paths_for_testing_ =
+ std::vector<std::string>();
+};
+} // namespace content
+
+#endif // CONTENT_BROWSER_FONT_UNIQUE_NAME_LOOKUP_FONT_UNIQUE_NAME_LOOKUP_H_
diff --git a/chromium/content/browser/font_unique_name_lookup/font_unique_name_lookup_service.cc b/chromium/content/browser/font_unique_name_lookup/font_unique_name_lookup_service.cc
new file mode 100644
index 00000000000..79c4fa1ac5e
--- /dev/null
+++ b/chromium/content/browser/font_unique_name_lookup/font_unique_name_lookup_service.cc
@@ -0,0 +1,50 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/font_unique_name_lookup/font_unique_name_lookup_service.h"
+
+#include "base/feature_list.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/task/post_task.h"
+#include "content/browser/font_unique_name_lookup/font_unique_name_lookup.h"
+#include "content/public/common/content_features.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+
+namespace content {
+
+FontUniqueNameLookupService::FontUniqueNameLookupService()
+ : font_unique_name_lookup_(::content::FontUniqueNameLookup::GetInstance()) {
+ DCHECK(base::FeatureList::IsEnabled(features::kFontSrcLocalMatching));
+}
+
+FontUniqueNameLookupService::~FontUniqueNameLookupService() {}
+
+// static
+void FontUniqueNameLookupService::Create(
+ blink::mojom::FontUniqueNameLookupRequest request) {
+ mojo::MakeStrongBinding(std::make_unique<FontUniqueNameLookupService>(),
+ std::move(request));
+}
+
+// static
+scoped_refptr<base::SequencedTaskRunner>
+FontUniqueNameLookupService::GetTaskRunner() {
+ CR_DEFINE_STATIC_LOCAL(
+ scoped_refptr<base::SequencedTaskRunner>, runner,
+ (base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
+ base::TaskPriority::USER_BLOCKING})));
+ return runner;
+}
+
+void FontUniqueNameLookupService::GetUniqueNameLookupTable(
+ GetUniqueNameLookupTableCallback callback) {
+ DCHECK(GetTaskRunner()->RunsTasksInCurrentSequence());
+ std::move(callback).Run(
+ font_unique_name_lookup_.GetUniqueNameTableAsSharedMemoryRegion());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/font_unique_name_lookup/font_unique_name_lookup_service.h b/chromium/content/browser/font_unique_name_lookup/font_unique_name_lookup_service.h
new file mode 100644
index 00000000000..01aac221714
--- /dev/null
+++ b/chromium/content/browser/font_unique_name_lookup/font_unique_name_lookup_service.h
@@ -0,0 +1,36 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_FONT_UNIQUE_NAME_LOOKUP_FONT_UNIQUE_NAME_LOOKUP_SERVICE_H_
+#define CONTENT_BROWSER_FONT_UNIQUE_NAME_LOOKUP_FONT_UNIQUE_NAME_LOOKUP_SERVICE_H_
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "third_party/blink/public/platform/modules/font_unique_name_lookup/font_unique_name_lookup.mojom.h"
+
+namespace content {
+
+class FontUniqueNameLookup;
+
+class FontUniqueNameLookupService : public blink::mojom::FontUniqueNameLookup {
+ public:
+ FontUniqueNameLookupService();
+ ~FontUniqueNameLookupService() override;
+
+ static void Create(blink::mojom::FontUniqueNameLookupRequest);
+
+ static scoped_refptr<base::SequencedTaskRunner> GetTaskRunner();
+
+ void GetUniqueNameLookupTable(
+ GetUniqueNameLookupTableCallback callback) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FontUniqueNameLookupService);
+ ::content::FontUniqueNameLookup& font_unique_name_lookup_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_FONT_UNIQUE_NAME_LOOKUP_FONT_UNIQUE_NAME_LOOKUP_SERVICE_H_
diff --git a/chromium/content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest.cc b/chromium/content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest.cc
new file mode 100644
index 00000000000..bc13d1ea346
--- /dev/null
+++ b/chromium/content/browser/font_unique_name_lookup/font_unique_name_lookup_unittest.cc
@@ -0,0 +1,334 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "base/android/build_info.h"
+#include "base/files/file.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "content/browser/font_unique_name_lookup/font_unique_name_lookup.h"
+#include "third_party/blink/public/common/font_unique_name_lookup/font_table_matcher.h"
+
+#include <functional>
+#include <memory>
+
+namespace {
+
+static const char* const kAndroidFontPaths[] = {"/system/fonts",
+ "/vendor/fonts"};
+
+// Full font name, postscript name, filename.
+static const char* const kRobotoCondensedBoldItalicNames[] = {
+ "Roboto Condensed Bold Italic", "RobotoCondensed-BoldItalic",
+ "RobotoCondensed-BoldItalic.ttf"};
+
+std::vector<std::string> AndroidFontFilesList() {
+ std::vector<std::string> font_files;
+ for (const char* font_dir_path : kAndroidFontPaths) {
+ base::FileEnumerator files_enumerator(
+ base::MakeAbsoluteFilePath(base::FilePath(font_dir_path)), true,
+ base::FileEnumerator::FILES);
+ for (base::FilePath name = files_enumerator.Next(); !name.empty();
+ name = files_enumerator.Next()) {
+ if (name.Extension() == ".ttf" || name.Extension() == ".ttc" ||
+ name.Extension() == ".otf") {
+ font_files.push_back(name.value());
+ }
+ }
+ }
+ return font_files;
+}
+
+std::vector<std::string> SplitFontFilesList(
+ const std::vector<std::string> font_files,
+ bool return_second_half) {
+ CHECK_GT(font_files.size(), 2u);
+ auto start_copy = font_files.begin();
+ auto end_copy = font_files.begin() + (font_files.size() / 2);
+ if (return_second_half) {
+ start_copy = end_copy;
+ end_copy = font_files.end();
+ }
+ return std::vector<std::string>(start_copy, end_copy);
+}
+
+enum class TruncateLength { TruncateToZero, TruncateHalf };
+
+void TruncateFile(const base::FilePath& file_path,
+ TruncateLength truncate_length) {
+ base::File file_to_truncate(
+ file_path, base::File::FLAG_OPEN | base::File::Flags::FLAG_WRITE);
+ size_t truncate_to = truncate_length == TruncateLength::TruncateHalf
+ ? file_to_truncate.GetLength() / 2
+ : 0;
+ file_to_truncate.SetLength(truncate_to);
+}
+
+} // namespace
+
+namespace content {
+
+class FontUniqueNameLookupTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ font_unique_name_lookup_ =
+ std::make_unique<FontUniqueNameLookup>(temp_dir_.GetPath());
+ }
+
+ base::ScopedTempDir temp_dir_;
+ std::unique_ptr<FontUniqueNameLookup> font_unique_name_lookup_;
+};
+
+TEST_F(FontUniqueNameLookupTest, TestBuildLookup) {
+ ASSERT_TRUE(font_unique_name_lookup_->UpdateTable());
+ base::ReadOnlySharedMemoryMapping mapping =
+ font_unique_name_lookup_->GetUniqueNameTableAsSharedMemoryRegion().Map();
+ blink::FontTableMatcher matcher(mapping);
+ ASSERT_GT(matcher.AvailableFonts(), 0u);
+ ASSERT_TRUE(font_unique_name_lookup_->PersistToFile());
+ ASSERT_TRUE(font_unique_name_lookup_->LoadFromFile());
+ blink::FontTableMatcher matcher_after_load(
+ font_unique_name_lookup_->GetUniqueNameTableAsSharedMemoryRegion().Map());
+ ASSERT_GT(matcher_after_load.AvailableFonts(), 0u);
+}
+
+TEST_F(FontUniqueNameLookupTest, TestHandleFailedRead) {
+ base::DeleteFile(font_unique_name_lookup_->TableCacheFilePathForTesting(),
+ false);
+ ASSERT_FALSE(font_unique_name_lookup_->LoadFromFile());
+ ASSERT_FALSE(font_unique_name_lookup_->IsValid());
+ ASSERT_TRUE(font_unique_name_lookup_->UpdateTable());
+ ASSERT_TRUE(font_unique_name_lookup_->IsValid());
+ base::ReadOnlySharedMemoryMapping mapping =
+ font_unique_name_lookup_->GetUniqueNameTableAsSharedMemoryRegion().Map();
+ blink::FontTableMatcher matcher(mapping);
+ ASSERT_GT(matcher.AvailableFonts(), 0u);
+ ASSERT_TRUE(font_unique_name_lookup_->PersistToFile());
+ ASSERT_TRUE(font_unique_name_lookup_->LoadFromFile());
+ ASSERT_TRUE(font_unique_name_lookup_->IsValid());
+ TruncateFile(font_unique_name_lookup_->TableCacheFilePathForTesting(),
+ TruncateLength::TruncateHalf);
+ ASSERT_FALSE(font_unique_name_lookup_->LoadFromFile());
+ ASSERT_FALSE(font_unique_name_lookup_->IsValid());
+ TruncateFile(font_unique_name_lookup_->TableCacheFilePathForTesting(),
+ TruncateLength::TruncateToZero);
+ ASSERT_FALSE(font_unique_name_lookup_->LoadFromFile());
+ ASSERT_FALSE(font_unique_name_lookup_->IsValid());
+}
+
+TEST_F(FontUniqueNameLookupTest, TestMatchPostScriptName) {
+ ASSERT_TRUE(font_unique_name_lookup_->UpdateTable());
+ blink::FontTableMatcher matcher(
+ font_unique_name_lookup_->GetUniqueNameTableAsSharedMemoryRegion().Map());
+ ASSERT_GT(matcher.AvailableFonts(), 0u);
+ auto match_result = matcher.MatchName(kRobotoCondensedBoldItalicNames[1]);
+ ASSERT_TRUE(match_result);
+ ASSERT_TRUE(EndsWith(match_result->font_path,
+ kRobotoCondensedBoldItalicNames[2],
+ base::CompareCase::SENSITIVE));
+ base::File found_file(base::FilePath(match_result->font_path),
+ base::File::FLAG_OPEN | base::File::FLAG_READ);
+ ASSERT_TRUE(found_file.IsValid());
+ ASSERT_EQ(match_result->ttc_index, 0u);
+}
+
+TEST_F(FontUniqueNameLookupTest, TestMatchPostScriptNameTtc) {
+ if (base::android::BuildInfo::GetInstance()->sdk_int() <
+ base::android::SdkVersion::SDK_VERSION_NOUGAT) {
+ // Pre-Nougat Android does not contain any .ttc files as system fonts.
+ return;
+ }
+ ASSERT_TRUE(font_unique_name_lookup_->UpdateTable());
+ blink::FontTableMatcher matcher(
+ font_unique_name_lookup_->GetUniqueNameTableAsSharedMemoryRegion().Map());
+ std::vector<std::string> ttc_postscript_names = {
+ "NotoSansCJKjp-Regular", "NotoSansCJKkr-Regular",
+ "NotoSansCJKsc-Regular", "NotoSansCJKtc-Regular",
+ "NotoSansMonoCJKjp-Regular", "NotoSansMonoCJKkr-Regular",
+ "NotoSansMonoCJKsc-Regular", "NotoSansMonoCJKtc-Regular",
+ };
+ for (size_t i = 0; i < ttc_postscript_names.size(); ++i) {
+ auto match_result = matcher.MatchName(ttc_postscript_names[i]);
+ ASSERT_TRUE(match_result);
+ ASSERT_TRUE(EndsWith(match_result->font_path, "NotoSansCJK-Regular.ttc",
+ base::CompareCase::SENSITIVE));
+ base::File found_file(base::FilePath(match_result->font_path),
+ base::File::FLAG_OPEN | base::File::FLAG_READ);
+ ASSERT_TRUE(found_file.IsValid());
+ ASSERT_EQ(match_result->ttc_index, i);
+ }
+}
+
+TEST_F(FontUniqueNameLookupTest, TestMatchFullFontName) {
+ ASSERT_TRUE(font_unique_name_lookup_->UpdateTable());
+ blink::FontTableMatcher matcher(
+ font_unique_name_lookup_->GetUniqueNameTableAsSharedMemoryRegion().Map());
+ auto match_result = matcher.MatchName(kRobotoCondensedBoldItalicNames[0]);
+ ASSERT_TRUE(match_result);
+ ASSERT_TRUE(EndsWith(match_result->font_path,
+ kRobotoCondensedBoldItalicNames[2],
+ base::CompareCase::SENSITIVE));
+ base::File found_file(base::FilePath(match_result->font_path),
+ base::File::FLAG_OPEN | base::File::Flags::FLAG_READ);
+ ASSERT_TRUE(found_file.IsValid());
+ ASSERT_EQ(match_result->ttc_index, 0u);
+}
+
+namespace {
+size_t GetNumTables(base::File& font_file) {
+ font_file.Seek(base::File::FROM_BEGIN, 5);
+ uint8_t num_tables_bytes[2] = {};
+ font_file.ReadAtCurrentPos(reinterpret_cast<char*>(num_tables_bytes),
+ base::size(num_tables_bytes));
+ uint16_t num_tables =
+ static_cast<uint16_t>(num_tables_bytes[0] + (num_tables_bytes[1] << 8));
+ return num_tables;
+};
+
+const size_t kOffsetTableRecords = 13;
+const size_t kSizeOneTableRecord = 16;
+
+} // namespace
+
+// Creates a temp directory and copies Android font files to this
+// directory. Provides two methods to inject faults into the font files 1)
+// ZeroOutTableRecords writes a sequence of 0 to where the font table offset
+// should be stored in the font file. 2) ZeroAfterTableIndex writes 0 from after
+// the table records until the end of the file.
+class FontFileCorruptor {
+ public:
+ FontFileCorruptor() {
+ CHECK(temp_dir_.CreateUniqueTempDir());
+ CopyPlatformFilesToTempDir();
+ }
+
+ // Overwrite the list of table records with 0.
+ void ZeroOutTableRecords() {
+ ForEachCopiedFontFile([](base::File& font_file) {
+ // Read number of font tables, then zero out the table record structure.
+ // https://docs.microsoft.com/en-us/typography/opentype/spec/font-file
+ size_t num_tables = GetNumTables(font_file);
+ CHECK_GT(num_tables, 0u);
+ char garbage[kSizeOneTableRecord] = {0};
+ for (size_t i = 0; i < num_tables; ++i) {
+ CHECK_EQ(static_cast<int>(kSizeOneTableRecord),
+ font_file.Write(kOffsetTableRecords + i * kSizeOneTableRecord,
+ garbage, base::size(garbage)));
+ }
+ });
+ }
+
+ // Overwrite the data in the font file with zeroes from after the table
+ // records until the end of the file.
+ void ZeroAfterTableIndex() {
+ ForEachCopiedFontFile([](base::File& font_file) {
+ size_t num_tables = GetNumTables(font_file);
+ CHECK_GT(num_tables, 0u);
+ const size_t offset_after_table_records =
+ kOffsetTableRecords + num_tables * kSizeOneTableRecord;
+ std::vector<char> zeroes;
+ zeroes.resize(font_file.GetLength() - offset_after_table_records);
+ std::fill(zeroes.begin(), zeroes.end(), 0);
+ CHECK_EQ(static_cast<int>(zeroes.size()),
+ font_file.Write(offset_after_table_records, zeroes.data(),
+ zeroes.size()));
+ });
+ }
+
+ // Get the list of filenames copied to the temporary directory.
+ std::vector<std::string> GetFontFilesList() { return copied_files_; }
+
+ private:
+ void ForEachCopiedFontFile(std::function<void(base::File&)> manipulate_file) {
+ for (const auto& filename : copied_files_) {
+ base::File font_file(base::FilePath(filename),
+ base::File::FLAG_OPEN | base::File::FLAG_READ |
+ base::File::FLAG_WRITE);
+ manipulate_file(font_file);
+ }
+ }
+
+ void CopyPlatformFilesToTempDir() {
+ std::vector<std::string> platform_files = AndroidFontFilesList();
+ for (auto& font_file : platform_files) {
+ base::FilePath source_path(font_file);
+ base::FilePath destination_path(temp_dir_.GetPath());
+ destination_path = destination_path.Append(source_path.BaseName());
+ if (base::CopyFile(source_path, destination_path))
+ copied_files_.push_back(destination_path.value());
+ }
+ }
+ base::ScopedTempDir temp_dir_;
+ std::vector<std::string> copied_files_;
+};
+
+class FaultInjectingFontUniqueNameLookupTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ font_unique_name_lookup_ =
+ std::make_unique<FontUniqueNameLookup>(temp_dir_.GetPath());
+ font_unique_name_lookup_->SetFontFilePathsForTesting(
+ font_file_corruptor_.GetFontFilesList());
+ }
+
+ base::ScopedTempDir temp_dir_;
+ FontFileCorruptor font_file_corruptor_;
+ std::unique_ptr<FontUniqueNameLookup> font_unique_name_lookup_;
+};
+
+TEST_F(FaultInjectingFontUniqueNameLookupTest, TestZeroedTableContents) {
+ font_file_corruptor_.ZeroAfterTableIndex();
+ ASSERT_TRUE(font_unique_name_lookup_->UpdateTable());
+ blink::FontTableMatcher matcher_after_update(
+ font_unique_name_lookup_->GetUniqueNameTableAsSharedMemoryRegion().Map());
+ ASSERT_EQ(matcher_after_update.AvailableFonts(), 0u);
+}
+
+TEST_F(FaultInjectingFontUniqueNameLookupTest, TestZeroedTableIndex) {
+ font_file_corruptor_.ZeroOutTableRecords();
+ ASSERT_TRUE(font_unique_name_lookup_->UpdateTable());
+ blink::FontTableMatcher matcher_after_update(
+ font_unique_name_lookup_->GetUniqueNameTableAsSharedMemoryRegion().Map());
+ ASSERT_EQ(matcher_after_update.AvailableFonts(), 0u);
+}
+
+class FontUniqueNameLookupUpdateTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ ASSERT_TRUE(lookup_table_storage_dir.CreateUniqueTempDir());
+ font_unique_name_lookup_ = std::make_unique<FontUniqueNameLookup>(
+ lookup_table_storage_dir.GetPath());
+ font_unique_name_lookup_->SetFontFilePathsForTesting(
+ SplitFontFilesList(AndroidFontFilesList(), false));
+ font_unique_name_lookup_->SetAndroidBuildFingerprintForTesting("A");
+ }
+
+ base::ScopedTempDir lookup_table_storage_dir;
+ std::unique_ptr<FontUniqueNameLookup> font_unique_name_lookup_;
+};
+
+TEST_F(FontUniqueNameLookupUpdateTest, CompareSets) {
+ ASSERT_TRUE(font_unique_name_lookup_->UpdateTable());
+ blink::FontTableMatcher matcher_initial(
+ font_unique_name_lookup_->GetUniqueNameTableAsSharedMemoryRegion().Map());
+ ASSERT_GT(matcher_initial.AvailableFonts(), 0u);
+ font_unique_name_lookup_->SetFontFilePathsForTesting(
+ SplitFontFilesList(AndroidFontFilesList(), true));
+ // Set the Android build fingerprint to something different from what it's set
+ // to in the test's SetUp method to trigger re-indexing.
+ font_unique_name_lookup_->SetAndroidBuildFingerprintForTesting("B");
+ font_unique_name_lookup_->UpdateTableIfNeeded();
+ blink::FontTableMatcher matcher_second_half(
+ font_unique_name_lookup_->GetUniqueNameTableAsSharedMemoryRegion().Map());
+ ASSERT_GT(matcher_initial.AvailableFonts(), 0u);
+ ASSERT_TRUE(matcher_initial.FontListIsDisjointFrom(matcher_second_half));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/frame_host/cross_process_frame_connector.cc b/chromium/content/browser/frame_host/cross_process_frame_connector.cc
index 146a166e410..4bd20a223cd 100644
--- a/chromium/content/browser/frame_host/cross_process_frame_connector.cc
+++ b/chromium/content/browser/frame_host/cross_process_frame_connector.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/metrics/histogram_macros.h"
+#include "components/viz/common/features.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
#include "components/viz/service/surfaces/surface.h"
#include "components/viz/service/surfaces/surface_hittest.h"
@@ -118,7 +119,7 @@ void CrossProcessFrameConnector::SetView(RenderWidgetHostViewChildFrame* view) {
if (is_hidden_)
OnVisibilityChanged(false);
FrameMsg_ViewChanged_Params params;
- if (features::IsAshInBrowserProcess())
+ if (!features::IsUsingWindowService())
params.frame_sink_id = view_->GetFrameSinkId();
frame_proxy_in_parent_renderer_->Send(new FrameMsg_ViewChanged(
frame_proxy_in_parent_renderer_->GetRoutingID(), params));
@@ -147,8 +148,10 @@ void CrossProcessFrameConnector::RenderProcessGone() {
void CrossProcessFrameConnector::FirstSurfaceActivation(
const viz::SurfaceInfo& surface_info) {
- frame_proxy_in_parent_renderer_->Send(new FrameMsg_FirstSurfaceActivation(
- frame_proxy_in_parent_renderer_->GetRoutingID(), surface_info));
+ if (!features::IsSurfaceSynchronizationEnabled()) {
+ frame_proxy_in_parent_renderer_->Send(new FrameMsg_FirstSurfaceActivation(
+ frame_proxy_in_parent_renderer_->GetRoutingID(), surface_info));
+ }
}
void CrossProcessFrameConnector::SendIntrinsicSizingInfoToParent(
@@ -225,17 +228,6 @@ bool CrossProcessFrameConnector::TransformPointToCoordSpaceForView(
*transformed_point, target_view, transformed_point, source);
}
-void CrossProcessFrameConnector::ForwardProcessAckedTouchEvent(
- const TouchEventWithLatencyInfo& touch,
- InputEventAckState ack_result) {
- auto* main_view = GetRootRenderWidgetHostView();
- // Note that the event's coordinates are in |view_|'s coordinate space, but
- // since |ProcessAckedTouchEvent| doesn't use the coordinates, we don't
- // bother to transform them back to the root coordinate space.
- if (main_view)
- main_view->ProcessAckedTouchEvent(touch, ack_result);
-}
-
void CrossProcessFrameConnector::ForwardAckedTouchpadPinchGestureEvent(
const blink::WebGestureEvent& event,
InputEventAckState ack_result) {
@@ -255,7 +247,8 @@ void CrossProcessFrameConnector::BubbleScrollEvent(
DCHECK(event.GetType() == blink::WebInputEvent::kGestureScrollBegin ||
event.GetType() == blink::WebInputEvent::kGestureScrollUpdate ||
event.GetType() == blink::WebInputEvent::kGestureScrollEnd ||
- event.GetType() == blink::WebInputEvent::kGestureFlingStart);
+ event.GetType() == blink::WebInputEvent::kGestureFlingStart ||
+ event.GetType() == blink::WebInputEvent::kGestureFlingCancel);
auto* parent_view = GetParentRenderWidgetHostView();
if (!parent_view)
@@ -278,7 +271,9 @@ void CrossProcessFrameConnector::BubbleScrollEvent(
if (event.GetType() == blink::WebInputEvent::kGestureScrollBegin) {
event_router->BubbleScrollEvent(parent_view, resent_gesture_event, view_);
is_scroll_bubbling_ = true;
- } else if (is_scroll_bubbling_) {
+ } else if (is_scroll_bubbling_ ||
+ event.GetType() == blink::WebInputEvent::kGestureFlingCancel) {
+ // For GFC events the router decides whether to bubble them or not.
event_router->BubbleScrollEvent(parent_view, resent_gesture_event, view_);
}
if (event.GetType() == blink::WebInputEvent::kGestureScrollEnd ||
@@ -336,12 +331,14 @@ void CrossProcessFrameConnector::OnSynchronizeVisualProperties(
void CrossProcessFrameConnector::OnUpdateViewportIntersection(
const gfx::Rect& viewport_intersection,
- const gfx::Rect& compositor_visible_rect) {
+ const gfx::Rect& compositor_visible_rect,
+ bool occluded_or_obscured) {
viewport_intersection_rect_ = viewport_intersection;
compositor_visible_rect_ = compositor_visible_rect;
+ occluded_or_obscured_ = occluded_or_obscured;
if (view_)
- view_->UpdateViewportIntersection(viewport_intersection,
- compositor_visible_rect);
+ view_->UpdateViewportIntersection(
+ viewport_intersection, compositor_visible_rect, occluded_or_obscured);
if (IsVisible()) {
// MaybeLogCrash will check 1) if there was a crash or not and 2) if the
@@ -461,7 +458,7 @@ bool CrossProcessFrameConnector::IsHidden() const {
#if defined(USE_AURA)
void CrossProcessFrameConnector::EmbedRendererWindowTreeClientInParent(
- ui::mojom::WindowTreeClientPtr window_tree_client) {
+ ws::mojom::WindowTreeClientPtr window_tree_client) {
RenderWidgetHostViewBase* root = GetRootRenderWidgetHostView();
RenderWidgetHostViewBase* parent = GetParentRenderWidgetHostView();
if (!parent || !root)
diff --git a/chromium/content/browser/frame_host/cross_process_frame_connector.h b/chromium/content/browser/frame_host/cross_process_frame_connector.h
index b0dc031915c..203b8a42831 100644
--- a/chromium/content/browser/frame_host/cross_process_frame_connector.h
+++ b/chromium/content/browser/frame_host/cross_process_frame_connector.h
@@ -96,8 +96,6 @@ class CONTENT_EXPORT CrossProcessFrameConnector
const viz::SurfaceId& local_surface_id,
gfx::PointF* transformed_point,
viz::EventSource source = viz::EventSource::ANY) override;
- void ForwardProcessAckedTouchEvent(const TouchEventWithLatencyInfo& touch,
- InputEventAckState ack_result) override;
void ForwardAckedTouchpadPinchGestureEvent(
const blink::WebGestureEvent& event,
InputEventAckState ack_result) override;
@@ -116,7 +114,7 @@ class CONTENT_EXPORT CrossProcessFrameConnector
bool IsSubtreeThrottled() const override;
#if defined(USE_AURA)
void EmbedRendererWindowTreeClientInParent(
- ui::mojom::WindowTreeClientPtr window_tree_client) override;
+ ws::mojom::WindowTreeClientPtr window_tree_client) override;
#endif
void DidUpdateVisualProperties(
const cc::RenderFrameMetadata& metadata) override;
@@ -164,7 +162,8 @@ class CONTENT_EXPORT CrossProcessFrameConnector
const viz::SurfaceId& surface_id,
const FrameVisualProperties& visual_properties);
void OnUpdateViewportIntersection(const gfx::Rect& viewport_intersection,
- const gfx::Rect& compositor_visible_rect);
+ const gfx::Rect& compositor_visible_rect,
+ bool occluded_or_obscured);
void OnVisibilityChanged(bool visible);
void OnSetIsInert(bool);
void OnSetInheritedEffectiveTouchAction(cc::TouchAction);
diff --git a/chromium/content/browser/frame_host/debug_urls.cc b/chromium/content/browser/frame_host/debug_urls.cc
index f66e16a2ebc..78868e2664b 100644
--- a/chromium/content/browser/frame_host/debug_urls.cc
+++ b/chromium/content/browser/frame_host/debug_urls.cc
@@ -26,6 +26,10 @@
#include "ppapi/proxy/ppapi_messages.h" // nogncheck
#endif
+#if defined(OS_WIN)
+#include "base/debug/invalid_access_win.h"
+#endif
+
namespace content {
class ScopedAllowWaitForDebugURL {
@@ -142,6 +146,14 @@ bool HandleDebugURL(const GURL& url, ui::PageTransition transition) {
return true;
}
+#if defined(OS_WIN)
+ if (url == kChromeUIBrowserHeapCorruptionURL) {
+ // Induce an intentional heap corruption in the browser process.
+ base::debug::win::TerminateWithHeapCorruption();
+ return true;
+ }
+#endif
+
if (url == kChromeUIBrowserUIHang) {
HangCurrentThread();
return true;
diff --git a/chromium/content/browser/frame_host/frame_tree_browsertest.cc b/chromium/content/browser/frame_host/frame_tree_browsertest.cc
index 13d191c9ebd..e0be5c94511 100644
--- a/chromium/content/browser/frame_host/frame_tree_browsertest.cc
+++ b/chromium/content/browser/frame_host/frame_tree_browsertest.cc
@@ -31,11 +31,8 @@ namespace content {
namespace {
-std::string GetOriginFromRenderer(FrameTreeNode* node) {
- std::string origin;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- node, "window.domAutomationController.send(document.origin);", &origin));
- return origin;
+EvalJsResult GetOriginFromRenderer(FrameTreeNode* node) {
+ return EvalJs(node, "document.origin");
}
} // namespace
@@ -314,22 +311,24 @@ IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, NavigateGrandchildToBlob) {
// target of the navigation.
FrameTreeNode* target = root->child_at(0)->child_at(0);
- std::string blob_url_string;
RenderFrameDeletedObserver deleted_observer(target->current_frame_host());
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- root,
- "function receiveMessage(event) {"
+ std::string html =
+ "<html><body><div>This is blob content.</div>"
+ "<script>"
+ "window.parent.parent.postMessage('HI', document.origin);"
+ "</script></body></html>";
+ std::string script = JsReplace(
+ "new Promise((resolve) => {"
+ " window.addEventListener('message', resolve, false);"
+ " var blob = new Blob([$1], {type: 'text/html'});"
+ " var blob_url = URL.createObjectURL(blob);"
+ " frames[0][0].location.href = blob_url;"
+ "}).then((event) => {"
" document.body.appendChild(document.createTextNode(event.data));"
- " domAutomationController.send(event.source.location.href);"
- "}"
- "window.addEventListener('message', receiveMessage, false);"
- "var blob = new Blob(["
- " '<html><body><div>This is blob content.</div><script>"
- " window.parent.parent.postMessage(\"HI\", document.origin);"
- " </script></body></html>'], {type: 'text/html'});"
- "var blob_url = URL.createObjectURL(blob);"
- "frames[0][0].location.href = blob_url;",
- &blob_url_string));
+ " return event.source.location.href;"
+ "});",
+ html);
+ std::string blob_url_string = EvalJs(root, script).ExtractString();
// Wait for the RenderFrame to go away, if this will be cross-process.
if (AreAllSitesIsolatedForTesting())
deleted_observer.WaitUntilDeleted();
@@ -338,13 +337,8 @@ IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, NavigateGrandchildToBlob) {
EXPECT_FALSE(target->current_origin().unique());
EXPECT_EQ("a.com", target->current_origin().host());
EXPECT_EQ(url::kHttpScheme, target->current_origin().scheme());
-
- std::string document_body;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- target,
- "domAutomationController.send(document.body.children[0].innerHTML);",
- &document_body));
- EXPECT_EQ("This is blob content.", document_body);
+ EXPECT_EQ("This is blob content.",
+ EvalJs(target, "document.body.children[0].innerHTML"));
EXPECT_EQ(reference_tree, FrameTreeVisualizer().DepictFrameTree(root));
}
@@ -362,38 +356,34 @@ IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, NavigateChildToAboutBlank) {
FrameTreeNode* initiator = target->parent();
// Give the target a name.
- EXPECT_TRUE(ExecuteScript(target, "window.name = 'target';"));
+ EXPECT_TRUE(ExecJs(target, "window.name = 'target';"));
// Use window.open(about:blank), then poll the document for access.
- std::string about_blank_origin;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
+ EvalJsResult about_blank_origin = EvalJs(
initiator,
- "var didNavigate = false;"
- "var intervalID = setInterval(function() {"
- " if (!didNavigate) {"
- " didNavigate = true;"
- " window.open('about:blank', 'target');"
- " }"
- " // Poll the document until it doesn't throw a SecurityError.\n"
- " try {"
- " frames[0].document.write('Hi from ' + document.domain);"
- " } catch (e) { return; }"
- " clearInterval(intervalID);"
- " domAutomationController.send(frames[0].document.origin);"
- "}, 16);",
- &about_blank_origin));
+ "new Promise(resolve => {"
+ " var didNavigate = false;"
+ " var intervalID = setInterval(function() {"
+ " if (!didNavigate) {"
+ " didNavigate = true;"
+ " window.open('about:blank', 'target');"
+ " }"
+ " // Poll the document until it doesn't throw a SecurityError.\n"
+ " try {"
+ " frames[0].document.write('Hi from ' + document.domain);"
+ " } catch (e) { return; }"
+ " clearInterval(intervalID);"
+ " resolve(frames[0].document.origin);"
+ " }, 16);"
+ "});");
+ EXPECT_EQ(target->current_origin(), about_blank_origin);
EXPECT_EQ(GURL(url::kAboutBlankURL), target->current_url());
EXPECT_EQ(url::kAboutScheme, target->current_url().scheme());
EXPECT_FALSE(target->current_origin().unique());
EXPECT_EQ("b.com", target->current_origin().host());
EXPECT_EQ(url::kHttpScheme, target->current_origin().scheme());
- EXPECT_EQ(target->current_origin().Serialize(), about_blank_origin);
- std::string document_body;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- target, "domAutomationController.send(document.body.innerHTML);",
- &document_body));
- EXPECT_EQ("Hi from b.com", document_body);
+ EXPECT_EQ("Hi from b.com", EvalJs(target, "document.body.innerHTML"));
}
// Nested iframes, three origins: A(B(C)). Frame A navigates C to about:blank
@@ -414,36 +404,34 @@ IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest,
FrameTreeNode* initiator = target->parent()->parent();
// Give the target a name.
- EXPECT_TRUE(ExecuteScript(target, "window.name = 'target';"));
+ EXPECT_TRUE(ExecJs(target, "window.name = 'target';"));
// Use window.open(about:blank), then poll the document for access.
- std::string about_blank_origin;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- initiator,
- "var didNavigate = false;"
- "var intervalID = setInterval(function() {"
- " if (!didNavigate) {"
- " didNavigate = true;"
- " window.open('about:blank', 'target');"
- " }"
- " // May raise a SecurityError, that's expected.\n"
- " frames[0][0].document.write('Hi from ' + document.domain);"
- " clearInterval(intervalID);"
- " domAutomationController.send(frames[0][0].document.origin);"
- "}, 16);",
- &about_blank_origin));
+ EvalJsResult about_blank_origin =
+ EvalJs(initiator,
+ "new Promise((resolve) => {"
+ " var didNavigate = false;"
+ " var intervalID = setInterval(() => {"
+ " if (!didNavigate) {"
+ " didNavigate = true;"
+ " window.open('about:blank', 'target');"
+ " }"
+ " // May raise a SecurityError, that's expected.\n"
+ " try {"
+ " frames[0][0].document.write('Hi from ' + document.domain);"
+ " } catch (e) { return; }"
+ " clearInterval(intervalID);"
+ " resolve(frames[0][0].document.origin);"
+ " }, 16);"
+ "});");
+ EXPECT_EQ(target->current_origin(), about_blank_origin);
EXPECT_EQ(GURL(url::kAboutBlankURL), target->current_url());
EXPECT_EQ(url::kAboutScheme, target->current_url().scheme());
EXPECT_FALSE(target->current_origin().unique());
EXPECT_EQ("a.com", target->current_origin().host());
EXPECT_EQ(url::kHttpScheme, target->current_origin().scheme());
- EXPECT_EQ(target->current_origin().Serialize(), about_blank_origin);
- std::string document_body;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- target, "domAutomationController.send(document.body.innerHTML);",
- &document_body));
- EXPECT_EQ("Hi from a.com", document_body);
+ EXPECT_EQ("Hi from a.com", EvalJs(target, "document.body.innerHTML"));
}
// Ensures that iframe with srcdoc is always put in the same origin as its
@@ -458,9 +446,7 @@ IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, ChildFrameWithSrcdoc) {
EXPECT_EQ(1U, root->child_count());
FrameTreeNode* child = root->child_at(0);
- std::string frame_origin;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- child, "domAutomationController.send(document.origin);", &frame_origin));
+ std::string frame_origin = EvalJs(child, "document.origin;").ExtractString();
EXPECT_TRUE(
child->current_frame_host()->GetLastCommittedOrigin().IsSameOriginWith(
url::Origin::Create(GURL(frame_origin))));
@@ -475,18 +461,16 @@ IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, ChildFrameWithSrcdoc) {
"f.srcdoc = 'some content';"
"document.body.appendChild(f)");
TestNavigationObserver observer(shell()->web_contents());
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
EXPECT_EQ(2U, root->child_count());
observer.Wait();
EXPECT_EQ(GURL(kAboutSrcDocURL), root->child_at(1)->current_url());
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- root->child_at(1), "domAutomationController.send(document.origin);",
- &frame_origin));
+ EvalJsResult frame_origin = EvalJs(root->child_at(1), "document.origin");
EXPECT_EQ(root->current_frame_host()->GetLastCommittedURL().GetOrigin(),
- GURL(frame_origin));
+ GURL(frame_origin.ExtractString()));
EXPECT_NE(child->current_frame_host()->GetLastCommittedURL().GetOrigin(),
- GURL(frame_origin));
+ GURL(frame_origin.ExtractString()));
}
// Set srcdoc on the existing cross-site frame. It should navigate the frame
@@ -495,15 +479,14 @@ IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, ChildFrameWithSrcdoc) {
std::string script("var f = document.getElementById('child-0');"
"f.srcdoc = 'some content';");
TestNavigationObserver observer(shell()->web_contents());
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
observer.Wait();
EXPECT_EQ(GURL(kAboutSrcDocURL), child->current_url());
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- child, "domAutomationController.send(document.origin);",
- &frame_origin));
- EXPECT_EQ(root->current_frame_host()->GetLastCommittedURL().GetOrigin(),
- GURL(frame_origin));
+ EXPECT_EQ(
+ url::Origin::Create(root->current_frame_host()->GetLastCommittedURL())
+ .Serialize(),
+ EvalJs(child, "document.origin"));
}
}
@@ -687,8 +670,8 @@ IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, SubframeOpenerSetForNewWindow) {
// Open a new window from a subframe.
ShellAddedObserver new_shell_observer;
GURL popup_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
- EXPECT_TRUE(ExecuteScript(root->child_at(0),
- "window.open('" + popup_url.spec() + "');"));
+ EXPECT_TRUE(
+ ExecJs(root->child_at(0), JsReplace("window.open($1);", popup_url)));
Shell* new_shell = new_shell_observer.GetShell();
WebContents* new_contents = new_shell->web_contents();
WaitForLoadStop(new_contents);
@@ -897,15 +880,15 @@ IN_PROC_BROWSER_TEST_F(IsolateIcelandFrameTreeBrowserTest,
// The navigation targets an invalid blob url; that's intentional to trigger
// an error response. The response should commit in a process dedicated to
// http://b.is.
- std::string result;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- root,
- "var iframe_element = document.getElementsByTagName('iframe')[0];"
- "iframe_element.onload = () => {"
- " domAutomationController.send('done');"
- "};"
- "iframe_element.src = 'blob:http://b.is:2932/';",
- &result));
+ EXPECT_EQ(
+ "done",
+ EvalJs(
+ root,
+ "new Promise((resolve) => {"
+ " var iframe_element = document.getElementsByTagName('iframe')[0];"
+ " iframe_element.onload = () => resolve('done');"
+ " iframe_element.src = 'blob:http://b.is:2932/';"
+ "});"));
WaitForLoadStop(contents);
// Make sure we did a process transfer back to "b.is".
diff --git a/chromium/content/browser/frame_host/frame_tree_node.h b/chromium/content/browser/frame_host/frame_tree_node.h
index 4e589ac428f..cee8a19d6dd 100644
--- a/chromium/content/browser/frame_host/frame_tree_node.h
+++ b/chromium/content/browser/frame_host/frame_tree_node.h
@@ -510,7 +510,7 @@ class CONTENT_EXPORT FrameTreeNode {
std::unique_ptr<NavigationRequest> navigation_request_;
// List of objects observing this FrameTreeNode.
- base::ObserverList<Observer> observers_;
+ base::ObserverList<Observer>::Unchecked observers_;
base::TimeTicks last_focus_time_;
diff --git a/chromium/content/browser/frame_host/interstitial_page_impl.cc b/chromium/content/browser/frame_host/interstitial_page_impl.cc
index f839f62061b..6a26f13d246 100644
--- a/chromium/content/browser/frame_host/interstitial_page_impl.cc
+++ b/chromium/content/browser/frame_host/interstitial_page_impl.cc
@@ -528,6 +528,7 @@ void InterstitialPageImpl::DidNavigate(
if (!controller_->delegate()->IsHidden())
render_view_host_->GetWidget()->GetView()->Show();
controller_->delegate()->AttachInterstitialPage(this);
+ render_view_host_->GetWidget()->GetView()->OnInterstitialPageAttached();
RenderWidgetHostView* rwh_view =
controller_->delegate()->GetRenderViewHost()->GetWidget()->GetView();
@@ -580,6 +581,20 @@ KeyboardEventProcessingResult InterstitialPageImpl::PreHandleKeyboardEvent(
return render_widget_host_delegate_->PreHandleKeyboardEvent(event);
}
+bool InterstitialPageImpl::PreHandleMouseEvent(
+ const blink::WebMouseEvent& event) {
+ if (!enabled())
+ return false;
+
+ if (event.GetType() == blink::WebInputEvent::Type::kMouseUp &&
+ event.button == blink::WebPointerProperties::Button::kBack &&
+ controller_->CanGoBack()) {
+ controller_->GoBack();
+ return true;
+ }
+ return false;
+}
+
void InterstitialPageImpl::HandleKeyboardEvent(
const NativeWebKeyboardEvent& event) {
if (enabled())
@@ -750,6 +765,8 @@ RenderWidgetHostView* InterstitialPageImpl::GetView() {
}
RenderFrameHost* InterstitialPageImpl::GetMainFrame() const {
+ if (!render_view_host_)
+ return nullptr;
return render_view_host_->GetMainFrame();
}
@@ -1073,4 +1090,16 @@ InterstitialPageImpl::GetOrCreateRootBrowserAccessibilityManager() {
return web_contents_impl->GetOrCreateRootBrowserAccessibilityManager();
}
+void InterstitialPageImpl::AudioContextPlaybackStarted(RenderFrameHost* host,
+ int context_id) {
+ // Interstitial pages should not be playing any sound via WebAudio
+ NOTREACHED();
+}
+
+void InterstitialPageImpl::AudioContextPlaybackStopped(RenderFrameHost* host,
+ int context_id) {
+ // Interstitial pages should not be playing any sound via WebAudio.
+ NOTREACHED();
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/interstitial_page_impl.h b/chromium/content/browser/frame_host/interstitial_page_impl.h
index d23262f505e..bb4b5f7771d 100644
--- a/chromium/content/browser/frame_host/interstitial_page_impl.h
+++ b/chromium/content/browser/frame_host/interstitial_page_impl.h
@@ -138,6 +138,10 @@ class CONTENT_EXPORT InterstitialPageImpl : public InterstitialPage,
bool user_gesture) override;
void SetFocusedFrame(FrameTreeNode* node, SiteInstance* source) override;
Visibility GetVisibility() const override;
+ void AudioContextPlaybackStarted(RenderFrameHost* host,
+ int context_id) override;
+ void AudioContextPlaybackStopped(RenderFrameHost* host,
+ int context_id) override;
// RenderViewHostDelegate implementation:
RenderViewHostDelegateView* GetDelegateView() override;
@@ -170,6 +174,7 @@ class CONTENT_EXPORT InterstitialPageImpl : public InterstitialPage,
void RenderWidgetDeleted(RenderWidgetHostImpl* render_widget_host) override;
KeyboardEventProcessingResult PreHandleKeyboardEvent(
const NativeWebKeyboardEvent& event) override;
+ bool PreHandleMouseEvent(const blink::WebMouseEvent& event) override;
void HandleKeyboardEvent(const NativeWebKeyboardEvent& event) override;
TextInputManager* GetTextInputManager() override;
RenderWidgetHostInputEventRouter* GetInputEventRouter() override;
diff --git a/chromium/content/browser/frame_host/interstitial_page_impl_browsertest.cc b/chromium/content/browser/frame_host/interstitial_page_impl_browsertest.cc
index 37108eea53e..edf5170facb 100644
--- a/chromium/content/browser/frame_host/interstitial_page_impl_browsertest.cc
+++ b/chromium/content/browser/frame_host/interstitial_page_impl_browsertest.cc
@@ -199,6 +199,15 @@ class InterstitialPageImplTest : public ContentBrowserTest {
EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
}
+ void PerformBack() {
+ RenderFrameHostImpl* rfh =
+ static_cast<RenderFrameHostImpl*>(interstitial_->GetMainFrame());
+ rfh->GetRenderWidgetHost()->ForwardMouseEvent(blink::WebMouseEvent(
+ blink::WebInputEvent::Type::kMouseUp, blink::WebFloatPoint(),
+ blink::WebFloatPoint(), blink::WebPointerProperties::Button::kBack, 0,
+ 0, base::TimeTicks::Now()));
+ }
+
private:
std::unique_ptr<InterstitialPageImpl> interstitial_;
@@ -351,4 +360,19 @@ IN_PROC_BROWSER_TEST_F(InterstitialPageImplTest, UnderlyingSubframeCommit) {
TearDownInterstitialPage();
}
+IN_PROC_BROWSER_TEST_F(InterstitialPageImplTest, BackMouseButton) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+
+ // Load something into the WebContents.
+ EXPECT_TRUE(NavigateToURL(
+ shell(), GURL(embedded_test_server()->GetURL("/title1.html"))));
+ SetUpInterstitialPage();
+
+ EXPECT_TRUE(shell()->web_contents()->ShowingInterstitialPage());
+ PerformBack();
+ EXPECT_FALSE(shell()->web_contents()->ShowingInterstitialPage());
+
+ TearDownInterstitialPage();
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/navigation_controller_android.cc b/chromium/content/browser/frame_host/navigation_controller_android.cc
index 7136ac7c8df..00e4c80e4f6 100644
--- a/chromium/content/browser/frame_host/navigation_controller_android.cc
+++ b/chromium/content/browser/frame_host/navigation_controller_android.cc
@@ -47,14 +47,16 @@ JNI_NavigationControllerImpl_CreateJavaNavigationEntry(
ConvertUTF8ToJavaString(env, entry->GetOriginalRequestURL().spec()));
ScopedJavaLocalRef<jstring> j_title(
ConvertUTF16ToJavaString(env, entry->GetTitle()));
+ ScopedJavaLocalRef<jstring> j_referrer_url(
+ ConvertUTF8ToJavaString(env, entry->GetReferrer().url.spec()));
ScopedJavaLocalRef<jobject> j_bitmap;
const content::FaviconStatus& status = entry->GetFavicon();
if (status.valid && status.image.ToSkBitmap()->computeByteSize() > 0)
j_bitmap = gfx::ConvertToJavaBitmap(status.image.ToSkBitmap());
return content::Java_NavigationControllerImpl_createNavigationEntry(
- env, index, j_url, j_virtual_url, j_original_url, j_title, j_bitmap,
- entry->GetTransitionType());
+ env, index, j_url, j_virtual_url, j_original_url, j_referrer_url, j_title,
+ j_bitmap, entry->GetTransitionType());
}
static void JNI_NavigationControllerImpl_AddNavigationEntryToHistory(
diff --git a/chromium/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/chromium/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index b1ed11f1561..06e52b458db 100644
--- a/chromium/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/chromium/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -42,6 +42,7 @@
#include "content/public/browser/resource_dispatcher_host.h"
#include "content/public/browser/resource_dispatcher_host_delegate.h"
#include "content/public/browser/resource_throttle.h"
+#include "content/public/browser/site_isolation_policy.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
@@ -55,8 +56,10 @@
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/download_test_observer.h"
+#include "content/public/test/navigation_handle_observer.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
+#include "content/public/test/url_loader_interceptor.h"
#include "content/shell/browser/shell.h"
#include "content/shell/browser/shell_download_manager_delegate.h"
#include "content/shell/common/shell_switches.h"
@@ -259,7 +262,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
"var xhr = new XMLHttpRequest();\n"
"xhr.open('GET', url);\n"
"xhr.send();\n";
- EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script));
+ EXPECT_TRUE(ExecJs(shell()->web_contents(), script));
// The renderer may not be killed immediately (if it is indeed killed), so
// reload, block and verify its liveness.
ReloadBlockUntilNavigationsComplete(shell(), 1);
@@ -325,10 +328,9 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Navigate with Javascript.
{
GURL navigate_url = embedded_test_server()->base_url();
- std::string script = "document.location = '" +
- navigate_url.spec() + "';";
+ std::string script = JsReplace("document.location = $1", navigate_url);
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
- EXPECT_TRUE(ExecuteScript(shell(), script));
+ EXPECT_TRUE(ExecJs(shell(), script));
same_tab_observer.Wait();
EXPECT_EQ(2, controller.GetEntryCount());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
@@ -377,7 +379,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
EXPECT_EQ(data_url, entry->GetURL());
// Passes if renderer is still alive.
- EXPECT_TRUE(ExecuteScript(shell(), "console.log('Success');"));
+ EXPECT_TRUE(ExecJs(shell(), "console.log('Success');"));
}
IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, UniqueIDs) {
@@ -392,7 +394,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, UniqueIDs) {
// Use JavaScript to click the link and load the iframe.
std::string script = "document.getElementById('link').click()";
- EXPECT_TRUE(ExecuteScript(shell(), script));
+ EXPECT_TRUE(ExecJs(shell(), script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
ASSERT_EQ(2, controller.GetEntryCount());
@@ -494,21 +496,13 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
namespace {
-int RendererHistoryLength(Shell* shell) {
- int value = 0;
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- shell, "domAutomationController.send(history.length)", &value));
- return value;
-}
-
// Does a renderer-initiated location.replace navigation to |url|, replacing the
// current entry.
bool RendererLocationReplace(Shell* shell, const GURL& url) {
WebContents* web_contents = shell->web_contents();
WaitForLoadStop(web_contents);
TestNavigationObserver same_tab_observer(web_contents, 1);
- EXPECT_TRUE(
- ExecuteScript(shell, "window.location.replace('" + url.spec() + "');"));
+ EXPECT_TRUE(ExecJs(shell, JsReplace("window.location.replace($1)", url)));
same_tab_observer.Wait();
if (!IsLastCommittedEntryOfPageType(web_contents, PAGE_TYPE_NORMAL))
return false;
@@ -527,24 +521,24 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("/simple_page.html")));
EXPECT_EQ(1, controller.GetEntryCount());
- EXPECT_EQ(1, RendererHistoryLength(shell()));
+ EXPECT_EQ(1, EvalJs(shell(), "history.length"));
EXPECT_TRUE(RendererLocationReplace(
shell(), embedded_test_server()->GetURL("/title1.html")));
EXPECT_EQ(1, controller.GetEntryCount());
- EXPECT_EQ(1, RendererHistoryLength(shell()));
+ EXPECT_EQ(1, EvalJs(shell(), "history.length"));
// Now create two more entries and go back, to test replacing an entry without
// pruning the forward history.
EXPECT_TRUE(
NavigateToURL(shell(), embedded_test_server()->GetURL("/title2.html")));
EXPECT_EQ(2, controller.GetEntryCount());
- EXPECT_EQ(2, RendererHistoryLength(shell()));
+ EXPECT_EQ(2, EvalJs(shell(), "history.length"));
EXPECT_TRUE(
NavigateToURL(shell(), embedded_test_server()->GetURL("/title3.html")));
EXPECT_EQ(3, controller.GetEntryCount());
- EXPECT_EQ(3, RendererHistoryLength(shell()));
+ EXPECT_EQ(3, EvalJs(shell(), "history.length"));
controller.GoBack();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
@@ -555,7 +549,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
EXPECT_TRUE(RendererLocationReplace(
shell(), embedded_test_server()->GetURL("/simple_page.html?page1b")));
EXPECT_EQ(3, controller.GetEntryCount());
- EXPECT_EQ(3, RendererHistoryLength(shell()));
+ EXPECT_EQ(3, EvalJs(shell(), "history.length"));
EXPECT_TRUE(controller.CanGoForward());
// Note that there's no way to access the renderer's notion of the history
@@ -576,15 +570,15 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
shell()->web_contents()->GetMainFrame()->GetEnabledBindings());
ShellAddedObserver observer;
- std::string page_url = embedded_test_server()->GetURL(
- "/navigation_controller/simple_page_1.html").spec();
+ GURL page_url = embedded_test_server()->GetURL(
+ "/navigation_controller/simple_page_1.html");
EXPECT_TRUE(
- ExecuteScript(shell(), "window.open('" + page_url + "', '_blank')"));
+ ExecJs(shell(), JsReplace("window.open($1, '_blank');", page_url)));
Shell* shell2 = observer.GetShell();
EXPECT_TRUE(WaitForLoadStop(shell2->web_contents()));
EXPECT_EQ(1, shell2->web_contents()->GetController().GetEntryCount());
- EXPECT_EQ(1, RendererHistoryLength(shell2));
+ EXPECT_EQ(1, EvalJs(shell2, "history.length"));
// Again, as above, there's no way to access the renderer's notion of the
// history offset via JavaScript. Checking just the history length, again,
@@ -850,7 +844,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, SubframeOnEmptyPage) {
ShellAddedObserver new_shell_observer;
{
std::string script = "window.open()";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
}
Shell* new_shell = new_shell_observer.GetShell();
ASSERT_NE(new_shell->web_contents(), shell()->web_contents());
@@ -868,7 +862,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, SubframeOnEmptyPage) {
std::string script = "var iframe = document.createElement('iframe');"
"iframe.src = 'data:text/html,<p>some page</p>';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(new_root, script));
+ EXPECT_TRUE(ExecJs(new_root, script));
capturer.Wait();
}
ASSERT_EQ(1U, new_root->child_count());
@@ -879,8 +873,8 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, SubframeOnEmptyPage) {
"foo.com", "/navigation_controller/simple_page_2.html");
{
LoadCommittedCapturer capturer(new_shell->web_contents());
- std::string script = "location.assign('" + frame_url.spec() + "')";
- EXPECT_TRUE(ExecuteScript(new_root->child_at(0), script));
+ std::string script = JsReplace("location.assign($1);", frame_url);
+ EXPECT_TRUE(ExecJs(new_root->child_at(0), script));
capturer.Wait();
}
@@ -896,7 +890,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, SubframeOnEmptyPage) {
std::string script = "var iframe = document.createElement('iframe');"
"iframe.src = '" + grandchild_url.spec() + "';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(new_root->child_at(0), script));
+ EXPECT_TRUE(ExecJs(new_root->child_at(0), script));
capturer.Wait();
}
ASSERT_EQ(1U, new_root->child_at(0)->child_count());
@@ -917,7 +911,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Pop open a new window to about:blank.
ShellAddedObserver new_shell_observer;
- EXPECT_TRUE(ExecuteScript(root, "var w = window.open('about:blank')"));
+ EXPECT_TRUE(ExecJs(root, "var w = window.open('about:blank')"));
Shell* new_shell = new_shell_observer.GetShell();
ASSERT_NE(new_shell->web_contents(), shell()->web_contents());
FrameTreeNode* new_root =
@@ -930,10 +924,12 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Make a new iframe in it using document.write from the opener.
{
LoadCommittedCapturer capturer(new_shell->web_contents());
- std::string script = "w.document.write("
- "\"<iframe src='" + url1.spec() + "'></iframe>\");"
- "w.document.close();";
- EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script));
+ std::string html = "<iframe src='" + url1.spec() + "'></iframe>";
+ std::string script = JsReplace(
+ "w.document.write($1);"
+ "w.document.close();",
+ html);
+ EXPECT_TRUE(ExecJs(root->current_frame_host(), script));
capturer.Wait();
}
ASSERT_EQ(1U, new_root->child_count());
@@ -946,7 +942,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
{
LoadCommittedCapturer capturer(new_root->child_at(0));
std::string script = "location.href = '" + url2.spec() + "';";
- EXPECT_TRUE(ExecuteScript(new_root->child_at(0), script));
+ EXPECT_TRUE(ExecJs(new_root->child_at(0), script));
capturer.Wait();
}
EXPECT_EQ(blank_url, new_root->current_url());
@@ -958,7 +954,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
{
LoadCommittedCapturer capturer(new_root);
std::string script = "history.replaceState({}, 'foo', 'foo');";
- EXPECT_TRUE(ExecuteScript(new_root, script));
+ EXPECT_TRUE(ExecJs(new_root, script));
capturer.Wait();
}
EXPECT_EQ(embedded_test_server()->GetURL("/navigation_controller/foo"),
@@ -1093,7 +1089,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Load via a fragment link click.
FrameNavigateParamsCapturer capturer(root);
std::string script = "document.getElementById('fraglink').click()";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_LINK));
@@ -1105,7 +1101,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Load via link click.
FrameNavigateParamsCapturer capturer(root);
std::string script = "document.getElementById('thelink').click()";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_LINK));
@@ -1118,8 +1114,8 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
FrameNavigateParamsCapturer capturer(root);
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
- std::string script = "location.assign('" + frame_url.spec() + "')";
- EXPECT_TRUE(ExecuteScript(root, script));
+ std::string script = JsReplace("location.assign($1);", frame_url);
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
@@ -1134,7 +1130,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
FrameNavigateParamsCapturer capturer(root);
std::string script =
"history.pushState({}, 'page 1', 'simple_page_1.html')";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
@@ -1148,8 +1144,8 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
FrameNavigateParamsCapturer capturer(root);
GURL frame_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_1.html"));
- std::string script = "location.replace('" + frame_url.spec() + "')";
- EXPECT_TRUE(ExecuteScript(root, script));
+ std::string script = JsReplace("location.replace($1);", frame_url);
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
@@ -1206,7 +1202,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
{
// Back from the renderer side.
FrameNavigateParamsCapturer capturer(root);
- EXPECT_TRUE(ExecuteScript(root, "history.back()"));
+ EXPECT_TRUE(ExecJs(root, "history.back()"));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
@@ -1220,7 +1216,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
{
// Forward from the renderer side.
FrameNavigateParamsCapturer capturer(root);
- EXPECT_TRUE(ExecuteScript(root, "history.forward()"));
+ EXPECT_TRUE(ExecJs(root, "history.forward()"));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
@@ -1234,7 +1230,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
{
// Back from the renderer side via history.go().
FrameNavigateParamsCapturer capturer(root);
- EXPECT_TRUE(ExecuteScript(root, "history.go(-1)"));
+ EXPECT_TRUE(ExecJs(root, "history.go(-1)"));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
@@ -1248,7 +1244,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
{
// Forward from the renderer side via history.go().
FrameNavigateParamsCapturer capturer(root);
- EXPECT_TRUE(ExecuteScript(root, "history.go(1)"));
+ EXPECT_TRUE(ExecJs(root, "history.go(1)"));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
@@ -1273,7 +1269,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
{
// Reload from the renderer side.
FrameNavigateParamsCapturer capturer(root);
- EXPECT_TRUE(ExecuteScript(root, "location.reload()"));
+ EXPECT_TRUE(ExecJs(root, "location.reload()"));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
@@ -1288,8 +1284,8 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
FrameNavigateParamsCapturer capturer(root);
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
- std::string script = "location.replace('" + frame_url.spec() + "')";
- EXPECT_TRUE(ExecuteScript(root, script));
+ std::string script = JsReplace("location.replace($1);", frame_url);
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
@@ -1322,7 +1318,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
FrameNavigateParamsCapturer capturer(root);
std::string script =
"history.replaceState({}, 'page 2', 'simple_page_2.html')";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
@@ -1338,7 +1334,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
"/navigation_controller/page_with_links.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_links));
std::string script = "document.getElementById('fraglink').click()";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
{
@@ -1372,7 +1368,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
EXPECT_TRUE(NavigateToURL(shell(), url1));
script = "history.pushState({}, 'page 2', 'simple_page_2.html')";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
{
@@ -1434,11 +1430,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, ReloadWithUrlAnchor) {
"/navigation_controller/reload-with-url-anchor.html#center-element"));
EXPECT_TRUE(NavigateToURL(shell(), url));
- double window_scroll_y = 0;
- std::string get_window_scroll_y =
- "domAutomationController.send(window.scrollY);";
- EXPECT_TRUE(ExecuteScriptAndExtractDouble(shell(), get_window_scroll_y,
- &window_scroll_y));
+ double window_scroll_y = EvalJs(shell(), "window.scrollY").ExtractDouble();
// The 'center-element' y-position is 2000px. 2000px is an arbitrary value.
double expected_window_scroll_y = 2000;
@@ -1456,8 +1448,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, ReloadWithUrlAnchor) {
// Reload.
ReloadBlockUntilNavigationsComplete(shell(), 1);
- EXPECT_TRUE(ExecuteScriptAndExtractDouble(shell(), get_window_scroll_y,
- &window_scroll_y));
+ window_scroll_y = EvalJs(shell(), "window.scrollY").ExtractDouble();
EXPECT_FLOAT_EQ(expected_window_scroll_y, window_scroll_y);
}
@@ -1474,11 +1465,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
std::string script_scroll_down = "window.scroll(0, 2100)";
EXPECT_TRUE(ExecuteScript(shell(), script_scroll_down));
- std::string get_window_scroll_y =
- "domAutomationController.send(window.scrollY)";
- double window_scroll_y = 0;
- EXPECT_TRUE(ExecuteScriptAndExtractDouble(shell(), get_window_scroll_y,
- &window_scroll_y));
+ double window_scroll_y = EvalJs(shell(), "window.scrollY").ExtractDouble();
double expected_window_scroll_y = 2100;
if (IsUseZoomForDSFEnabled()) {
@@ -1495,8 +1482,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Reload.
ReloadBlockUntilNavigationsComplete(shell(), 1);
- EXPECT_TRUE(ExecuteScriptAndExtractDouble(shell(), get_window_scroll_y,
- &window_scroll_y));
+ window_scroll_y = EvalJs(shell(), "window.scrollY").ExtractDouble();
EXPECT_FLOAT_EQ(expected_window_scroll_y, window_scroll_y);
}
@@ -1599,7 +1585,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Load via a fragment link click.
FrameNavigateParamsCapturer capturer(root->child_at(0));
std::string script = "document.getElementById('fraglink').click()";
- EXPECT_TRUE(ExecuteScript(root->child_at(0), script));
+ EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
@@ -1611,8 +1597,8 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
FrameNavigateParamsCapturer capturer(root->child_at(0));
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
- std::string script = "location.assign('" + frame_url.spec() + "')";
- EXPECT_TRUE(ExecuteScript(root->child_at(0), script));
+ std::string script = JsReplace("location.assign($1);", frame_url);
+ EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
@@ -1624,8 +1610,8 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
LoadCommittedCapturer capturer(root->child_at(0));
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
- std::string script = "location.replace('" + frame_url.spec() + "')";
- EXPECT_TRUE(ExecuteScript(root->child_at(0), script));
+ std::string script = JsReplace("location.replace($1);", frame_url);
+ EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -1636,7 +1622,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
FrameNavigateParamsCapturer capturer(root->child_at(0));
std::string script =
"history.pushState({}, 'page 1', 'simple_page_1.html')";
- EXPECT_TRUE(ExecuteScript(root->child_at(0), script));
+ EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
@@ -1648,7 +1634,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
LoadCommittedCapturer capturer(root->child_at(0));
std::string script =
"history.replaceState({}, 'page 2', 'simple_page_2.html')";
- EXPECT_TRUE(ExecuteScript(root->child_at(0), script));
+ EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -1657,7 +1643,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
{
// Reload.
LoadCommittedCapturer capturer(root->child_at(0));
- EXPECT_TRUE(ExecuteScript(root->child_at(0), "location.reload()"));
+ EXPECT_TRUE(ExecJs(root->child_at(0), "location.reload()"));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -1671,7 +1657,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
std::string script = "var iframe = document.createElement('iframe');"
"iframe.src = '" + frame_url.spec() + "';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -1729,7 +1715,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Do a fragment link click.
FrameNavigateParamsCapturer capturer(root);
std::string script = "document.getElementById('fraglink').click()";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_LINK));
@@ -1741,7 +1727,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Do a non-fragment link click.
FrameNavigateParamsCapturer capturer(root);
std::string script = "document.getElementById('thelink').click()";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_LINK));
@@ -1768,7 +1754,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Do a fragment link click.
FrameNavigateParamsCapturer capturer(root->child_at(0));
std::string script = "document.getElementById('fraglink').click()";
- EXPECT_TRUE(ExecuteScript(root->child_at(0), script));
+ EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
@@ -1780,7 +1766,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Do a non-fragment link click.
FrameNavigateParamsCapturer capturer(root->child_at(0));
std::string script = "document.getElementById('thelink').click()";
- EXPECT_TRUE(ExecuteScript(root->child_at(0), script));
+ EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
@@ -1809,7 +1795,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
LoadCommittedCapturer capturer(shell()->web_contents());
std::string script = "var iframe = document.createElement('iframe');"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -1836,7 +1822,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
LoadCommittedCapturer capturer(shell()->web_contents());
std::string script = "var iframe = document.createElement('iframe');"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root->child_at(0), script));
+ EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -1855,7 +1841,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
std::string script = "var iframe = document.createElement('iframe');"
"iframe.src = 'about:blank';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -1877,9 +1863,11 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
"/navigation_controller/simple_page_1.html"));
{
LoadCommittedCapturer capturer(root->child_at(0)->child_at(0));
- std::string script = "var frames = document.getElementsByTagName('iframe');"
- "frames[0].src = '" + frame_url.spec() + "';";
- EXPECT_TRUE(ExecuteScript(root->child_at(0), script));
+ std::string script = JsReplace(
+ "var frames = document.getElementsByTagName('iframe');"
+ "frames[0].src = $1;",
+ frame_url);
+ EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -1903,9 +1891,11 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
"foo.com", "/navigation_controller/simple_page_2.html"));
{
LoadCommittedCapturer capturer(root->child_at(1));
- std::string script = "var frames = document.getElementsByTagName('iframe');"
- "frames[1].src = '" + foo_url.spec() + "';";
- EXPECT_TRUE(ExecuteScript(root, script));
+ std::string script = JsReplace(
+ "var frames = document.getElementsByTagName('iframe');"
+ "frames[1].src = $1;",
+ foo_url);
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -1930,7 +1920,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
LoadCommittedCapturer capturer(root->child_at(0)->child_at(0));
std::string script = "var frames = document.getElementsByTagName('iframe');"
"frames[0].src = 'about:blank';";
- EXPECT_TRUE(ExecuteScript(root->child_at(0), script));
+ EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
@@ -1980,12 +1970,12 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
GURL slow_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
TestNavigationManager subframe_delayer(shell()->web_contents(), slow_url);
- {
- std::string script = "var iframe = document.createElement('iframe');"
- "iframe.src = '" + slow_url.spec() + "';"
- "document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root, script));
- }
+ std::string script_template =
+ "var iframe = document.createElement('iframe');"
+ "iframe.src = $1;"
+ "document.body.appendChild(iframe);";
+
+ EXPECT_TRUE(ExecJs(root, JsReplace(script_template, slow_url)));
EXPECT_TRUE(subframe_delayer.WaitForRequestStart());
// Stop the request so that we can wait for load stop below, without ending up
@@ -1995,13 +1985,8 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// 2. A nested iframe with a cross-site URL should be able to commit.
GURL foo_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_1.html"));
- {
- std::string script = "var iframe = document.createElement('iframe');"
- "iframe.src = '" + foo_url.spec() + "';"
- "document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root->child_at(0), script));
- WaitForLoadStopWithoutSuccessCheck(shell()->web_contents());
- }
+ EXPECT_TRUE(ExecJs(root->child_at(0), JsReplace(script_template, foo_url)));
+ WaitForLoadStopWithoutSuccessCheck(shell()->web_contents());
// TODO(creis): Check subframe entries once we create them in this case.
// See https://crbug.com/608402.
@@ -2028,7 +2013,7 @@ IN_PROC_BROWSER_TEST_F(
std::string script = "var iframe = document.createElement('iframe');"
"iframe.src = '" + no_commit_url.spec() + "';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
}
EXPECT_EQ(GURL(), root->child_at(0)->current_url());
@@ -2040,7 +2025,7 @@ IN_PROC_BROWSER_TEST_F(
std::string script = "var iframe = document.createElement('iframe');"
"iframe.src = '" + foo_url.spec() + "';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root->child_at(0), script));
+ EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -2068,7 +2053,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
{
FrameNavigateParamsCapturer capturer(root);
std::string script = "history.pushState({}, 'foo', 'foo')";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
EXPECT_TRUE(capturer.is_same_document());
@@ -2082,7 +2067,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
std::string script = "var iframe = document.createElement('iframe');"
"iframe.src = '" + child_url.spec() + "';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -2103,7 +2088,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
std::string script = "var iframe = document.createElement('iframe');"
"iframe.src = '" + grandchild_url.spec() + "';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root->child_at(0), script));
+ EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -2134,14 +2119,14 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
std::string script = "var iframe = document.createElement('iframe');"
"iframe.src = '" + child_url.spec() + "';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
// 2. Change the iframe's name.
- EXPECT_TRUE(ExecuteScript(root->child_at(0), "window.name = 'foo';"));
+ EXPECT_TRUE(ExecJs(root->child_at(0), "window.name = 'foo';"));
// 3. A nested iframe with a cross-site URL should be able to commit.
GURL bar_url(embedded_test_server()->GetURL(
@@ -2151,7 +2136,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
std::string script = "var iframe = document.createElement('iframe');"
"iframe.src = '" + bar_url.spec() + "';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root->child_at(0), script));
+ EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
@@ -2186,7 +2171,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
std::string script = "var iframe = document.createElement('iframe');"
"iframe.src = '" + frame_url.spec() + "';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -2215,7 +2200,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
std::string script = "var iframe = document.createElement('iframe');"
"iframe.src = '" + foo_url.spec() + "';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -2241,7 +2226,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
std::string script = "var iframe = document.createElement('iframe');"
"iframe.src = '" + foo_url.spec() + "';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root->child_at(1), script));
+ EXPECT_TRUE(ExecJs(root->child_at(1), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -2267,7 +2252,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
std::string script = "var iframe = document.createElement('iframe');"
"iframe.src = '" + foo_url.spec() + "';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -2292,7 +2277,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
"iframe.src = '" + frame_url.spec() + "';"
"document.body.appendChild(iframe);";
FrameTreeNode* child = root->child_at(2);
- EXPECT_TRUE(ExecuteScript(child, script));
+ EXPECT_TRUE(ExecJs(child, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -2349,7 +2334,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
std::string script = "var iframe = document.createElement('iframe');"
"iframe.src = '" + frame_url.spec() + "';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
}
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
@@ -2387,7 +2372,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
std::string script = "var iframe = document.createElement('iframe');"
"iframe.src = '" + foo_url.spec() + "';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
}
@@ -2398,7 +2383,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
std::string script = "var iframe = document.createElement('iframe');"
"iframe.src = '" + foo_url.spec() + "';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root->child_at(1), script));
+ EXPECT_TRUE(ExecJs(root->child_at(1), script));
capturer.Wait();
}
GURL bar_url(embedded_test_server()->GetURL(
@@ -2443,7 +2428,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
root->child_at(1)->current_frame_host());
std::string script = "var frames = document.getElementsByTagName('iframe');"
"frames[1].src = '" + baz_url.spec() + "';";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
// Wait for the RenderFrame to go away, if this will be cross-process.
if (AreAllSitesIsolatedForTesting())
deleted_observer.WaitUntilDeleted();
@@ -2513,7 +2498,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// 2. Same document navigation in the main frame.
std::string push_script = "history.pushState({}, 'page 2', 'page_2.html')";
- EXPECT_TRUE(ExecuteScript(root, push_script));
+ EXPECT_TRUE(ExecJs(root, push_script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
// The entry should have a FrameNavigationEntry for the subframe.
@@ -2527,7 +2512,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
std::string script = "var iframe = document.createElement('iframe');"
"iframe.src = '" + subframe_url.spec() + "';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root->child_at(0), script));
+ EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -2564,7 +2549,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
std::string script = "var iframe = document.createElement('iframe');"
"iframe.src = '" + frame_url.spec() + "';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
}
NavigationEntryImpl* entry1 = controller.GetLastCommittedEntry();
@@ -2810,7 +2795,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
->frame_entry->document_sequence_number());
// Inject a JS value so that we can check for it later.
- EXPECT_TRUE(content::ExecuteScript(root, "foo=3;"));
+ EXPECT_TRUE(ExecJs(root, "foo=3;"));
// 7. Go back again, to the data URL in the nested iframe.
{
@@ -2836,12 +2821,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
entry3->root_node()->children[0]->children[0]->frame_entry->url());
// Verify that we did not reload the main frame. See https://crbug.com/586234.
- {
- int value = 0;
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- root, "domAutomationController.send(foo)", &value));
- EXPECT_EQ(3, value);
- }
+ EXPECT_EQ(3, EvalJs(root, "foo"));
// 8. Go back again, to the data URL in the first subframe.
{
@@ -3104,14 +3084,8 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
EXPECT_EQ(blank_url, root->child_at(0)->current_url());
// Verify that the parent was able to script the iframe.
- std::string expected_text("Injected text");
- {
- std::string value;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- root->child_at(0),
- "domAutomationController.send(document.body.innerHTML)", &value));
- EXPECT_EQ(expected_text, value);
- }
+ EXPECT_EQ("Injected text",
+ EvalJs(root->child_at(0), "document.body.innerHTML"));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
@@ -3142,13 +3116,8 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
EXPECT_EQ(blank_url, root->child_at(0)->current_url());
// Verify that the parent was able to script the iframe.
- {
- std::string value;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- root->child_at(0),
- "domAutomationController.send(document.body.innerHTML)", &value));
- EXPECT_EQ(expected_text, value);
- }
+ EXPECT_EQ("Injected text",
+ EvalJs(root->child_at(0), "document.body.innerHTML"));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
@@ -3197,9 +3166,8 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
entry->root_node()->children[0]->children[0]->frame_entry->url());
// Set a value in the form which will be stored in the PageState.
- EXPECT_TRUE(
- ExecuteScript(root->child_at(0)->child_at(0),
- "document.getElementById('itext').value = 'modified';"));
+ EXPECT_TRUE(ExecJs(root->child_at(0)->child_at(0),
+ "document.getElementById('itext').value = 'modified';"));
// 2. Navigate the main frame same-site, destroying the subframes.
GURL main_url_2(embedded_test_server()->GetURL(
@@ -3241,13 +3209,8 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// With injected about:blank iframes, we never restore form values from
// PageState.
- std::string form_value = "fail";
- EXPECT_TRUE(
- ExecuteScriptAndExtractString(root->child_at(0)->child_at(0),
- "window.domAutomationController.send("
- "document.getElementById('itext').value);",
- &form_value));
- EXPECT_EQ("", form_value);
+ EXPECT_EQ("", EvalJs(root->child_at(0)->child_at(0),
+ "document.getElementById('itext').value"));
}
// Verify that we correctly load a nested iframe created by an injected iframe
@@ -3295,9 +3258,8 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
entry->root_node()->children[0]->children[0]->frame_entry->url());
// Set a value in the form which will be stored in the PageState.
- EXPECT_TRUE(
- ExecuteScript(root->child_at(0)->child_at(0),
- "document.getElementById('itext').value = 'modified';"));
+ EXPECT_TRUE(ExecJs(root->child_at(0)->child_at(0),
+ "document.getElementById('itext').value = 'modified';"));
// 2. Navigate the main frame same-site, destroying the subframes.
GURL main_url_2(embedded_test_server()->GetURL(
@@ -3347,13 +3309,8 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Note that restoring form values in srcdoc frames created via static html is
// expected to work and is tested by
// RenderFrameHostManagerTest.RestoreSubframeFileAccessForHistoryNavigation.
- std::string form_value = "fail";
- EXPECT_TRUE(
- ExecuteScriptAndExtractString(root->child_at(0)->child_at(0),
- "window.domAutomationController.send("
- "document.getElementById('itext').value);",
- &form_value));
- EXPECT_EQ("", form_value);
+ EXPECT_EQ("", EvalJs(root->child_at(0)->child_at(0),
+ "document.getElementById('itext').value"));
}
// Verify that we can load about:blank in an iframe when going back to a page,
@@ -3461,7 +3418,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
EXPECT_EQ(main_url, root->current_url());
// Check that the renderer is still alive.
- EXPECT_TRUE(ExecuteScript(shell(), "console.log('Success');"));
+ EXPECT_TRUE(ExecJs(shell(), "console.log('Success');"));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
@@ -3531,7 +3488,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
TestNavigationObserver observer(shell()->web_contents());
std::string script = "history.replaceState({}, '', '/server-redirect?" +
frame_redirect_dest_url.spec() + "')";
- EXPECT_TRUE(ExecuteScript(root->child_at(0), script));
+ EXPECT_TRUE(ExecJs(root->child_at(0), script));
observer.Wait();
}
@@ -3587,7 +3544,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
TestNavigationObserver observer(shell()->web_contents());
std::string script = "history.replaceState({}, '', '/server-redirect?" +
frame_redirect_dest_url.spec() + "')";
- EXPECT_TRUE(ExecuteScript(root->child_at(1), script));
+ EXPECT_TRUE(ExecJs(root->child_at(1), script));
observer.Wait();
}
@@ -3635,7 +3592,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
TestNavigationObserver observer(shell()->web_contents());
std::string script = "history.replaceState({}, '', '/server-redirect?" +
redirect_dest_url.spec() + "')";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
observer.Wait();
}
@@ -3703,7 +3660,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
TestNavigationObserver observer(shell()->web_contents());
std::string script = "history.replaceState({}, '', '/server-redirect?" +
frame_redirect_dest_url.spec() + "')";
- EXPECT_TRUE(ExecuteScript(root->child_at(0), script));
+ EXPECT_TRUE(ExecJs(root->child_at(0), script));
observer.Wait();
}
@@ -3752,7 +3709,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
TestNavigationObserver observer(shell()->web_contents());
std::string script = "history.replaceState({}, '', '/server-redirect?" +
redirect_dest_url.spec() + "')";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
observer.Wait();
}
@@ -3943,14 +3900,8 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
EXPECT_EQ(blank_url, new_entry->root_node()->children[0]->frame_entry->url());
// Verify that the parent was able to script the iframe.
- std::string expected_text("Injected text");
- {
- std::string value;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- root->child_at(0),
- "domAutomationController.send(document.body.innerHTML)", &value));
- EXPECT_EQ(expected_text, value);
- }
+ EXPECT_EQ("Injected text",
+ EvalJs(root->child_at(0), "document.body.innerHTML"));
}
// Verifies that the |frame_unique_name| is set to the correct frame, so that we
@@ -3983,7 +3934,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
std::string script = "var iframe = document.createElement('iframe');"
"iframe.src = '" + url.spec() + "';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -4009,7 +3960,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
"iframe.src = '" + url.spec() + "';"
"iframe.name = 'foo';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -4489,7 +4440,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, CloneNamedWindow) {
EXPECT_TRUE(NavigateToURL(shell(), url_1));
// Name the window.
- EXPECT_TRUE(ExecuteScript(shell(), "window.name = 'foo';"));
+ EXPECT_TRUE(ExecJs(shell(), "window.name = 'foo';"));
// Navigate it.
GURL url_2(embedded_test_server()->GetURL(
@@ -4520,7 +4471,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
EXPECT_TRUE(NavigateToURL(shell(), url_1));
// Name the window.
- EXPECT_TRUE(ExecuteScript(shell(), "window.name = 'foo';"));
+ EXPECT_TRUE(ExecJs(shell(), "window.name = 'foo';"));
// Navigate it.
GURL url_2(embedded_test_server()->GetURL(
@@ -4528,7 +4479,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
EXPECT_TRUE(NavigateToURL(shell(), url_2));
// Clear the name.
- EXPECT_TRUE(ExecuteScript(shell(), "window.name = '';"));
+ EXPECT_TRUE(ExecJs(shell(), "window.name = '';"));
// Navigate it again.
EXPECT_TRUE(NavigateToURL(shell(), url_1));
@@ -4637,7 +4588,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
"document.body.appendChild(iframe);";
{
LoadCommittedCapturer capturer(shell()->web_contents());
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -4666,7 +4617,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// 4. Add the iframe again.
{
LoadCommittedCapturer capturer(shell()->web_contents());
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -4702,7 +4653,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// 2. Do a same document fragment navigation.
std::string script = "document.getElementById('fraglink').click()";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
frame_entry = controller.GetLastCommittedEntry()->GetFrameEntry(root);
@@ -4718,7 +4669,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
std::string add_script = "var iframe = document.createElement('iframe');"
"iframe.src = '" + url.spec() + "';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root, add_script));
+ EXPECT_TRUE(ExecJs(root, add_script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
@@ -4739,7 +4690,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
EXPECT_NE(dsn_2, dsn_3);
// 4. Do a same document fragment navigation in the subframe.
- EXPECT_TRUE(ExecuteScript(subframe, script));
+ EXPECT_TRUE(ExecJs(subframe, script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
subframe_entry = controller.GetLastCommittedEntry()->GetFrameEntry(subframe);
@@ -4977,7 +4928,7 @@ void DoReplaceStateWhilePending(Shell* shell,
capturer.set_wait_for_load(false);
std::string script =
"history.replaceState({}, '', '" + replace_state_filename + "')";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
// The fact that there was a pending entry shouldn't interfere with the
@@ -5070,7 +5021,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
FrameNavigateParamsCapturer capturer(root);
capturer.set_wait_for_load(false);
std::string script = "history.pushState({}, '', 'pushed')";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
EXPECT_TRUE(capturer.is_same_document());
@@ -5107,7 +5058,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Go to the second page.
std::string script = "document.getElementById('thelink').click()";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
@@ -5176,7 +5127,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// location.replace() to cause an inert commit.
TestNavigationObserver replace_load_observer(shell()->web_contents());
std::string script = "location.replace('" + url3.spec() + "')";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
replace_load_observer.Wait();
}
@@ -5258,7 +5209,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
FrameNavigateParamsCapturer capturer(root);
std::string script =
"history.replaceState({}, 'replaced', 'replaced')";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
}
@@ -5387,6 +5338,11 @@ class RenderProcessKilledObserver : public WebContentsObserver {
// not modify the underlying last committed entry.) Not crashing means that
// the test is successful.
IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, ReloadOriginalRequest) {
+ // TODO(lukasza): https://crbug.com/417518: Get tests working with
+ // --site-per-process.
+ if (SiteIsolationPolicy::UseDedicatedProcessesForAllSites())
+ return;
+
GURL original_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), original_url));
@@ -5401,7 +5357,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, ReloadOriginalRequest) {
{
std::string script = "location.replace('" + redirect_url.spec() + "');";
FrameNavigateParamsCapturer capturer(root);
- EXPECT_TRUE(ExecuteScript(shell(), script));
+ EXPECT_TRUE(ExecJs(shell(), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
@@ -5443,7 +5399,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, ReloadOriginalRequest) {
}
// Make sure the renderer is still alive.
- EXPECT_TRUE(ExecuteScript(shell(), "console.log('Success');"));
+ EXPECT_TRUE(ExecJs(shell(), "console.log('Success');"));
}
// This test shows that the initial "about:blank" URL is elided from the
@@ -5466,7 +5422,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
->root();
EXPECT_EQ(1, controller.GetEntryCount());
- EXPECT_EQ(1, RendererHistoryLength(shell()));
+ EXPECT_EQ(1, EvalJs(shell(), "history.length"));
// Add an iframe with no 'src'.
@@ -5474,11 +5430,11 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
"var iframe = document.createElement('iframe');"
"iframe.id = 'frame';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(1, controller.GetEntryCount());
- EXPECT_EQ(1, RendererHistoryLength(shell()));
+ EXPECT_EQ(1, EvalJs(shell(), "history.length"));
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
ASSERT_EQ(1U, root->child_count());
@@ -5492,11 +5448,11 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// "about:blank" as the URL in the iframe.
script = "history.pushState({}, '', 'notarealurl.html')";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetEntryCount());
- EXPECT_EQ(2, RendererHistoryLength(shell()));
+ EXPECT_EQ(2, EvalJs(shell(), "history.length"));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
// Load the iframe; the initial "about:blank" URL should be elided and thus we
@@ -5508,7 +5464,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetEntryCount());
- EXPECT_EQ(2, RendererHistoryLength(shell()));
+ EXPECT_EQ(2, EvalJs(shell(), "history.length"));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(frame_url, frame->current_url());
@@ -5522,7 +5478,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
}
EXPECT_EQ(2, controller.GetEntryCount());
- EXPECT_EQ(2, RendererHistoryLength(shell()));
+ EXPECT_EQ(2, EvalJs(shell(), "history.length"));
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
// There is some open discussion over whether this should send the iframe
@@ -5540,11 +5496,11 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Do a same document navigation in the subframe.
std::string fragment_script = "location.href = \"#foo\";";
- EXPECT_TRUE(ExecuteScript(frame->current_frame_host(), fragment_script));
+ EXPECT_TRUE(ExecJs(frame->current_frame_host(), fragment_script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetEntryCount());
- EXPECT_EQ(2, RendererHistoryLength(shell()));
+ EXPECT_EQ(2, EvalJs(shell(), "history.length"));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
GURL frame_url_2 = embedded_test_server()->GetURL(
@@ -5561,7 +5517,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Verify the process is still alive by running script. We can't just call
// IsRenderFrameLive after the navigation since it might not have disconnected
// yet.
- EXPECT_TRUE(ExecuteScript(root->current_frame_host(), "true;"));
+ EXPECT_TRUE(ExecJs(root->current_frame_host(), "true;"));
EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
// TODO(creis): We should probably go back to frame_url here instead of the
@@ -5588,7 +5544,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
->root();
EXPECT_EQ(1, controller.GetEntryCount());
- EXPECT_EQ(1, RendererHistoryLength(shell()));
+ EXPECT_EQ(1, EvalJs(shell(), "history.length"));
// Add an iframe with a 'src'.
@@ -5599,11 +5555,11 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
"iframe.src = '" + frame_url_1.spec() + "';"
"iframe.id = 'frame';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(1, controller.GetEntryCount());
- EXPECT_EQ(1, RendererHistoryLength(shell()));
+ EXPECT_EQ(1, EvalJs(shell(), "history.length"));
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
ASSERT_EQ(1U, root->child_count());
@@ -5616,11 +5572,11 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// old navigation entry has frame_url_1 as the URL in the iframe.
script = "document.getElementById('fraglink').click()";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetEntryCount());
- EXPECT_EQ(2, RendererHistoryLength(shell()));
+ EXPECT_EQ(2, EvalJs(shell(), "history.length"));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(frame_url_1, frame->current_url());
@@ -5634,7 +5590,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(3, controller.GetEntryCount());
- EXPECT_EQ(3, RendererHistoryLength(shell()));
+ EXPECT_EQ(3, EvalJs(shell(), "history.length"));
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(frame_url_2, frame->current_url());
@@ -5648,7 +5604,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
}
EXPECT_EQ(3, controller.GetEntryCount());
- EXPECT_EQ(3, RendererHistoryLength(shell()));
+ EXPECT_EQ(3, EvalJs(shell(), "history.length"));
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
// There is some open discussion over whether this should send the iframe back
@@ -5666,11 +5622,11 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Do a same document navigation in the subframe.
std::string fragment_script = "location.href = \"#foo\";";
- EXPECT_TRUE(ExecuteScript(frame->current_frame_host(), fragment_script));
+ EXPECT_TRUE(ExecJs(frame->current_frame_host(), fragment_script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetEntryCount());
- EXPECT_EQ(2, RendererHistoryLength(shell()));
+ EXPECT_EQ(2, EvalJs(shell(), "history.length"));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
// Go back.
@@ -5683,7 +5639,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Verify the process is still alive by running script. We can't just call
// IsRenderFrameLive after the navigation since it might not have disconnected
// yet.
- EXPECT_TRUE(ExecuteScript(root->current_frame_host(), "true;"));
+ EXPECT_TRUE(ExecJs(root->current_frame_host(), "true;"));
EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
// TODO(creis): It's a bit surprising to go to frame_url_1 here instead of
@@ -5713,7 +5669,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
->root();
EXPECT_EQ(1, controller.GetEntryCount());
- EXPECT_EQ(1, RendererHistoryLength(shell()));
+ EXPECT_EQ(1, EvalJs(shell(), "history.length"));
// Add an iframe with a 'src'.
@@ -5724,11 +5680,11 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
"iframe.src = '" + frame_url_1.spec() + "';"
"iframe.id = 'frame';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script));
+ EXPECT_TRUE(ExecJs(root->current_frame_host(), script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(1, controller.GetEntryCount());
- EXPECT_EQ(1, RendererHistoryLength(shell()));
+ EXPECT_EQ(1, EvalJs(shell(), "history.length"));
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
ASSERT_EQ(1U, root->child_count());
@@ -5741,19 +5697,19 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
GURL frame_url_2 = embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html#foo");
std::string fragment_script = "location.href = \"#foo\";";
- EXPECT_TRUE(ExecuteScript(frame->current_frame_host(), fragment_script));
+ EXPECT_TRUE(ExecJs(frame->current_frame_host(), fragment_script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetEntryCount());
- EXPECT_EQ(2, RendererHistoryLength(shell()));
+ EXPECT_EQ(2, EvalJs(shell(), "history.length"));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(frame_url_2, frame->current_url());
// Do a fragment navigation at the top level.
std::string link_script = "document.getElementById('fraglink').click()";
- EXPECT_TRUE(ExecuteScript(root->current_frame_host(), link_script));
+ EXPECT_TRUE(ExecJs(root->current_frame_host(), link_script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(3, controller.GetEntryCount());
- EXPECT_EQ(3, RendererHistoryLength(shell()));
+ EXPECT_EQ(3, EvalJs(shell(), "history.length"));
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(frame_url_2, frame->current_url());
@@ -5763,7 +5719,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
NavigateFrameToURL(frame, frame_url_3);
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(4, controller.GetEntryCount());
- EXPECT_EQ(4, RendererHistoryLength(shell()));
+ EXPECT_EQ(4, EvalJs(shell(), "history.length"));
EXPECT_EQ(3, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(frame_url_3, frame->current_url());
@@ -5775,7 +5731,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
observer.Wait();
}
EXPECT_EQ(4, controller.GetEntryCount());
- EXPECT_EQ(4, RendererHistoryLength(shell()));
+ EXPECT_EQ(4, EvalJs(shell(), "history.length"));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(links_url, root->current_url());
@@ -5802,7 +5758,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Verify the process is still alive by running script. We can't just call
// IsRenderFrameLive after the navigation since it might not have disconnected
// yet.
- EXPECT_TRUE(ExecuteScript(root->current_frame_host(), "true;"));
+ EXPECT_TRUE(ExecJs(root->current_frame_host(), "true;"));
EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
// TODO(creis): It's a bit surprising to go to frame_url_1 here instead of
@@ -5826,7 +5782,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
->root();
EXPECT_EQ(1, controller.GetEntryCount());
- EXPECT_EQ(1, RendererHistoryLength(shell()));
+ EXPECT_EQ(1, EvalJs(shell(), "history.length"));
// Add an iframe with no 'src'.
GURL blank_url(url::kAboutBlankURL);
@@ -5834,10 +5790,10 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
"var iframe = document.createElement('iframe');"
"iframe.id = 'frame';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script));
+ EXPECT_TRUE(ExecJs(root->current_frame_host(), script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(1, controller.GetEntryCount());
- EXPECT_EQ(1, RendererHistoryLength(shell()));
+ EXPECT_EQ(1, EvalJs(shell(), "history.length"));
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
ASSERT_EQ(1U, root->child_count());
FrameTreeNode* frame = root->child_at(0);
@@ -5850,17 +5806,17 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
"iframe.contentWindow.document.write("
" \"<a id='fraglink' href='#frag'>fragment link</a>\");"
"iframe.contentWindow.document.close();";
- EXPECT_TRUE(ExecuteScript(root->current_frame_host(), document_write_script));
+ EXPECT_TRUE(ExecJs(root->current_frame_host(), document_write_script));
// Click the link to do a same document navigation. Due to the
// document.write, the new URL matches the parent frame's URL.
GURL frame_url_2(embedded_test_server()->GetURL(
"/navigation_controller/page_with_links.html#frag"));
std::string link_script = "document.getElementById('fraglink').click()";
- EXPECT_TRUE(ExecuteScript(frame->current_frame_host(), link_script));
+ EXPECT_TRUE(ExecJs(frame->current_frame_host(), link_script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetEntryCount());
- EXPECT_EQ(2, RendererHistoryLength(shell()));
+ EXPECT_EQ(2, EvalJs(shell(), "history.length"));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(frame_url_2, frame->current_url());
@@ -5874,7 +5830,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Verify the process is still alive by running script. We can't just call
// IsRenderFrameLive after the navigation since it might not have disconnected
// yet.
- EXPECT_TRUE(ExecuteScript(root->current_frame_host(), "true;"));
+ EXPECT_TRUE(ExecJs(root->current_frame_host(), "true;"));
EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
EXPECT_EQ(blank_url, frame->current_url());
@@ -5896,7 +5852,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
->root();
EXPECT_EQ(1, controller.GetEntryCount());
- EXPECT_EQ(1, RendererHistoryLength(shell()));
+ EXPECT_EQ(1, EvalJs(shell(), "history.length"));
// Add an iframe with no 'src'.
GURL blank_url(url::kAboutBlankURL);
@@ -5904,10 +5860,10 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
"var iframe = document.createElement('iframe');"
"iframe.id = 'frame';"
"document.body.appendChild(iframe);";
- EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script));
+ EXPECT_TRUE(ExecJs(root->current_frame_host(), script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(1, controller.GetEntryCount());
- EXPECT_EQ(1, RendererHistoryLength(shell()));
+ EXPECT_EQ(1, EvalJs(shell(), "history.length"));
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
ASSERT_EQ(1U, root->child_count());
FrameTreeNode* frame = root->child_at(0);
@@ -5915,21 +5871,22 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
EXPECT_EQ(blank_url, frame->current_url());
// Do a document.write in the subframe to create a link to click.
- std::string document_write_script =
+ std::string html = "<a id='fraglink' href='#frag'>fragment link</a>";
+ std::string document_write_script = JsReplace(
"var iframe = document.getElementById('frame');"
- "iframe.contentWindow.document.write("
- " \"<a id='fraglink' href='#frag'>fragment link</a>\");"
- "iframe.contentWindow.document.close();";
- EXPECT_TRUE(ExecuteScript(root->current_frame_host(), document_write_script));
+ "iframe.contentWindow.document.write($1);"
+ "iframe.contentWindow.document.close();",
+ html);
+ EXPECT_TRUE(ExecJs(root->current_frame_host(), document_write_script));
// Click the link to do a same document navigation. Due to the
// document.write, the new URL matches the parent frame's URL.
GURL frame_url_2("data:text/html,Top level page#frag");
std::string link_script = "document.getElementById('fraglink').click()";
- EXPECT_TRUE(ExecuteScript(frame->current_frame_host(), link_script));
+ EXPECT_TRUE(ExecJs(frame->current_frame_host(), link_script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetEntryCount());
- EXPECT_EQ(2, RendererHistoryLength(shell()));
+ EXPECT_EQ(2, EvalJs(shell(), "history.length"));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(frame_url_2, frame->current_url());
@@ -5943,7 +5900,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Verify the process is still alive by running script. We can't just call
// IsRenderFrameLive after the navigation since it might not have disconnected
// yet.
- EXPECT_TRUE(ExecuteScript(root->current_frame_host(), "true;"));
+ EXPECT_TRUE(ExecJs(root->current_frame_host(), "true;"));
EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
EXPECT_EQ(blank_url, frame->current_url());
@@ -6108,7 +6065,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
"b.com", "/navigation_controller/simple_page_2.html"));
std::string replace_script = "location.replace('" + url_b.spec() + "')";
TestNavigationObserver replace_observer(shell()->web_contents());
- EXPECT_TRUE(ExecuteScript(shell()->web_contents(), replace_script));
+ EXPECT_TRUE(ExecJs(shell()->web_contents(), replace_script));
replace_observer.Wait();
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
@@ -6120,8 +6077,8 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Navigate forward twice using script. In https://crbug.com/623319, this
// caused a mismatch between the NavigationEntry's URL and PageState.
- EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
- "history.forward(); history.forward();"));
+ EXPECT_TRUE(
+ ExecJs(shell()->web_contents(), "history.forward(); history.forward();"));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(url_b, root->current_url());
@@ -6193,7 +6150,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
"b.com", "/navigation_controller/page_with_data_iframe.html"));
std::string replace_script = "location.replace('" + url_b.spec() + "')";
TestNavigationObserver replace_observer(shell()->web_contents());
- EXPECT_TRUE(ExecuteScript(shell()->web_contents(), replace_script));
+ EXPECT_TRUE(ExecJs(shell()->web_contents(), replace_script));
replace_observer.Wait();
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
@@ -6208,8 +6165,8 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// we want to ensure that the subframes target entry index 1 and not 2. In
// https://crbug.com/623319, the subframes targeted the wrong entry, leading
// to a URL spoof and renderer kill.
- EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
- "history.forward(); history.forward();"));
+ EXPECT_TRUE(
+ ExecJs(shell()->web_contents(), "history.forward(); history.forward();"));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
@@ -6269,7 +6226,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
TestNavigationObserver observer(shell()->web_contents());
std::string script =
"history.replaceState({}, '', '/server-redirect?" + url_3.spec() + "')";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
observer.Wait();
}
@@ -6327,7 +6284,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
TestNavigationObserver observer(shell()->web_contents());
std::string script = "history.replaceState({}, '', '/server-redirect?" +
frame_url2.spec() + "')";
- EXPECT_TRUE(ExecuteScript(root->child_at(0), script));
+ EXPECT_TRUE(ExecJs(root->child_at(0), script));
observer.Wait();
}
@@ -6427,8 +6384,8 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, PostViaOpenUrlMsg) {
// Submit the form.
TestNavigationObserver form_post_observer(shell()->web_contents(), 1);
- EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
- "document.getElementById('form').submit();"));
+ EXPECT_TRUE(ExecJs(shell()->web_contents(),
+ "document.getElementById('form').submit();"));
form_post_observer.Wait();
// Verify that we arrived at the expected location.
@@ -6437,9 +6394,170 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, PostViaOpenUrlMsg) {
// Verify that POST body was correctly passed to the server and ended up in
// the body of the page.
+ EXPECT_EQ(
+ "text=value\n",
+ EvalJs(shell(), "document.getElementsByTagName('pre')[0].innerText"));
+}
+
+// This test verifies that reloading a POST request that is uncacheable won't
+// incorrectly result in a GET request. This is a regression test for
+// https://crbug.com/860807.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, UncacheablePost) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "/form_that_posts_to_echoall_nocache.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+ WebContents* web_contents = shell()->web_contents();
+ EXPECT_EQ(0, web_contents->GetController().GetLastCommittedEntryIndex());
+
+ // Submit the form.
+ TestNavigationObserver form_post_observer(web_contents, 1);
+ EXPECT_TRUE(
+ ExecuteScript(web_contents, "document.getElementById('form').submit();"));
+ form_post_observer.Wait();
+
+ // Verify that we arrived at the expected location.
+ GURL target_url(embedded_test_server()->GetURL("/echoall/nocache"));
+ EXPECT_EQ(target_url, web_contents->GetLastCommittedURL());
+ EXPECT_EQ(1, web_contents->GetController().GetLastCommittedEntryIndex());
+
+ // Verify that this was a POST request.
+ std::string request_headers;
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ web_contents,
+ "window.domAutomationController.send("
+ "document.getElementsByTagName('pre')[1].innerText);",
+ &request_headers));
+ EXPECT_THAT(request_headers, ::testing::HasSubstr("POST /echoall/nocache"));
+
+ // Verify that POST body was correctly passed to the server and ended up in
+ // the body of the page.
std::string body;
EXPECT_TRUE(ExecuteScriptAndExtractString(
- shell()->web_contents(),
+ web_contents,
+ "window.domAutomationController.send("
+ "document.getElementsByTagName('pre')[0].innerText);",
+ &body));
+ EXPECT_EQ("text=value\n", body);
+
+ // Extract the response nonce.
+ std::string old_response_nonce;
+ std::string response_nonce_extraction_script = R"(
+ domAutomationController.send(
+ document.getElementById('response-nonce').innerText); )";
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ web_contents, response_nonce_extraction_script, &old_response_nonce));
+
+ // Go back.
+ {
+ TestNavigationObserver observer(web_contents);
+ web_contents->GetController().GoBack();
+ observer.Wait();
+ }
+ EXPECT_EQ(main_url, web_contents->GetLastCommittedURL());
+ EXPECT_EQ(0, web_contents->GetController().GetLastCommittedEntryIndex());
+
+ // Go forward.
+ {
+ TestNavigationObserver navigation_observer(web_contents);
+ NavigationHandleObserver handle_observer(web_contents, target_url);
+ web_contents->GetController().GoForward();
+ navigation_observer.Wait();
+
+ // Verify that the previous response response really was treated as
+ // uncacheable.
+ EXPECT_TRUE(handle_observer.is_error());
+ EXPECT_EQ(net::ERR_CACHE_MISS, handle_observer.net_error_code());
+ }
+ EXPECT_EQ(target_url, web_contents->GetLastCommittedURL());
+ EXPECT_EQ(1, web_contents->GetController().GetLastCommittedEntryIndex());
+
+ // Reload
+ {
+ TestNavigationObserver observer(web_contents);
+ web_contents->GetController().Reload(content::ReloadType::NORMAL,
+ false); // check_for_repost
+ observer.Wait();
+ }
+ EXPECT_EQ(target_url, web_contents->GetLastCommittedURL());
+ EXPECT_EQ(1, web_contents->GetController().GetLastCommittedEntryIndex());
+
+ // MAIN VERIFICATION for https://crbug.com/860807: Verify that the reload was
+ // a POST request.
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ web_contents,
+ "window.domAutomationController.send("
+ "document.getElementsByTagName('pre')[1].innerText);",
+ &request_headers));
+ EXPECT_THAT(request_headers, ::testing::HasSubstr("POST /echoall/nocache"));
+
+ // Verify that POST body was correctly passed to the server and ended up in
+ // the body of the page. This is supplementary verification against
+ // https://crbug.com/860807.
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ web_contents,
+ "window.domAutomationController.send("
+ "document.getElementsByTagName('pre')[0].innerText);",
+ &body));
+ EXPECT_EQ("text=value\n", body);
+
+ // Extract the new response nonce and verify that it did change (e.g. that the
+ // reload did load fresh content).
+ std::string new_response_nonce;
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ web_contents, response_nonce_extraction_script, &new_response_nonce));
+ EXPECT_NE(new_response_nonce, old_response_nonce);
+}
+
+// This test verifies that it is possible to reload a POST request that
+// initially failed (e.g. because the network was offline or the host was
+// unreachable during the initial navigation). This is a regression test for
+// https://crbug.com/869117.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+ ReloadOfInitiallyFailedPost) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "/form_that_posts_to_echoall_nocache.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+ WebContents* web_contents = shell()->web_contents();
+ EXPECT_EQ(0, web_contents->GetController().GetLastCommittedEntryIndex());
+
+ // Submit the form while simulating "network down" conditions.
+ GURL target_url(embedded_test_server()->GetURL("/echoall/nocache"));
+ {
+ std::unique_ptr<URLLoaderInterceptor> interceptor =
+ URLLoaderInterceptor::SetupRequestFailForURL(
+ target_url, net::ERR_INTERNET_DISCONNECTED);
+ TestNavigationObserver form_post_observer(web_contents, 1);
+ EXPECT_TRUE(ExecuteScript(web_contents,
+ "document.getElementById('form').submit();"));
+ form_post_observer.Wait();
+ }
+ EXPECT_EQ(target_url, web_contents->GetLastCommittedURL());
+ EXPECT_EQ(1, web_contents->GetController().GetLastCommittedEntryIndex());
+
+ // Reload
+ {
+ TestNavigationObserver observer(web_contents);
+ web_contents->GetController().Reload(content::ReloadType::NORMAL,
+ false); // check_for_repost
+ observer.Wait();
+ }
+ EXPECT_EQ(target_url, web_contents->GetLastCommittedURL());
+ EXPECT_EQ(1, web_contents->GetController().GetLastCommittedEntryIndex());
+
+ // Verify that the reload was a POST request.
+ std::string request_headers;
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ web_contents,
+ "window.domAutomationController.send("
+ "document.getElementsByTagName('pre')[1].innerText);",
+ &request_headers));
+ EXPECT_THAT(request_headers, ::testing::HasSubstr("POST /echoall/nocache"));
+
+ // Verify that POST body was correctly passed to the server and ended up in
+ // the body of the page.
+ std::string body;
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ web_contents,
"window.domAutomationController.send("
"document.getElementsByTagName('pre')[0].innerText);",
&body));
@@ -6494,7 +6612,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Removing the first child of the main frame should remove the corresponding
// FrameTreeNode.
- EXPECT_TRUE(ExecuteScript(root, kRemoveFrameScript));
+ EXPECT_TRUE(ExecJs(root, kRemoveFrameScript));
EXPECT_EQ(2U, root->child_count());
// However, the FrameNavigationEntry objects for the frame that was removed
@@ -6535,7 +6653,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
"f.src = '1-1.html';"
"document.body.appendChild(f);";
TestNavigationObserver observer(web_contents, 1);
- EXPECT_TRUE(ExecuteScript(subframe, add_matching_name_frame_script));
+ EXPECT_TRUE(ExecJs(subframe, add_matching_name_frame_script));
EXPECT_EQ(1U, subframe->child_count());
observer.Wait();
@@ -6575,7 +6693,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// |tree_node| will becoma a dangling pointer when the frame is removed below.
auto* tree_node = nav_entry->root_node()->children[0].get();
- EXPECT_TRUE(ExecuteScript(root, kRemoveFrameScript));
+ EXPECT_TRUE(ExecJs(root, kRemoveFrameScript));
EXPECT_EQ(0U, root->child_count());
EXPECT_EQ(0U, nav_entry->root_node()->children.size());
@@ -6588,7 +6706,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
EXPECT_EQ(1U, nav_entry->root_node()->children.size());
EXPECT_NE(tree_node, nav_entry->root_node()->children[0].get());
- EXPECT_TRUE(ExecuteScript(root, kRemoveFrameScript));
+ EXPECT_TRUE(ExecJs(root, kRemoveFrameScript));
EXPECT_EQ(0U, root->child_count());
}
@@ -6619,7 +6737,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
TestNavigationObserver observer(web_contents);
std::string script = "history.replaceState({}, '', '/server-redirect?" +
redirect_dest_url.spec() + "')";
- EXPECT_TRUE(ExecuteScript(root, script));
+ EXPECT_TRUE(ExecJs(root, script));
observer.Wait();
}
@@ -6646,10 +6764,8 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// Verify the expected origin through JavaScript. It also has the additional
// verification of the process also being still alive.
- std::string origin;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- web_contents, "domAutomationController.send(document.origin)", &origin));
- EXPECT_EQ(start_url.GetOrigin().spec(), origin + "/");
+ EXPECT_EQ(url::Origin::Create(start_url).Serialize(),
+ EvalJs(web_contents, "document.origin"));
}
// Helper to trigger a history-back navigation in the WebContents after the
@@ -6737,10 +6853,8 @@ IN_PROC_BROWSER_TEST_F(
// Verify the expected origin through JavaScript. It also has the additional
// verification of the process also being still alive.
- std::string origin;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- web_contents, "domAutomationController.send(document.origin)", &origin));
- EXPECT_EQ(start_url.GetOrigin().spec(), origin + "/");
+ EXPECT_EQ(url::Origin::Create(start_url).Serialize(),
+ EvalJs(web_contents, "document.origin"));
}
// Test that verifies that Referer and Origin http headers are correctly sent
@@ -6764,7 +6878,7 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// 3. http://x.com:.../echoall/
TestNavigationObserver form_post_observer(shell()->web_contents(), 1);
EXPECT_TRUE(
- ExecuteScript(shell(), "document.getElementById('text-form').submit();"));
+ ExecJs(shell(), "document.getElementById('text-form').submit();"));
form_post_observer.Wait();
// Verify that we arrived at the expected, redirected location.
@@ -6772,12 +6886,9 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
shell()->web_contents()->GetLastCommittedURL());
// Get the http request headers.
- std::string headers;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- shell(),
- "window.domAutomationController.send("
- "document.getElementsByTagName('pre')[1].innerText);",
- &headers));
+ std::string headers =
+ EvalJs(shell(), "document.getElementsByTagName('pre')[1].innerText")
+ .ExtractString();
// Verify the Origin and Referer headers.
EXPECT_THAT(headers, ::testing::HasSubstr("Origin: null"));
@@ -6919,7 +7030,7 @@ void ExecuteJavaScriptAndWaitForLoadStop(WebContents* web_contents,
// JavaScript asynchronously.
TestNavigationObserver observer(web_contents);
- // ExecuteScript() sets a user gesture flag internally for testing, but we
+ // ExecJs() sets a user gesture flag internally for testing, but we
// want to run JavaScript without the flag. Call ExecuteJavaScriptForTests
// directory.
static_cast<WebContentsImpl*>(web_contents)
@@ -7206,8 +7317,8 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
NavigationHandleCommitObserver push_state_observer(shell()->web_contents(),
kPushStateURL);
std::string push_state =
- "history.pushState({}, \"title 1\", \"" + kPushStateURL.spec() + "\");";
- EXPECT_TRUE(ExecuteScript(shell()->web_contents(), push_state));
+ JsReplace("history.pushState({}, 'title 1', $1);", kPushStateURL);
+ EXPECT_TRUE(ExecJs(shell()->web_contents(), push_state));
NavigationEntry* last_committed =
shell()->web_contents()->GetController().GetLastCommittedEntry();
ASSERT_TRUE(last_committed);
@@ -7471,17 +7582,13 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
// The opener should not be able to script the page, which should be another
// error message and not a blank page.
- std::string result;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- shell(),
- "domAutomationController.send((function() {\n"
- " try {\n"
- " return w.document.body.innerHTML;\n"
- " } catch (e) {\n"
- " return e.toString();\n"
- " }\n"
- "})())",
- &result));
+ std::string result = EvalJs(shell(),
+ "try {\n"
+ " w.document.body.innerHTML;\n"
+ "} catch (e) {\n"
+ " e.toString();\n"
+ "}")
+ .ExtractString();
DLOG(INFO) << "Result: " << result;
EXPECT_THAT(result,
::testing::MatchesRegex("SecurityError: Blocked a frame with "
@@ -7527,8 +7634,12 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
TestNavigationObserver observer(shell()->web_contents());
controller.GoBack();
observer.Wait();
+ GURL x_frame_options_deny_url =
+ embedded_test_server()->GetURL("/x-frame-options-deny.html");
+ EXPECT_EQ(x_frame_options_deny_url, root->child_at(0)->current_url());
+ EXPECT_EQ(net::ERR_BLOCKED_BY_RESPONSE, observer.last_net_error_code());
+ EXPECT_FALSE(observer.last_navigation_succeeded());
}
- EXPECT_EQ(GURL("data:,"), root->child_at(0)->current_url());
// Go back again. This would have been same-document if the prior navigation
// had succeeded.
@@ -7731,25 +7842,19 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
EXPECT_TRUE(NavigateToURL(shell(), main_url));
// Repeatedly create and remove a frame from a script.
- std::string result;
std::string script = R"(
- var iterations_left = 5;
- function runOneIteration() {
- if (iterations_left == 0) {
- domAutomationController.send("done-with-test");
- return;
- }
-
- var iframe = document.createElement("iframe");
- document.body.appendChild(iframe);
- document.body.removeChild(iframe);
-
- iterations_left = iterations_left - 1;
- setTimeout(runOneIteration, 0);
- }
- runOneIteration(); )";
- EXPECT_TRUE(ExecuteScriptAndExtractString(shell(), script, &result));
- EXPECT_EQ("done-with-test", result);
+ (async () => {
+ for (let i = 0; i < 5; i++) {
+ // Create and remove an iframe.
+ let iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ document.body.removeChild(iframe);
+ // Let the message loop run (this works in an async function).
+ await new Promise(resolve => setTimeout(resolve, 0));
+ }
+ return 'done-with-test';
+ })(); )";
+ EXPECT_EQ("done-with-test", EvalJs(shell(), script));
// Grab the last committed entry.
const NavigationControllerImpl& controller =
@@ -8007,13 +8112,8 @@ IN_PROC_BROWSER_TEST_F(ContentBrowserTest, HistoryBackInUnloadCancelsReload) {
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
// Test what is in the loaded document.
- std::string html_content;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- shell(), "domAutomationController.send(document.body.textContent)",
- &html_content));
-
EXPECT_EQ("First part of the response... ...and the second part!",
- html_content);
+ EvalJs(shell(), "document.body.textContent"));
}
// Data URLs can have a reference fragment like any other URLs. In this test,
diff --git a/chromium/content/browser/frame_host/navigation_entry_screenshot_manager.cc b/chromium/content/browser/frame_host/navigation_entry_screenshot_manager.cc
index 0b8b2df4b80..5930c7d1acf 100644
--- a/chromium/content/browser/frame_host/navigation_entry_screenshot_manager.cc
+++ b/chromium/content/browser/frame_host/navigation_entry_screenshot_manager.cc
@@ -8,7 +8,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "content/browser/frame_host/navigation_controller_impl.h"
#include "content/browser/frame_host/navigation_entry_impl.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
diff --git a/chromium/content/browser/frame_host/navigation_handle_impl.cc b/chromium/content/browser/frame_host/navigation_handle_impl.cc
index 201f23b9b42..6bc8930b7d8 100644
--- a/chromium/content/browser/frame_host/navigation_handle_impl.cc
+++ b/chromium/content/browser/frame_host/navigation_handle_impl.cc
@@ -6,8 +6,10 @@
#include <iterator>
+#include "base/bind.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
+#include "base/time/time.h"
#include "content/browser/appcache/appcache_navigation_handle.h"
#include "content/browser/appcache/appcache_service_impl.h"
#include "content/browser/child_process_security_policy_impl.h"
@@ -25,6 +27,7 @@
#include "content/browser/frame_host/origin_policy_throttle.h"
#include "content/browser/frame_host/webui_navigation_throttle.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_navigation_handle.h"
#include "content/common/child_process_host_impl.h"
@@ -46,6 +49,16 @@ namespace content {
namespace {
+// Default timeout for the READY_TO_COMMIT -> COMMIT transition. Chosen
+// initially based on the Navigation.ReadyToCommitUntilCommit UMA, and then
+// refined based on feedback based on CrashExitCodes.Renderer/RESULT_CODE_HUNG.
+constexpr base::TimeDelta kDefaultCommitTimeout =
+ base::TimeDelta::FromSeconds(30);
+
+// Timeout for the READY_TO_COMMIT -> COMMIT transition.
+// Overrideable via SetCommitTimeoutForTesting.
+base::TimeDelta g_commit_timeout = kDefaultCommitTimeout;
+
// Use this to get a new unique ID for a NavigationHandle during construction.
// The returned ID is guaranteed to be nonzero (zero is the "no ID" indicator).
int64_t CreateUniqueHandleID() {
@@ -114,7 +127,7 @@ std::unique_ptr<NavigationHandleImpl> NavigationHandleImpl::Create(
FrameTreeNode* frame_tree_node,
bool is_renderer_initiated,
bool is_same_document,
- const base::TimeTicks& navigation_start,
+ base::TimeTicks navigation_start,
int pending_nav_entry_id,
bool started_from_context_menu,
CSPDisposition should_check_main_world_csp,
@@ -128,7 +141,8 @@ std::unique_ptr<NavigationHandleImpl> NavigationHandleImpl::Create(
ui::PageTransition transition,
bool is_external_protocol,
RequestContextType request_context_type,
- blink::WebMixedContentContextType mixed_content_context_type) {
+ blink::WebMixedContentContextType mixed_content_context_type,
+ base::TimeTicks input_start) {
return std::unique_ptr<NavigationHandleImpl>(new NavigationHandleImpl(
url, redirect_chain, frame_tree_node, is_renderer_initiated,
is_same_document, navigation_start, pending_nav_entry_id,
@@ -136,7 +150,7 @@ std::unique_ptr<NavigationHandleImpl> NavigationHandleImpl::Create(
is_form_submission, std::move(navigation_ui_data), method,
std::move(request_headers), resource_request_body, sanitized_referrer,
has_user_gesture, transition, is_external_protocol, request_context_type,
- mixed_content_context_type));
+ mixed_content_context_type, input_start));
}
NavigationHandleImpl::NavigationHandleImpl(
@@ -145,7 +159,7 @@ NavigationHandleImpl::NavigationHandleImpl(
FrameTreeNode* frame_tree_node,
bool is_renderer_initiated,
bool is_same_document,
- const base::TimeTicks& navigation_start,
+ base::TimeTicks navigation_start,
int pending_nav_entry_id,
bool started_from_context_menu,
CSPDisposition should_check_main_world_csp,
@@ -159,7 +173,8 @@ NavigationHandleImpl::NavigationHandleImpl(
ui::PageTransition transition,
bool is_external_protocol,
RequestContextType request_context_type,
- blink::WebMixedContentContextType mixed_content_context_type)
+ blink::WebMixedContentContextType mixed_content_context_type,
+ base::TimeTicks input_start)
: url_(url),
has_user_gesture_(has_user_gesture),
transition_(transition),
@@ -180,6 +195,7 @@ NavigationHandleImpl::NavigationHandleImpl(
frame_tree_node_(frame_tree_node),
next_index_(0),
navigation_start_(navigation_start),
+ input_start_(input_start),
pending_nav_entry_id_(pending_nav_entry_id),
request_context_type_(request_context_type),
mixed_content_context_type_(mixed_content_context_type),
@@ -343,10 +359,14 @@ RenderFrameHostImpl* NavigationHandleImpl::GetParentFrame() {
return frame_tree_node_->parent()->current_frame_host();
}
-const base::TimeTicks& NavigationHandleImpl::NavigationStart() {
+base::TimeTicks NavigationHandleImpl::NavigationStart() {
return navigation_start_;
}
+base::TimeTicks NavigationHandleImpl::NavigationInputStart() {
+ return input_start_;
+}
+
bool NavigationHandleImpl::IsPost() {
return method_ == "POST";
}
@@ -550,6 +570,11 @@ void NavigationHandleImpl::CallResumeForTesting() {
ResumeInternal();
}
+bool NavigationHandleImpl::IsDeferredForTesting() {
+ return state_ == DEFERRING_START || state_ == DEFERRING_REDIRECT ||
+ state_ == DEFERRING_FAILURE || state_ == DEFERRING_RESPONSE;
+}
+
bool NavigationHandleImpl::WasStartedFromContextMenu() const {
return started_from_context_menu_;
}
@@ -822,6 +847,7 @@ void NavigationHandleImpl::ReadyToCommitNavigation(
render_frame_host_ = render_frame_host;
state_ = READY_TO_COMMIT;
ready_to_commit_time_ = base::TimeTicks::Now();
+ RestartCommitTimeout();
// Record metrics for the time it takes to get to this state from the
// beginning of the navigation.
@@ -897,6 +923,8 @@ void NavigationHandleImpl::DidCommitNavigation(
"DidCommitNavigation");
state_ = DID_COMMIT;
}
+ commit_timeout_timer_.Stop();
+ GetRenderFrameHost()->GetRenderWidgetHost()->RendererIsResponsive();
// Record metrics for the time it took to commit the navigation if it was to
// another document without error.
@@ -1381,4 +1409,31 @@ NavigationThrottle* NavigationHandleImpl::GetDeferringThrottle() const {
return throttles_[next_index_ - 1].get();
}
+void NavigationHandleImpl::RestartCommitTimeout() {
+ commit_timeout_timer_.Stop();
+ if (state_ >= DID_COMMIT)
+ return;
+
+ commit_timeout_timer_.Start(
+ FROM_HERE, g_commit_timeout,
+ base::BindRepeating(&NavigationHandleImpl::OnCommitTimeout,
+ weak_factory_.GetWeakPtr()));
+}
+
+void NavigationHandleImpl::OnCommitTimeout() {
+ DCHECK_EQ(READY_TO_COMMIT, state_);
+ GetRenderFrameHost()->GetRenderWidgetHost()->RendererIsUnresponsive(
+ base::BindRepeating(&NavigationHandleImpl::RestartCommitTimeout,
+ weak_factory_.GetWeakPtr()));
+}
+
+// static
+void NavigationHandleImpl::SetCommitTimeoutForTesting(
+ const base::TimeDelta& timeout) {
+ if (timeout.is_zero())
+ g_commit_timeout = kDefaultCommitTimeout;
+ else
+ g_commit_timeout = timeout;
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/navigation_handle_impl.h b/chromium/content/browser/frame_host/navigation_handle_impl.h
index fe477a944b9..22ecf65f214 100644
--- a/chromium/content/browser/frame_host/navigation_handle_impl.h
+++ b/chromium/content/browser/frame_host/navigation_handle_impl.h
@@ -18,6 +18,8 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/optional.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
#include "content/browser/frame_host/frame_tree_node.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/common/content_export.h"
@@ -61,7 +63,7 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
FrameTreeNode* frame_tree_node,
bool is_renderer_initiated,
bool is_same_document,
- const base::TimeTicks& navigation_start,
+ base::TimeTicks navigation_start,
int pending_nav_entry_id,
bool started_from_context_menu,
CSPDisposition should_check_main_world_csp,
@@ -78,7 +80,8 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
RequestContextType request_context_type =
REQUEST_CONTEXT_TYPE_UNSPECIFIED,
blink::WebMixedContentContextType mixed_content_context_type =
- blink::WebMixedContentContextType::kBlockable);
+ blink::WebMixedContentContextType::kBlockable,
+ base::TimeTicks input_start = base::TimeTicks());
~NavigationHandleImpl() override;
@@ -110,7 +113,8 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
const std::vector<GURL>& GetRedirectChain() override;
int GetFrameTreeNodeId() override;
RenderFrameHostImpl* GetParentFrame() override;
- const base::TimeTicks& NavigationStart() override;
+ base::TimeTicks NavigationStart() override;
+ base::TimeTicks NavigationInputStart() override;
bool IsPost() override;
const scoped_refptr<network::ResourceRequestBody>& GetResourceRequestBody()
override;
@@ -150,6 +154,7 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
const std::string& raw_response_header) override;
void CallDidCommitNavigationForTesting(const GURL& url) override;
void CallResumeForTesting() override;
+ bool IsDeferredForTesting() override;
bool WasStartedFromContextMenu() const override;
const GURL& GetSearchableFormURL() override;
const std::string& GetSearchableFormEncoding() override;
@@ -377,6 +382,10 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
return GetDeferringThrottle();
}
+ // Sets the READY_TO_COMMIT -> DID_COMMIT timeout. Resets the timeout to the
+ // default value if |timeout| is zero.
+ static void SetCommitTimeoutForTesting(const base::TimeDelta& timeout);
+
private:
friend class NavigationHandleImplTest;
@@ -386,7 +395,7 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
FrameTreeNode* frame_tree_node,
bool is_renderer_initiated,
bool is_same_document,
- const base::TimeTicks& navigation_start,
+ base::TimeTicks navigation_start,
int pending_nav_entry_id,
bool started_from_context_menu,
CSPDisposition should_check_main_world_csp,
@@ -400,7 +409,8 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
ui::PageTransition transition,
bool is_external_protocol,
RequestContextType request_context_type,
- blink::WebMixedContentContextType mixed_content_context_type);
+ blink::WebMixedContentContextType mixed_content_context_type,
+ base::TimeTicks input_start);
NavigationThrottle::ThrottleCheckResult CheckWillStartRequest();
NavigationThrottle::ThrottleCheckResult CheckWillRedirectRequest();
@@ -440,6 +450,12 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
// nullptr;
NavigationThrottle* GetDeferringThrottle() const;
+ // Called if READY_TO_COMMIT -> COMMIT state transition takes an unusually
+ // long time.
+ void OnCommitTimeout();
+
+ void RestartCommitTimeout();
+
// See NavigationHandle for a description of those member variables.
GURL url_;
scoped_refptr<SiteInstance> starting_site_instance_;
@@ -492,9 +508,17 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
// The time this navigation started.
const base::TimeTicks navigation_start_;
+ // The time the input event that lead to this navigation started.
+ // Currently available only if the navigation was initiated by
+ // the user clicking a link in the renderer.
+ const base::TimeTicks input_start_;
+
// The time this naviagtion was ready to commit.
base::TimeTicks ready_to_commit_time_;
+ // Timer for detecting an unexpectedly long time to commit a navigation.
+ base::OneShotTimer commit_timeout_timer_;
+
// The unique id of the corresponding NavigationEntry.
int pending_nav_entry_id_;
diff --git a/chromium/content/browser/frame_host/navigation_handle_impl_browsertest.cc b/chromium/content/browser/frame_host/navigation_handle_impl_browsertest.cc
index c199bfb8bb9..9cd758fa060 100644
--- a/chromium/content/browser/frame_host/navigation_handle_impl_browsertest.cc
+++ b/chromium/content/browser/frame_host/navigation_handle_impl_browsertest.cc
@@ -1444,15 +1444,16 @@ class NavigationHandleImplHttpsUpgradeBrowserTest
// Tests that the start URL is HTTPS upgraded for a same site navigation.
IN_PROC_BROWSER_TEST_F(NavigationHandleImplHttpsUpgradeBrowserTest,
StartUrlIsHttpsUpgradedSameSite) {
- GURL start_url(
- embedded_test_server()->GetURL("/https_upgrade_same_site.html"));
+ GURL start_url(embedded_test_server()->GetURL(
+ "example.com", "/https_upgrade_same_site.html"));
// Builds the expected upgraded same site URL.
GURL::Replacements replace_scheme;
replace_scheme.SetSchemeStr("https");
- GURL cross_site_iframe_secure_url = embedded_test_server()
- ->GetURL("/title1.html")
- .ReplaceComponents(replace_scheme);
+ GURL cross_site_iframe_secure_url =
+ embedded_test_server()
+ ->GetURL("example.com", "/title1.html")
+ .ReplaceComponents(replace_scheme);
CheckHttpsUpgradedIframeNavigation(start_url, cross_site_iframe_secure_url);
}
diff --git a/chromium/content/browser/frame_host/navigation_request.cc b/chromium/content/browser/frame_host/navigation_request.cc
index dd7375c470e..701167c2055 100644
--- a/chromium/content/browser/frame_host/navigation_request.cc
+++ b/chromium/content/browser/frame_host/navigation_request.cc
@@ -210,9 +210,9 @@ void AddAdditionalRequestHeaders(
}
}
std::string value = base::StringPrintf(
- "cause=\"%s\", destination=\"document\", target=\"%s\", site=\"%s\"",
+ "cause=\"%s\", destination=\"%s\", site=\"%s\"",
has_user_gesture ? "user-activated" : "forced",
- frame_tree_node->IsMainFrame() ? "top-level" : "nested",
+ frame_tree_node->IsMainFrame() ? "document" : "nested-document",
site_value.c_str());
headers->SetHeaderIfMissing("Sec-Metadata", value);
}
@@ -693,7 +693,8 @@ void NavigationRequest::CreateNavigationHandle() {
common_params_.referrer),
common_params_.has_user_gesture, common_params_.transition,
is_external_protocol, begin_params_->request_context_type,
- begin_params_->mixed_content_context_type);
+ begin_params_->mixed_content_context_type,
+ common_params_.input_start);
if (!frame_tree_node->navigation_request()) {
// A callback could have cancelled this request synchronously in which case
@@ -925,8 +926,9 @@ void NavigationRequest::OnResponseStarted(
const GlobalRequestID& request_id,
bool is_download,
bool is_stream,
+ PreviewsState previews_state,
base::Optional<SubresourceLoaderParams> subresource_loader_params) {
- DCHECK(state_ == STARTED);
+ DCHECK_EQ(state_, STARTED);
DCHECK(response);
TRACE_EVENT_ASYNC_STEP_INTO0("navigation", "NavigationRequest", this,
"OnResponseStarted");
@@ -993,8 +995,7 @@ void NavigationRequest::OnResponseStarted(
}
// Update the previews state of the request.
- common_params_.previews_state =
- static_cast<PreviewsState>(response->head.previews_state);
+ common_params_.previews_state = previews_state;
// Select an appropriate renderer to commit the navigation.
RenderFrameHostImpl* render_frame_host = nullptr;
@@ -1073,8 +1074,13 @@ void NavigationRequest::OnResponseStarted(
// download.
if (is_download && (response->head.headers.get() &&
(response->head.headers->response_code() / 100 != 2))) {
- navigation_handle_->set_net_error_code(net::ERR_INVALID_RESPONSE);
- frame_tree_node_->ResetNavigationRequest(false, true);
+ OnRequestFailedInternal(
+ network::URLLoaderCompletionStatus(net::ERR_INVALID_RESPONSE),
+ false /* skip_throttles */, base::nullopt /* error_page_content */,
+ false /* collapse_frame */);
+
+ // DO NOT ADD CODE after this. The previous call to OnRequestFailedInternal
+ // has destroyed the NavigationRequest.
return;
}
@@ -1498,6 +1504,7 @@ void NavigationRequest::OnWillProcessResponseChecksComplete(
resource_request->method = common_params_.method;
resource_request->request_initiator = begin_params_->initiator_origin;
resource_request->referrer = common_params_.referrer.url;
+ resource_request->has_user_gesture = common_params_.has_user_gesture;
BrowserContext* browser_context =
frame_tree_node_->navigator()->GetController()->GetBrowserContext();
diff --git a/chromium/content/browser/frame_host/navigation_request.h b/chromium/content/browser/frame_host/navigation_request.h
index 10440a4a70c..5d4aa5cbeab 100644
--- a/chromium/content/browser/frame_host/navigation_request.h
+++ b/chromium/content/browser/frame_host/navigation_request.h
@@ -237,6 +237,7 @@ class CONTENT_EXPORT NavigationRequest : public NavigationURLLoaderDelegate {
const GlobalRequestID& request_id,
bool is_download,
bool is_stream,
+ PreviewsState previews_state,
base::Optional<SubresourceLoaderParams> subresource_loader_params)
override;
void OnRequestFailed(
diff --git a/chromium/content/browser/frame_host/navigator_impl_unittest.cc b/chromium/content/browser/frame_host/navigator_impl_unittest.cc
index 78c1a044c48..7d748abfede 100644
--- a/chromium/content/browser/frame_host/navigator_impl_unittest.cc
+++ b/chromium/content/browser/frame_host/navigator_impl_unittest.cc
@@ -133,7 +133,7 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
EXPECT_TRUE(main_test_rfh()->navigation_request());
main_test_rfh()->SendNavigate(entry_id, true, kUrl);
EXPECT_TRUE(main_test_rfh()->is_active());
- EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrl),
+ EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrl),
main_test_rfh()->GetSiteInstance()->GetSiteURL());
EXPECT_EQ(kUrl, contents()->GetLastCommittedURL());
@@ -187,7 +187,7 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
// Commit the navigation.
navigation->Commit();
EXPECT_TRUE(main_test_rfh()->is_active());
- EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrl2),
+ EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrl2),
main_test_rfh()->GetSiteInstance()->GetSiteURL());
EXPECT_EQ(kUrl2, contents()->GetLastCommittedURL());
EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
@@ -878,7 +878,7 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
// Receive the beforeUnload ACK.
main_test_rfh()->SendBeforeUnloadACK(true);
EXPECT_EQ(speculative_rfh, GetSpeculativeRenderFrameHost(node));
- EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrl),
+ EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrl),
speculative_rfh->GetSiteInstance()->GetSiteURL());
int32_t site_instance_id = speculative_rfh->GetSiteInstance()->GetId();
int64_t navigation_id =
@@ -923,7 +923,7 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
EXPECT_NE(init_site_instance_id, site_instance_id);
EXPECT_EQ(init_site_instance_id, main_test_rfh()->GetSiteInstance()->GetId());
EXPECT_NE(speculative_rfh, main_test_rfh());
- EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrl),
+ EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrl),
speculative_rfh->GetSiteInstance()->GetSiteURL());
// Receive the beforeUnload ACK.
@@ -960,7 +960,7 @@ TEST_F(NavigatorTestWithBrowserSideNavigation,
// Once commit happens the speculative RenderFrameHost is updated to match the
// known final SiteInstance.
- EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrlRedirect),
+ EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrlRedirect),
speculative_rfh->GetSiteInstance()->GetSiteURL());
int32_t redirect_site_instance_id =
speculative_rfh->GetSiteInstance()->GetId();
diff --git a/chromium/content/browser/frame_host/origin_policy_throttle.cc b/chromium/content/browser/frame_host/origin_policy_throttle.cc
index ab137232754..5d2904a633b 100644
--- a/chromium/content/browser/frame_host/origin_policy_throttle.cc
+++ b/chromium/content/browser/frame_host/origin_policy_throttle.cc
@@ -8,14 +8,14 @@
#include "base/feature_list.h"
#include "base/no_destructor.h"
#include "content/browser/frame_host/navigation_handle_impl.h"
+#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/network_service_instance.h"
+#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
+#include "net/base/load_flags.h"
#include "net/http/http_request_headers.h"
-#include "services/network/network_context.h"
-#include "services/network/network_service.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "url/origin.h"
@@ -164,24 +164,6 @@ const url::Origin OriginPolicyThrottle::GetRequestOrigin() {
}
void OriginPolicyThrottle::FetchPolicy(const GURL& url, FetchCallback done) {
- // Obtain a network context from the network service.
- network::mojom::NetworkContextParamsPtr context_params =
- network::mojom::NetworkContextParams::New();
- content::GetNetworkService()->CreateNetworkContext(
- mojo::MakeRequest(&network_context_ptr_), std::move(context_params));
-
- // Create URLLoaderFactory
- network::mojom::URLLoaderFactoryParamsPtr url_loader_factory_params =
- network::mojom::URLLoaderFactoryParams::New();
- url_loader_factory_params->process_id = network::mojom::kBrowserProcessId;
- url_loader_factory_params->is_corb_enabled = false;
- url_loader_factory_params->disable_web_security =
- base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableWebSecurity);
- network_context_ptr_->CreateURLLoaderFactory(
- mojo::MakeRequest(&url_loader_factory_),
- std::move(url_loader_factory_params));
-
// Create the traffic annotation
net::NetworkTrafficAnnotationTag traffic_annotation =
net::DefineNetworkTrafficAnnotation("origin_policy_loader", R"(
@@ -209,14 +191,27 @@ void OriginPolicyThrottle::FetchPolicy(const GURL& url, FetchCallback done) {
std::unique_ptr<network::ResourceRequest> policy_request =
std::make_unique<network::ResourceRequest>();
policy_request->url = url;
+ policy_request->request_initiator = url::Origin::Create(url);
+ policy_request->fetch_credentials_mode =
+ network::mojom::FetchCredentialsMode::kOmit;
policy_request->fetch_redirect_mode =
network::mojom::FetchRedirectMode::kError;
+ policy_request->load_flags = net::LOAD_DO_NOT_SEND_COOKIES |
+ net::LOAD_DO_NOT_SAVE_COOKIES |
+ net::LOAD_DO_NOT_SEND_AUTH_DATA;
url_loader_ = network::SimpleURLLoader::Create(std::move(policy_request),
traffic_annotation);
- url_loader_->SetAllowHttpErrorResults(false);
+
+ // Obtain the URLLoaderFactory from the NavigationHandle.
+ SiteInstance* site_instance = navigation_handle()->GetStartingSiteInstance();
+ content::StoragePartition* storage_partition =
+ BrowserContext::GetStoragePartition(site_instance->GetBrowserContext(),
+ site_instance);
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory =
+ storage_partition->GetURLLoaderFactoryForBrowserProcess();
// Start the download, and pass the callback for when we're finished.
- url_loader_->DownloadToString(url_loader_factory_.get(), std::move(done),
+ url_loader_->DownloadToString(url_loader_factory.get(), std::move(done),
kMaxPolicySize);
}
@@ -229,8 +224,6 @@ void OriginPolicyThrottle::OnTheGloriousPolicyHasArrived(
std::unique_ptr<std::string> policy_content) {
// Release resources associated with the loading.
url_loader_.reset();
- url_loader_factory_.reset();
- network_context_ptr_.reset();
// Fail hard if the policy could not be loaded.
if (!policy_content) {
diff --git a/chromium/content/browser/frame_host/origin_policy_throttle.h b/chromium/content/browser/frame_host/origin_policy_throttle.h
index ac200046c8c..320558cce4e 100644
--- a/chromium/content/browser/frame_host/origin_policy_throttle.h
+++ b/chromium/content/browser/frame_host/origin_policy_throttle.h
@@ -6,11 +6,13 @@
#define CONTENT_BROWSER_FRAME_HOST_ORIGIN_POLICY_THROTTLE_H_
#include <map>
+#include <memory>
#include <string>
+
#include "base/gtest_prod_util.h"
#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
#include "content/public/browser/navigation_throttle.h"
-#include "services/network/public/mojom/network_service.mojom.h"
class GURL;
@@ -71,11 +73,8 @@ class CONTENT_EXPORT OriginPolicyThrottle : public NavigationThrottle {
void OnTheGloriousPolicyHasArrived(
std::unique_ptr<std::string> policy_content);
- // We may need the SimpleURLLoader to download the policy.
- // The network context and url loader must be kept alive while the load is
- // ongoing.
- network::mojom::NetworkContextPtr network_context_ptr_;
- network::mojom::URLLoaderFactoryPtr url_loader_factory_;
+ // We may need the SimpleURLLoader to download the policy. The loader must
+ // be kept alive while the load is ongoing.
std::unique_ptr<network::SimpleURLLoader> url_loader_;
DISALLOW_COPY_AND_ASSIGN(OriginPolicyThrottle);
diff --git a/chromium/content/browser/frame_host/render_frame_host_android.h b/chromium/content/browser/frame_host/render_frame_host_android.h
index 423e1a62778..23ae2410604 100644
--- a/chromium/content/browser/frame_host/render_frame_host_android.h
+++ b/chromium/content/browser/frame_host/render_frame_host_android.h
@@ -52,6 +52,8 @@ class RenderFrameHostAndroid : public base::SupportsUserData::Data {
void NotifyUserActivation(JNIEnv* env,
const base::android::JavaParamRef<jobject>&);
+ RenderFrameHostImpl* render_frame_host() const { return render_frame_host_; }
+
private:
RenderFrameHostImpl* const render_frame_host_;
service_manager::mojom::InterfaceProviderPtr interface_provider_ptr_;
diff --git a/chromium/content/browser/frame_host/render_frame_host_delegate.cc b/chromium/content/browser/frame_host/render_frame_host_delegate.cc
index 26b8eec2bb7..623cd428e20 100644
--- a/chromium/content/browser/frame_host/render_frame_host_delegate.cc
+++ b/chromium/content/browser/frame_host/render_frame_host_delegate.cc
@@ -126,4 +126,9 @@ Visibility RenderFrameHostDelegate::GetVisibility() const {
return Visibility::HIDDEN;
}
+ukm::SourceId RenderFrameHostDelegate::GetUkmSourceIdForLastCommittedSource()
+ const {
+ return ukm::kInvalidSourceId;
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/render_frame_host_delegate.h b/chromium/content/browser/frame_host/render_frame_host_delegate.h
index 7919ac1e579..9ac81d17f61 100644
--- a/chromium/content/browser/frame_host/render_frame_host_delegate.h
+++ b/chromium/content/browser/frame_host/render_frame_host_delegate.h
@@ -27,6 +27,7 @@
#include "net/http/http_response_headers.h"
#include "services/device/public/mojom/geolocation_context.mojom.h"
#include "services/device/public/mojom/wake_lock.mojom.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
#include "ui/base/window_open_disposition.h"
#if defined(OS_WIN)
@@ -69,6 +70,7 @@ struct AXEventNotificationDetails;
struct AXLocationChangeNotificationDetails;
struct ContextMenuParams;
struct FileChooserParams;
+struct GlobalRequestID;
namespace mojom {
class CreateNewWindowParams;
@@ -363,6 +365,7 @@ class CONTENT_EXPORT RenderFrameHostDelegate {
// associated with |render_frame_host|.
virtual void ResourceLoadComplete(
RenderFrameHost* render_frame_host,
+ const GlobalRequestID& request_id,
mojom::ResourceLoadInfoPtr resource_load_info) {}
// Request to print a frame that is in a different process than its parent.
@@ -378,6 +381,18 @@ class CONTENT_EXPORT RenderFrameHostDelegate {
// Returns the visibility of the delegate.
virtual Visibility GetVisibility() const;
+ // Get the UKM source ID for current content. This is used for providing
+ // data about the content to the URL-keyed metrics service.
+ // Note: This is also exposed by the RenderWidgetHostDelegate.
+ virtual ukm::SourceId GetUkmSourceIdForLastCommittedSource() const;
+
+ // Notify observers if WebAudio AudioContext has started (or stopped) playing
+ // audible sounds.
+ virtual void AudioContextPlaybackStarted(RenderFrameHost* host,
+ int context_id){};
+ virtual void AudioContextPlaybackStopped(RenderFrameHost* host,
+ int context_id){};
+
protected:
virtual ~RenderFrameHostDelegate() {}
};
diff --git a/chromium/content/browser/frame_host/render_frame_host_impl.cc b/chromium/content/browser/frame_host/render_frame_host_impl.cc
index 8e5af3e3b9c..e67018e0f80 100644
--- a/chromium/content/browser/frame_host/render_frame_host_impl.cc
+++ b/chromium/content/browser/frame_host/render_frame_host_impl.cc
@@ -23,13 +23,15 @@
#include "base/numerics/safe_conversions.h"
#include "base/process/kill.h"
#include "base/stl_util.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event_argument.h"
#include "build/build_config.h"
#include "cc/base/switches.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/accessibility/browser_accessibility_state_impl.h"
+#include "content/browser/background_fetch/background_fetch_service_impl.h"
#include "content/browser/bluetooth/web_bluetooth_service_impl.h"
#include "content/browser/browser_main_loop.h"
#include "content/browser/child_process_security_policy_impl.h"
@@ -64,10 +66,12 @@
#include "content/browser/media/capture/audio_mirroring_manager.h"
#include "content/browser/media/media_interface_proxy.h"
#include "content/browser/media/session/media_session_service_impl.h"
+#include "content/browser/media/webaudio/audio_context_manager_impl.h"
#include "content/browser/payments/payment_app_context_impl.h"
#include "content/browser/permissions/permission_controller_impl.h"
#include "content/browser/permissions/permission_service_context.h"
#include "content/browser/permissions/permission_service_impl.h"
+#include "content/browser/portal/portal.h"
#include "content/browser/presentation/presentation_service_impl.h"
#include "content/browser/quota_dispatcher_host.h"
#include "content/browser/renderer_host/dip_util.h"
@@ -98,8 +102,6 @@
#include "content/browser/webui/web_ui_controller_factory_registry.h"
#include "content/browser/webui/web_ui_url_loader_factory_internal.h"
#include "content/common/accessibility_messages.h"
-#include "content/common/associated_interface_provider_impl.h"
-#include "content/common/associated_interface_registry_impl.h"
#include "content/common/associated_interfaces.mojom.h"
#include "content/common/content_security_policy/content_security_policy.h"
#include "content/common/frame_messages.h"
@@ -163,12 +165,15 @@
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "storage/browser/blob/blob_storage_context.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
#include "third_party/blink/public/common/blob/blob_utils.h"
#include "third_party/blink/public/common/feature_policy/feature_policy.h"
#include "third_party/blink/public/common/frame/frame_policy.h"
#include "third_party/blink/public/mojom/page/page_visibility_state.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h"
-#include "third_party/blink/public/platform/modules/webauth/virtual_authenticator.mojom.h"
+#include "third_party/blink/public/mojom/usb/web_usb_service.mojom.h"
+#include "third_party/blink/public/platform/modules/webauthn/virtual_authenticator.mojom.h"
#include "ui/accessibility/ax_tree.h"
#include "ui/accessibility/ax_tree_id_registry.h"
#include "ui/accessibility/ax_tree_update.h"
@@ -314,7 +319,7 @@ void CreateFrameResourceCoordinator(
std::move(request));
}
-using FrameCallback =
+using FrameNotifyCallback =
base::RepeatingCallback<void(ResourceDispatcherHostImpl*,
const GlobalFrameRoutingId&)>;
@@ -322,7 +327,7 @@ using FrameCallback =
// ResourceDispatcherHostImpl of information pertaining to loading behavior of
// frame hosts.
void NotifyRouteChangesOnIO(
- const FrameCallback& frame_callback,
+ const FrameNotifyCallback& frame_callback,
std::unique_ptr<std::set<GlobalFrameRoutingId>> routing_ids) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
@@ -332,13 +337,11 @@ void NotifyRouteChangesOnIO(
frame_callback.Run(rdh, routing_id);
}
-void NotifyForEachFrameFromUI(RenderFrameHost* root_frame_host,
- const FrameCallback& frame_callback) {
+void NotifyForEachFrameFromUI(RenderFrameHostImpl* root_frame_host,
+ const FrameNotifyCallback& frame_callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- FrameTree* frame_tree = static_cast<RenderFrameHostImpl*>(root_frame_host)
- ->frame_tree_node()
- ->frame_tree();
+ FrameTree* frame_tree = root_frame_host->frame_tree_node()->frame_tree();
DCHECK_EQ(root_frame_host, frame_tree->GetMainFrame());
auto routing_ids = std::make_unique<std::set<GlobalFrameRoutingId>>();
@@ -357,6 +360,25 @@ void NotifyForEachFrameFromUI(RenderFrameHost* root_frame_host,
std::move(routing_ids)));
}
+using FrameCallback = base::RepeatingCallback<void(RenderFrameHostImpl*)>;
+void ForEachFrame(RenderFrameHostImpl* root_frame_host,
+ const FrameCallback& frame_callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ FrameTree* frame_tree = root_frame_host->frame_tree_node()->frame_tree();
+ DCHECK_EQ(root_frame_host, frame_tree->GetMainFrame());
+
+ for (FrameTreeNode* node : frame_tree->Nodes()) {
+ RenderFrameHostImpl* frame_host = node->current_frame_host();
+ RenderFrameHostImpl* pending_frame_host =
+ node->render_manager()->speculative_frame_host();
+ if (frame_host)
+ frame_callback.Run(frame_host);
+ if (pending_frame_host)
+ frame_callback.Run(pending_frame_host);
+ }
+}
+
void LookupRenderFrameHostOrProxy(int process_id,
int routing_id,
RenderFrameHostImpl** rfh,
@@ -628,6 +650,8 @@ RenderFrameHostImpl::RenderFrameHostImpl(SiteInstance* site_instance,
DCHECK(!render_widget_host_->owned_by_render_frame_host());
render_widget_host_->SetWidget(std::move(widget));
}
+ if (!frame_tree_node_->parent())
+ render_widget_host_->SetIntersectsViewport(true);
render_widget_host_->SetFrameDepth(frame_tree_node_->depth());
render_widget_host_->SetWidgetInputHandler(std::move(widget_handler),
std::move(host_request));
@@ -671,6 +695,12 @@ RenderFrameHostImpl::~RenderFrameHostImpl() {
if (delegate_ && render_frame_created_)
delegate_->RenderFrameDeleted(this);
+ // Ensure that the render process host has been notified that all audio
+ // streams from this frame have terminated. This is required to ensure the
+ // process host has the correct media stream count, which affects its
+ // background priority.
+ OnAudibleStateChanged(false);
+
// If this was the last active frame in the SiteInstance, the
// DecrementActiveFrameCount call will trigger the deletion of the
// SiteInstance's proxies.
@@ -759,6 +789,14 @@ void RenderFrameHostImpl::DidCommitProvisionalLoadForTesting(
std::move(interface_provider_request));
}
+void RenderFrameHostImpl::AudioContextPlaybackStarted(int audio_context_id) {
+ delegate_->AudioContextPlaybackStarted(this, audio_context_id);
+}
+
+void RenderFrameHostImpl::AudioContextPlaybackStopped(int audio_context_id) {
+ delegate_->AudioContextPlaybackStopped(this, audio_context_id);
+}
+
SiteInstanceImpl* RenderFrameHostImpl::GetSiteInstance() {
return site_instance_.get();
}
@@ -826,36 +864,10 @@ void RenderFrameHostImpl::ExecuteMediaPlayerActionAtLocation(
Send(new FrameMsg_MediaPlayerActionAt(routing_id_, point_in_view, action));
}
-void RenderFrameHostImpl::CreateNetworkServiceDefaultFactory(
+bool RenderFrameHostImpl::CreateNetworkServiceDefaultFactory(
network::mojom::URLLoaderFactoryRequest default_factory_request) {
- network::mojom::URLLoaderFactoryParamsPtr params =
- network::mojom::URLLoaderFactoryParams::New();
- params->process_id = GetProcess()->GetID();
- params->disable_web_security =
- base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableWebSecurity);
- SiteIsolationPolicy::PopulateURLLoaderFactoryParamsPtrForCORB(params.get());
-
- auto* context = GetSiteInstance()->GetBrowserContext();
- GetContentClient()->browser()->WillCreateURLLoaderFactory(
- context, this, false /* is_navigation */, &default_factory_request);
- // Keep DevTools proxy lasy, i.e. closest to the network.
- RenderFrameDevToolsAgentHost::WillCreateURLLoaderFactory(
- this, false /* is_navigation */, false /* is_download */,
- &default_factory_request);
- StoragePartitionImpl* storage_partition = static_cast<StoragePartitionImpl*>(
- BrowserContext::GetStoragePartition(context, GetSiteInstance()));
- if (g_create_network_factory_callback_for_test.Get().is_null()) {
- storage_partition->GetNetworkContext()->CreateURLLoaderFactory(
- std::move(default_factory_request), std::move(params));
- } else {
- network::mojom::URLLoaderFactoryPtr original_factory;
- storage_partition->GetNetworkContext()->CreateURLLoaderFactory(
- mojo::MakeRequest(&original_factory), std::move(params));
- g_create_network_factory_callback_for_test.Get().Run(
- std::move(default_factory_request), GetProcess()->GetID(),
- original_factory.PassInterface());
- }
+ return CreateNetworkServiceDefaultFactoryInternal(
+ last_committed_url_, std::move(default_factory_request));
}
gfx::NativeView RenderFrameHostImpl::GetNativeView() {
@@ -961,7 +973,7 @@ service_manager::InterfaceProvider* RenderFrameHostImpl::GetRemoteInterfaces() {
blink::AssociatedInterfaceProvider*
RenderFrameHostImpl::GetRemoteAssociatedInterfaces() {
if (!remote_associated_interfaces_) {
- mojom::AssociatedInterfaceProviderAssociatedPtr remote_interfaces;
+ blink::mojom::AssociatedInterfaceProviderAssociatedPtr remote_interfaces;
IPC::ChannelProxy* channel = GetProcess()->GetChannel();
if (channel) {
RenderProcessHostImpl* process =
@@ -973,8 +985,9 @@ RenderFrameHostImpl::GetRemoteAssociatedInterfaces() {
// case we set up a dummy interface provider.
mojo::MakeRequestAssociatedWithDedicatedPipe(&remote_interfaces);
}
- remote_associated_interfaces_.reset(new AssociatedInterfaceProviderImpl(
- std::move(remote_interfaces)));
+ remote_associated_interfaces_ =
+ std::make_unique<blink::AssociatedInterfaceProvider>(
+ std::move(remote_interfaces));
}
return remote_associated_interfaces_.get();
}
@@ -1138,10 +1151,9 @@ void RenderFrameHostImpl::OnAssociatedInterfaceRequest(
const std::string& interface_name,
mojo::ScopedInterfaceEndpointHandle handle) {
ContentBrowserClient* browser_client = GetContentClient()->browser();
- if (associated_registry_->CanBindRequest(interface_name)) {
- associated_registry_->BindRequest(interface_name, std::move(handle));
- } else if (!browser_client->BindAssociatedInterfaceRequestFromFrame(
- this, interface_name, &handle)) {
+ if (!associated_registry_->TryBindInterface(interface_name, &handle) &&
+ !browser_client->BindAssociatedInterfaceRequestFromFrame(
+ this, interface_name, &handle)) {
delegate_->OnAssociatedInterfaceRequest(this, interface_name,
std::move(handle));
}
@@ -1231,14 +1243,14 @@ void RenderFrameHostImpl::RenderProcessGone(SiteInstanceImpl* site_instance) {
// The renderer process is gone, so this frame can no longer be loading.
if (GetNavigationHandle())
GetNavigationHandle()->set_net_error_code(net::ERR_ABORTED);
+ ResetNavigationRequests();
ResetLoadingState();
// Any future UpdateState or UpdateTitle messages from this or a recreated
// process should be ignored until the next commit.
set_nav_entry_id(0);
- if (is_audible_)
- GetProcess()->OnMediaStreamRemoved();
+ OnAudibleStateChanged(false);
}
void RenderFrameHostImpl::ReportContentSecurityPolicyViolation(
@@ -1701,6 +1713,12 @@ void RenderFrameHostImpl::DidCommitProvisionalLoad(
validated_params,
service_manager::mojom::InterfaceProviderRequest
interface_provider_request) {
+ if (GetNavigationHandle()) {
+ main_frame_request_ids_ = {validated_params->request_id,
+ GetNavigationHandle()->GetGlobalRequestID()};
+ if (deferred_main_frame_load_info_)
+ ResourceLoadComplete(std::move(deferred_main_frame_load_info_));
+ }
// DidCommitProvisionalLoad IPC should be associated with the URL being
// committed (not with the *last* committed URL that most other IPCs are
// associated with).
@@ -1712,8 +1730,8 @@ void RenderFrameHostImpl::DidCommitProvisionalLoad(
RenderProcessHost* process = GetProcess();
TRACE_EVENT2("navigation", "RenderFrameHostImpl::DidCommitProvisionalLoad",
- "frame_tree_node", frame_tree_node_->frame_tree_node_id(), "url",
- validated_params->url.possibly_invalid_spec());
+ "url", validated_params->url.possibly_invalid_spec(), "details",
+ CommitAsTracedValue(validated_params.get()));
// Notify the resource scheduler of the navigation committing.
NotifyResourceSchedulerOfNavigation(process->GetID(), *validated_params);
@@ -2103,8 +2121,11 @@ void RenderFrameHostImpl::OnRenderProcessGone(int status, int exit_code) {
// Reset frame tree state associated with this process. This must happen
// before RenderViewTerminated because observers expect the subframes of any
- // affected frames to be cleared first.
- frame_tree_node_->ResetForNewProcess();
+ // affected frames to be cleared first. Only do this if this is the current
+ // RenderFrameHost; if the process goes away for a pending delete or
+ // speculative RFH, we shouldn't remove subframes from the current RFH.
+ if (IsCurrent())
+ frame_tree_node_->ResetForNewProcess();
// Reset state for the current RenderFrameHost once the FrameTreeNode has been
// reset.
@@ -3221,17 +3242,19 @@ void RenderFrameHostImpl::CreateNewWindow(
// be needed if a response ends up creating a plugin. We'll only have a
// single frame at this point. These requests will be resumed either in
// WebContentsImpl::CreateNewWindow or RenderFrameHost::Init.
- // TODO(crbug.com/581037): Now that NPAPI is deprecated we should be able to
- // remove this, but more investigation is needed.
- auto block_requests_for_route = base::Bind(
- [](const GlobalFrameRoutingId& id) {
- auto* rdh = ResourceDispatcherHostImpl::Get();
- if (rdh)
- rdh->BlockRequestsForRoute(id);
- },
- GlobalFrameRoutingId(render_process_id, main_frame_route_id));
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
- std::move(block_requests_for_route));
+ // TODO(crbug.com/581037): Even though NPAPI is deleted, other features
+ // depend on this behavior. See the bug for more information.
+ if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ auto block_requests_for_route = base::Bind(
+ [](const GlobalFrameRoutingId& id) {
+ auto* rdh = ResourceDispatcherHostImpl::Get();
+ if (rdh)
+ rdh->BlockRequestsForRoute(id);
+ },
+ GlobalFrameRoutingId(render_process_id, main_frame_route_id));
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ std::move(block_requests_for_route));
+ }
}
DCHECK(IsRenderFrameLive());
@@ -3266,6 +3289,14 @@ void RenderFrameHostImpl::CreateNewWindow(
RenderFrameHostImpl::FromID(GetProcess()->GetID(), main_frame_route_id);
DCHECK(rfh);
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService) &&
+ rfh->waiting_for_init_) {
+ // Need to check |waiting_for_init_| as some paths inside CreateNewWindow
+ // call above (namely, if WebContentsDelegate::ShouldCreateWebContents
+ // returns false) will resume requests by calling RenderFrameHostImpl::Init.
+ rfh->frame_->BlockRequests();
+ }
+
service_manager::mojom::InterfaceProviderPtrInfo
main_frame_interface_provider_info;
rfh->BindInterfaceProviderRequest(
@@ -3379,7 +3410,20 @@ void RenderFrameHostImpl::SubresourceResponseStarted(
void RenderFrameHostImpl::ResourceLoadComplete(
mojom::ResourceLoadInfoPtr resource_load_info) {
- delegate_->ResourceLoadComplete(this, std::move(resource_load_info));
+ GlobalRequestID global_request_id;
+ if (main_frame_request_ids_.first == resource_load_info->request_id) {
+ global_request_id = main_frame_request_ids_.second;
+ } else if (resource_load_info->resource_type ==
+ content::RESOURCE_TYPE_MAIN_FRAME) {
+ // The load complete message for the main resource arrived before
+ // |DidCommitProvisionalLoad()|. We save the load info so
+ // |ResourceLoadComplete()| can be called later in
+ // |DidCommitProvisionalLoad()| when we can map to the global request ID.
+ deferred_main_frame_load_info_ = std::move(resource_load_info);
+ return;
+ }
+ delegate_->ResourceLoadComplete(this, global_request_id,
+ std::move(resource_load_info));
}
void RenderFrameHostImpl::RegisterMojoInterfaces() {
@@ -3436,10 +3480,7 @@ void RenderFrameHostImpl::RegisterMojoInterfaces() {
base::Unretained(this)));
registry_->AddInterface(base::BindRepeating(
- &RenderFrameHostImpl::CreateUsbDeviceManager, base::Unretained(this)));
-
- registry_->AddInterface(base::BindRepeating(
- &RenderFrameHostImpl::CreateUsbChooserService, base::Unretained(this)));
+ &RenderFrameHostImpl::CreateWebUsbService, base::Unretained(this)));
registry_->AddInterface<media::mojom::InterfaceFactory>(
base::Bind(&RenderFrameHostImpl::BindMediaInterfaceFactoryRequest,
@@ -3535,8 +3576,15 @@ void RenderFrameHostImpl::RegisterMojoInterfaces() {
->GetVideoDecodePerfHistory()
->GetSaveCallback();
}
+
registry_->AddInterface(base::BindRepeating(
- &media::MediaMetricsProvider::Create, std::move(save_stats_cb)));
+ &media::MediaMetricsProvider::Create, frame_tree_node_->IsMainFrame(),
+ base::BindRepeating(
+ &RenderFrameHostDelegate::GetUkmSourceIdForLastCommittedSource,
+ // This callback is only executed when Create() is called, during
+ // which the lifetime of the |delegate_| is guaranteed.
+ base::Unretained(delegate_)),
+ std::move(save_stats_cb)));
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
cc::switches::kEnableGpuBenchmarking)) {
@@ -3552,6 +3600,17 @@ void RenderFrameHostImpl::RegisterMojoInterfaces() {
base::BindRepeating(SpeechRecognitionDispatcherHost::Create,
GetProcess()->GetID(), routing_id_),
BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
+
+ if (Portal::IsEnabled()) {
+ registry_->AddInterface(base::BindRepeating(IgnoreResult(&Portal::Create),
+ base::Unretained(this)));
+ }
+
+ registry_->AddInterface(base::BindRepeating(
+ &BackgroundFetchServiceImpl::CreateForFrame, GetProcess(), routing_id_));
+
+ registry_->AddInterface(base::BindRepeating(&AudioContextManagerImpl::Create,
+ base::Unretained(this)));
}
void RenderFrameHostImpl::ResetWaitingState() {
@@ -3973,8 +4032,11 @@ void RenderFrameHostImpl::CommitNavigation(
if (!default_factory_info) {
// Otherwise default to a Network Service-backed loader from the
// appropriate NetworkContext.
- CreateNetworkServiceDefaultFactoryAndObserve(
- mojo::MakeRequest(&default_factory_info));
+ bool bypass_redirect_checks =
+ CreateNetworkServiceDefaultFactoryAndObserve(
+ common_params.url, mojo::MakeRequest(&default_factory_info));
+ subresource_loader_factories->set_bypass_redirect_checks(
+ bypass_redirect_checks);
}
DCHECK(default_factory_info);
@@ -3988,7 +4050,7 @@ void RenderFrameHostImpl::CommitNavigation(
auto file_factory = std::make_unique<FileURLLoaderFactory>(
browser_context->GetPath(),
base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::BACKGROUND,
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
non_network_url_loader_factories_.emplace(url::kFileScheme,
std::move(file_factory));
@@ -4019,7 +4081,8 @@ void RenderFrameHostImpl::CommitNavigation(
network::mojom::URLLoaderFactoryPtrInfo factory_proxy_info;
auto factory_request = mojo::MakeRequest(&factory_proxy_info);
GetContentClient()->browser()->WillCreateURLLoaderFactory(
- browser_context, this, false /* is_navigation */, &factory_request);
+ browser_context, this, false /* is_navigation */, common_params.url,
+ &factory_request);
// Keep DevTools proxy lasy, i.e. closest to the network.
RenderFrameDevToolsAgentHost::WillCreateURLLoaderFactory(
this, false /* is_navigation */, false /* is_download */,
@@ -4092,7 +4155,9 @@ void RenderFrameHostImpl::CommitNavigation(
head, common_params, request_params,
std::move(url_loader_client_endpoints), CloneSubresourceFactories(),
std::move(subresource_overrides), std::move(controller),
- std::move(prefetch_loader_factory), devtools_navigation_token);
+ std::move(prefetch_loader_factory), devtools_navigation_token,
+ base::BindOnce(&RenderFrameHostImpl::OnCrossDocumentCommitProcessed,
+ base::Unretained(this), navigation_id));
} else {
GetNavigationControl()->CommitNavigation(
head, common_params, request_params,
@@ -4148,11 +4213,12 @@ void RenderFrameHostImpl::FailedNavigation(
std::unique_ptr<URLLoaderFactoryBundleInfo> subresource_loader_factories;
if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
network::mojom::URLLoaderFactoryPtrInfo default_factory_info;
- CreateNetworkServiceDefaultFactoryAndObserve(
- mojo::MakeRequest(&default_factory_info));
+ bool bypass_redirect_checks = CreateNetworkServiceDefaultFactoryAndObserve(
+ common_params.url, mojo::MakeRequest(&default_factory_info));
subresource_loader_factories = std::make_unique<URLLoaderFactoryBundleInfo>(
std::move(default_factory_info),
- std::map<std::string, network::mojom::URLLoaderFactoryPtrInfo>());
+ std::map<std::string, network::mojom::URLLoaderFactoryPtrInfo>(),
+ bypass_redirect_checks);
}
SaveSubresourceFactories(std::move(subresource_loader_factories));
@@ -4164,7 +4230,9 @@ void RenderFrameHostImpl::FailedNavigation(
request->GetCommitNavigationClient()) {
request->GetCommitNavigationClient()->CommitFailedNavigation(
common_params, request_params, has_stale_copy_in_cache, error_code,
- error_page_content, CloneSubresourceFactories());
+ error_page_content, CloneSubresourceFactories(),
+ base::BindOnce(&RenderFrameHostImpl::OnCrossDocumentCommitProcessed,
+ base::Unretained(this), navigation_id));
} else {
GetNavigationControl()->CommitFailedNavigation(
common_params, request_params, has_stale_copy_in_cache, error_code,
@@ -4199,15 +4267,15 @@ void RenderFrameHostImpl::SetUpMojoIfNeeded() {
if (registry_.get())
return;
- associated_registry_ = std::make_unique<AssociatedInterfaceRegistryImpl>();
+ associated_registry_ = std::make_unique<blink::AssociatedInterfaceRegistry>();
registry_ = std::make_unique<service_manager::BinderRegistry>();
auto make_binding = [](RenderFrameHostImpl* impl,
mojom::FrameHostAssociatedRequest request) {
impl->frame_host_associated_binding_.Bind(std::move(request));
};
- static_cast<blink::AssociatedInterfaceRegistry*>(associated_registry_.get())
- ->AddInterface(base::Bind(make_binding, base::Unretained(this)));
+ associated_registry_->AddInterface(
+ base::BindRepeating(make_binding, base::Unretained(this)));
RegisterMojoInterfaces();
mojom::FrameFactoryPtr frame_factory;
@@ -4418,22 +4486,47 @@ bool RenderFrameHostImpl::CanCommitURL(const GURL& url) {
void RenderFrameHostImpl::BlockRequestsForFrame() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- NotifyForEachFrameFromUI(
- this,
- base::BindRepeating(&ResourceDispatcherHostImpl::BlockRequestsForRoute));
+
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ ForEachFrame(
+ this, base::BindRepeating([](RenderFrameHostImpl* render_frame_host) {
+ if (render_frame_host->frame_)
+ render_frame_host->frame_->BlockRequests();
+ }));
+ } else {
+ NotifyForEachFrameFromUI(
+ this, base::BindRepeating(
+ &ResourceDispatcherHostImpl::BlockRequestsForRoute));
+ }
}
void RenderFrameHostImpl::ResumeBlockedRequestsForFrame() {
- NotifyForEachFrameFromUI(
- this, base::BindRepeating(
- &ResourceDispatcherHostImpl::ResumeBlockedRequestsForRoute));
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ ForEachFrame(
+ this, base::BindRepeating([](RenderFrameHostImpl* render_frame_host) {
+ if (render_frame_host->frame_)
+ render_frame_host->frame_->ResumeBlockedRequests();
+ }));
+ } else {
+ NotifyForEachFrameFromUI(
+ this, base::BindRepeating(
+ &ResourceDispatcherHostImpl::ResumeBlockedRequestsForRoute));
+ }
}
void RenderFrameHostImpl::CancelBlockedRequestsForFrame() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- NotifyForEachFrameFromUI(
- this, base::BindRepeating(
- &ResourceDispatcherHostImpl::CancelBlockedRequestsForRoute));
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ ForEachFrame(
+ this, base::BindRepeating([](RenderFrameHostImpl* render_frame_host) {
+ if (render_frame_host->frame_)
+ render_frame_host->frame_->CancelBlockedRequests();
+ }));
+ } else {
+ NotifyForEachFrameFromUI(
+ this, base::BindRepeating(
+ &ResourceDispatcherHostImpl::CancelBlockedRequestsForRoute));
+ }
}
bool RenderFrameHostImpl::IsSameSiteInstance(
@@ -4661,13 +4754,14 @@ void RenderFrameHostImpl::UpdateSubresourceLoaderFactories() {
DCHECK(network_service_connection_error_handler_holder_.is_bound());
network::mojom::URLLoaderFactoryPtrInfo default_factory_info;
- CreateNetworkServiceDefaultFactoryAndObserve(
- mojo::MakeRequest(&default_factory_info));
+ bool bypass_redirect_checks = CreateNetworkServiceDefaultFactoryAndObserve(
+ last_committed_url_, mojo::MakeRequest(&default_factory_info));
std::unique_ptr<URLLoaderFactoryBundleInfo> subresource_loader_factories =
- std::make_unique<URLLoaderFactoryBundleInfo>();
- subresource_loader_factories->default_factory_info() =
- std::move(default_factory_info);
+ std::make_unique<URLLoaderFactoryBundleInfo>(
+ std::move(default_factory_info),
+ std::map<std::string, network::mojom::URLLoaderFactoryPtrInfo>(),
+ bypass_redirect_checks);
SaveSubresourceFactories(std::move(subresource_loader_factories));
GetNavigationControl()->UpdateSubresourceLoaderFactories(
CloneSubresourceFactories());
@@ -4682,9 +4776,11 @@ std::set<int> RenderFrameHostImpl::GetNavigationEntryIdsPendingCommit() {
return result;
}
-void RenderFrameHostImpl::CreateNetworkServiceDefaultFactoryAndObserve(
+bool RenderFrameHostImpl::CreateNetworkServiceDefaultFactoryAndObserve(
+ const GURL& url,
network::mojom::URLLoaderFactoryRequest default_factory_request) {
- CreateNetworkServiceDefaultFactory(std::move(default_factory_request));
+ bool bypass_redirect_checks = CreateNetworkServiceDefaultFactoryInternal(
+ url, std::move(default_factory_request));
// Add connection error observer when Network Service is running
// out-of-process.
@@ -4704,6 +4800,48 @@ void RenderFrameHostImpl::CreateNetworkServiceDefaultFactoryAndObserve(
&RenderFrameHostImpl::UpdateSubresourceLoaderFactories,
weak_ptr_factory_.GetWeakPtr()));
}
+ return bypass_redirect_checks;
+}
+
+bool RenderFrameHostImpl::CreateNetworkServiceDefaultFactoryInternal(
+ const GURL& url,
+ network::mojom::URLLoaderFactoryRequest default_factory_request) {
+ network::mojom::URLLoaderFactoryParamsPtr params =
+ network::mojom::URLLoaderFactoryParams::New();
+ params->process_id = GetProcess()->GetID();
+ params->disable_web_security =
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableWebSecurity);
+ SiteIsolationPolicy::PopulateURLLoaderFactoryParamsPtrForCORB(params.get());
+
+ auto* context = GetSiteInstance()->GetBrowserContext();
+ bool bypass_redirect_checks = false;
+
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ bypass_redirect_checks =
+ GetContentClient()->browser()->WillCreateURLLoaderFactory(
+ context, this, false /* is_navigation */, url,
+ &default_factory_request);
+ }
+
+ // Keep DevTools proxy lasy, i.e. closest to the network.
+ RenderFrameDevToolsAgentHost::WillCreateURLLoaderFactory(
+ this, false /* is_navigation */, false /* is_download */,
+ &default_factory_request);
+ StoragePartitionImpl* storage_partition = static_cast<StoragePartitionImpl*>(
+ BrowserContext::GetStoragePartition(context, GetSiteInstance()));
+ if (g_create_network_factory_callback_for_test.Get().is_null()) {
+ storage_partition->GetNetworkContext()->CreateURLLoaderFactory(
+ std::move(default_factory_request), std::move(params));
+ } else {
+ network::mojom::URLLoaderFactoryPtr original_factory;
+ storage_partition->GetNetworkContext()->CreateURLLoaderFactory(
+ mojo::MakeRequest(&original_factory), std::move(params));
+ g_create_network_factory_callback_for_test.Get().Run(
+ std::move(default_factory_request), GetProcess()->GetID(),
+ original_factory.PassInterface());
+ }
+ return bypass_redirect_checks;
}
bool RenderFrameHostImpl::CanExecuteJavaScript() {
@@ -4858,16 +4996,9 @@ void RenderFrameHostImpl::DeleteWebBluetoothService(
web_bluetooth_services_.erase(it);
}
-void RenderFrameHostImpl::CreateUsbDeviceManager(
- device::mojom::UsbDeviceManagerRequest request) {
- GetContentClient()->browser()->CreateUsbDeviceManager(this,
- std::move(request));
-}
-
-void RenderFrameHostImpl::CreateUsbChooserService(
- device::mojom::UsbChooserServiceRequest request) {
- GetContentClient()->browser()->CreateUsbChooserService(this,
- std::move(request));
+void RenderFrameHostImpl::CreateWebUsbService(
+ blink::mojom::WebUsbServiceRequest request) {
+ GetContentClient()->browser()->CreateWebUsbService(this, std::move(request));
}
void RenderFrameHostImpl::ResetFeaturePolicy() {
@@ -5072,6 +5203,9 @@ RenderFrameHostImpl::TakeNavigationHandleForCommit(
navigation_request_ ? navigation_request_->navigation_handle() : nullptr;
// Determine if the current NavigationHandle can be used.
+ //
+ // TODO(lukasza, clamy): https://crbug.com/784904: Match commit IPC to proper
+ // NavigationHandle without requiring URLs to match.
if (navigation_handle && navigation_handle->GetURL() == params.url) {
std::unique_ptr<NavigationHandleImpl> result_navigation_handle =
navigation_request()->TakeNavigationHandle();
@@ -5080,15 +5214,29 @@ RenderFrameHostImpl::TakeNavigationHandleForCommit(
return result_navigation_handle;
}
- // If the URL does not match what the NavigationHandle expects, treat the
- // commit as a new navigation. This can happen when loading a Data
- // navigation with LoadDataWithBaseURL.
+ // At this point we know that the right/matching |navigation_request_| has
+ // already been found based on navigation id look-up performed by
+ // RFHI::OnCrossDocumentCommitProcessed. OTOH, we cannot use
+ // |navigation_handle|, because it has a mismatched URL (which would cause
+ // DCHECKs - for example in NavigationHandleImpl::DidCommitNavigation).
+ //
+ // Because of the above, if the URL does not match what the NavigationHandle
+ // expects, we want to treat the commit as a new navigation.
+ // This mostly works, but there are some remaining issues here tracked
+ // by https://crbug.com/872803.
//
+ // The URL mismatch can happen when loading a Data navigation with
+ // LoadDataWithBaseURL.
// TODO(csharrison): Data navigations loaded with LoadDataWithBaseURL get
// reset here, because the NavigationHandle tracks the URL but the params.url
// tracks the data. The trick of saving the old entry ids for these
// navigations should go away when this is properly handled.
- // See crbug.com/588317.
+ // See https://crbug.com/588317.
+ //
+ // Other cases are where URL mismatch can happen is when committing an error
+ // page - for example this can happen during CSP/frame-ancestors checks (see
+ // https://crbug.com/759184).
+
int entry_id_for_data_nav = 0;
bool is_renderer_initiated = true;
@@ -5112,6 +5260,11 @@ RenderFrameHostImpl::TakeNavigationHandleForCommit(
entry_id_for_data_nav = navigation_handle->pending_nav_entry_id();
is_renderer_initiated = pending_entry->is_renderer_initiated();
}
+
+ // Going forward we'll use the NavigationHandle created below. Therefore we
+ // should destroy the old |navigation_request_| and the NavigationHandle it
+ // owns. This avoids the leak reported in https://crbug.com/872803.
+ navigation_request_.reset();
}
// There is no pending NavigationEntry in these cases, so pass 0 as the
@@ -5265,25 +5418,48 @@ bool RenderFrameHostImpl::ValidateDidCommitParams(
// Error pages may sometimes commit a URL in the wrong process, which requires
// an exception for the CanCommitURL checks. This is ok as long as the origin
// is unique.
- // TODO(creis): Kill the renderer if it claims an error page has a non-unique
- // origin.
bool is_permitted_error_page = false;
- if (validated_params->origin.unique()) {
- if (SiteIsolationPolicy::IsErrorPageIsolationEnabled(
- frame_tree_node_->IsMainFrame())) {
- // With error page isolation, any URL can commit in an error page process.
- if (GetSiteInstance()->GetSiteURL() ==
- GURL(content::kUnreachableWebDataURL)) {
- is_permitted_error_page = true;
+ if (SiteIsolationPolicy::IsErrorPageIsolationEnabled(
+ frame_tree_node_->IsMainFrame())) {
+ if (site_instance_->GetSiteURL() == GURL(content::kUnreachableWebDataURL)) {
+ // Commits in the error page process must only be failures, otherwise
+ // successful navigations could commit documents from origins different
+ // than the chrome-error://chromewebdata/ one and violate expectations.
+ if (!validated_params->url_is_unreachable) {
+ DEBUG_ALIAS_FOR_ORIGIN(origin_debug_alias, validated_params->origin);
+ bad_message::ReceivedBadMessage(
+ process, bad_message::RFH_ERROR_PROCESS_NON_ERROR_COMMIT);
+ return false;
}
- } else {
- // Without error page isolation, a blocked navigation is expected to
- // commit in the old renderer process. This may be true for subframe
- // navigations even when error page isolation is enabled for main frames.
- if (GetNavigationHandle() && GetNavigationHandle()->GetNetErrorCode() ==
- net::ERR_BLOCKED_BY_CLIENT) {
- is_permitted_error_page = true;
+
+ // Error pages must commit in a unique origin. Terminate the renderer
+ // process if this is violated.
+ if (!validated_params->origin.unique()) {
+ DEBUG_ALIAS_FOR_ORIGIN(origin_debug_alias, validated_params->origin);
+ bad_message::ReceivedBadMessage(
+ process, bad_message::RFH_ERROR_PROCESS_NON_UNIQUE_ORIGIN_COMMIT);
+ return false;
}
+
+ // With error page isolation, any URL can commit in an error page process.
+ is_permitted_error_page = true;
+ }
+ } else {
+ // Without error page isolation, a blocked navigation is expected to
+ // commit in the old renderer process. This may be true for subframe
+ // navigations even when error page isolation is enabled for main frames.
+ if (GetNavigationHandle() && GetNavigationHandle()->GetNetErrorCode() ==
+ net::ERR_BLOCKED_BY_CLIENT) {
+ // Since this is known to be an error page commit, verify it happened in
+ // a unique origin, terminating the renderer process otherwise.
+ if (!validated_params->origin.unique()) {
+ DEBUG_ALIAS_FOR_ORIGIN(origin_debug_alias, validated_params->origin);
+ bad_message::ReceivedBadMessage(
+ process, bad_message::RFH_ERROR_PROCESS_NON_UNIQUE_ORIGIN_COMMIT);
+ return false;
+ }
+
+ is_permitted_error_page = true;
}
}
@@ -5460,4 +5636,25 @@ RenderFrameHostImpl::CloneSubresourceFactories() {
return nullptr;
}
+std::unique_ptr<base::trace_event::TracedValue>
+RenderFrameHostImpl::CommitAsTracedValue(
+ FrameHostMsg_DidCommitProvisionalLoad_Params* validated_params) const {
+ auto value = std::make_unique<base::trace_event::TracedValue>();
+
+ value->SetInteger("frame_tree_node", frame_tree_node_->frame_tree_node_id());
+ value->SetInteger("site id", site_instance_->GetId());
+ value->SetString("process lock", ChildProcessSecurityPolicyImpl::GetInstance()
+ ->GetOriginLock(process_->GetID())
+ .spec());
+ value->SetString("origin", validated_params->origin.Serialize());
+ value->SetInteger("transition", validated_params->transition);
+
+ if (!validated_params->base_url.is_empty()) {
+ value->SetString("base_url",
+ validated_params->base_url.possibly_invalid_spec());
+ }
+
+ return value;
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/render_frame_host_impl.h b/chromium/content/browser/frame_host/render_frame_host_impl.h
index 6c6f78fec35..d71a3c050e6 100644
--- a/chromium/content/browser/frame_host/render_frame_host_impl.h
+++ b/chromium/content/browser/frame_host/render_frame_host_impl.h
@@ -30,7 +30,6 @@
#include "build/build_config.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/bad_message.h"
-#include "content/browser/loader/global_routing_id.h"
#include "content/browser/renderer_host/media/old_render_frame_audio_input_stream_factory.h"
#include "content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory.h"
#include "content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h"
@@ -50,6 +49,7 @@
#include "content/common/navigation_params.mojom.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/common/javascript_dialog_type.h"
#include "content/public/common/previews_state.h"
@@ -65,10 +65,10 @@
#include "third_party/blink/public/common/feature_policy/feature_policy.h"
#include "third_party/blink/public/common/frame/user_activation_update_type.h"
#include "third_party/blink/public/mojom/frame/find_in_page.mojom.h"
+#include "third_party/blink/public/mojom/presentation/presentation.mojom.h"
#include "third_party/blink/public/platform/dedicated_worker_factory.mojom.h"
#include "third_party/blink/public/platform/modules/bluetooth/web_bluetooth.mojom.h"
-#include "third_party/blink/public/platform/modules/presentation/presentation.mojom.h"
-#include "third_party/blink/public/platform/modules/webauth/authenticator.mojom.h"
+#include "third_party/blink/public/platform/modules/webauthn/authenticator.mojom.h"
#include "third_party/blink/public/platform/web_focus_type.h"
#include "third_party/blink/public/platform/web_insecure_request_policy.h"
#include "third_party/blink/public/platform/web_scroll_types.h"
@@ -103,10 +103,16 @@ class ListValue;
}
namespace blink {
+class AssociatedInterfaceProvider;
+class AssociatedInterfaceRegistry;
struct FramePolicy;
struct WebFullscreenOptions;
struct WebScrollIntoViewParams;
+
+namespace mojom {
+class WebUsbService;
}
+} // namespace blink
namespace gfx {
class Range;
@@ -118,8 +124,6 @@ struct ResourceResponse;
} // namespace network
namespace content {
-class AssociatedInterfaceProviderImpl;
-class AssociatedInterfaceRegistryImpl;
class AuthenticatorImpl;
class FrameTree;
class FrameTreeNode;
@@ -247,7 +251,7 @@ class CONTENT_EXPORT RenderFrameHostImpl
void ExecuteMediaPlayerActionAtLocation(
const gfx::Point&,
const blink::WebMediaPlayerAction& action) override;
- void CreateNetworkServiceDefaultFactory(
+ bool CreateNetworkServiceDefaultFactory(
network::mojom::URLLoaderFactoryRequest default_factory_request) override;
// IPC::Sender
@@ -776,6 +780,15 @@ class CONTENT_EXPORT RenderFrameHostImpl
service_manager::mojom::InterfaceProviderRequest
interface_provider_request);
+ service_manager::BinderRegistry& BinderRegistryForTesting() {
+ return *registry_;
+ }
+
+ // Called when the WebAudio AudioContext given by |audio_context_id| has
+ // started (or stopped) playing audible audio.
+ void AudioContextPlaybackStarted(int audio_context_id);
+ void AudioContextPlaybackStopped(int audio_context_id);
+
protected:
friend class RenderFrameHostFactory;
@@ -819,6 +832,9 @@ class CONTENT_EXPORT RenderFrameHostImpl
FRIEND_TEST_ALL_PREFIXES(RenderFrameHostManagerTest,
WebUIJavascriptDisallowedAfterSwapOut);
FRIEND_TEST_ALL_PREFIXES(RenderFrameHostManagerTest, LastCommittedOrigin);
+ FRIEND_TEST_ALL_PREFIXES(
+ RenderFrameHostManagerUnloadBrowserTest,
+ PendingDeleteRFHProcessShutdownDoesNotRemoveSubframes);
FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest, CrashSubframe);
FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest, FindImmediateLocalRoots);
FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest,
@@ -839,6 +855,8 @@ class CONTENT_EXPORT RenderFrameHostImpl
SwapOutACKArrivesPriorToProcessShutdownRequest);
FRIEND_TEST_ALL_PREFIXES(SecurityExploitBrowserTest,
AttemptDuplicateRenderViewHost);
+ FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest,
+ FullscreenAfterFrameSwap);
class DroppedInterfaceRequestLogger;
@@ -1037,8 +1055,19 @@ class CONTENT_EXPORT RenderFrameHostImpl
// Creates a Network Service-backed factory from appropriate |NetworkContext|
// and sets a connection error handler to trigger
- // |OnNetworkServiceConnectionError()| if the factory is out-of-process.
- void CreateNetworkServiceDefaultFactoryAndObserve(
+ // |OnNetworkServiceConnectionError()| if the factory is out-of-process. If
+ // this returns true, any redirect safety checks should be bypassed in
+ // downstream loaders.
+ // |url| is the URL that the RenderFrame is either committing (in the case of
+ // navigation) or has last committed (when handling network process crashes).
+ bool CreateNetworkServiceDefaultFactoryAndObserve(
+ const GURL& url,
+ network::mojom::URLLoaderFactoryRequest default_factory_request);
+
+ // |url| is the URL that the RenderFrame is either committing (in the case of
+ // navigation) or has last committed (when handling network process crashes).
+ bool CreateNetworkServiceDefaultFactoryInternal(
+ const GURL& url,
network::mojom::URLLoaderFactoryRequest default_factory_request);
// Returns true if the ExecuteJavaScript() API can be used on this host.
@@ -1084,8 +1113,8 @@ class CONTENT_EXPORT RenderFrameHostImpl
WebBluetoothServiceImpl* web_bluetooth_service);
// Creates connections to WebUSB interfaces bound to this frame.
- void CreateUsbDeviceManager(device::mojom::UsbDeviceManagerRequest request);
- void CreateUsbChooserService(device::mojom::UsbChooserServiceRequest request);
+ void CreateWebUsbService(
+ mojo::InterfaceRequest<blink::mojom::WebUsbService> request);
void CreateAudioInputStreamFactory(
mojom::RendererAudioInputStreamFactoryRequest request);
@@ -1262,6 +1291,11 @@ class CONTENT_EXPORT RenderFrameHostImpl
std::unique_ptr<URLLoaderFactoryBundleInfo> bundle_info);
std::unique_ptr<URLLoaderFactoryBundleInfo> CloneSubresourceFactories();
+ // Creates a TracedValue object containing the details of a committed
+ // navigation, so it can be logged with the tracing system.
+ std::unique_ptr<base::trace_event::TracedValue> CommitAsTracedValue(
+ FrameHostMsg_DidCommitProvisionalLoad_Params* validated_params) const;
+
// For now, RenderFrameHosts indirectly keep RenderViewHosts alive via a
// refcount that calls Shutdown when it reaches zero. This allows each
// RenderFrameHostManager to just care about RenderFrameHosts, while ensuring
@@ -1412,7 +1446,7 @@ class CONTENT_EXPORT RenderFrameHostImpl
// SensorProvider proxy which acts as a gatekeeper to the real SensorProvider.
std::unique_ptr<SensorProviderProxyImpl> sensor_provider_proxy_;
- std::unique_ptr<AssociatedInterfaceRegistryImpl> associated_registry_;
+ std::unique_ptr<blink::AssociatedInterfaceRegistry> associated_registry_;
std::unique_ptr<service_manager::BinderRegistry> registry_;
std::unique_ptr<service_manager::InterfaceProvider> remote_interfaces_;
@@ -1584,7 +1618,7 @@ class CONTENT_EXPORT RenderFrameHostImpl
std::unique_ptr<AuthenticatorImpl> authenticator_impl_;
#endif
- std::unique_ptr<AssociatedInterfaceProviderImpl>
+ std::unique_ptr<blink::AssociatedInterfaceProvider>
remote_associated_interfaces_;
// A bitwise OR of bindings types that have been enabled for this RenderFrame.
@@ -1674,6 +1708,18 @@ class CONTENT_EXPORT RenderFrameHostImpl
network::mojom::URLLoaderFactoryPtr
network_service_connection_error_handler_holder_;
+ // Holds the renderer generated ID and global request ID for the main frame
+ // request.
+ std::pair<int, GlobalRequestID> main_frame_request_ids_;
+
+ // If |ResourceLoadComplete()| is called for the main resource before
+ // |DidCommitProvisionalLoad()|, the load info is saved here to call
+ // |ResourceLoadComplete()| when |DidCommitProvisionalLoad()| is called. This
+ // is necessary so the renderer ID can be mapped to the global ID in
+ // |DidCommitProvisionalLoad()|. This situation should only happen when an
+ // empty document is loaded.
+ mojom::ResourceLoadInfoPtr deferred_main_frame_load_info_;
+
// NOTE: This must be the last member.
base::WeakPtrFactory<RenderFrameHostImpl> weak_ptr_factory_;
diff --git a/chromium/content/browser/frame_host/render_frame_host_impl_browsertest.cc b/chromium/content/browser/frame_host/render_frame_host_impl_browsertest.cc
index 87210e4c20e..bea486b54d1 100644
--- a/chromium/content/browser/frame_host/render_frame_host_impl_browsertest.cc
+++ b/chromium/content/browser/frame_host/render_frame_host_impl_browsertest.cc
@@ -17,6 +17,7 @@
#include "content/browser/frame_host/navigation_handle_impl.h"
#include "content/browser/interface_provider_filtering.h"
#include "content/browser/renderer_host/input/timeout_monitor.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/frame_messages.h"
#include "content/public/browser/javascript_dialog_manager.h"
@@ -28,6 +29,7 @@
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/navigation_handle_observer.h"
#include "content/public/test/test_frame_navigation_observer.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
@@ -1831,4 +1833,87 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
main_frame->GetCanonicalUrlForSharing(base::DoNothing());
}
+// This test makes sure that when a blocked frame commits with a different URL,
+// it doesn't lead to a leaked NavigationHandle. This is a regression test for
+// https://crbug.com/872803.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
+ ErrorPagesShouldntLeakNavigationHandles) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "foo.com", "/frame_tree/page_with_one_frame.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ GURL blocked_url(embedded_test_server()->GetURL(
+ "blocked.com", "/frame-ancestors-none.html"));
+ WebContents* web_contents = shell()->web_contents();
+ NavigationHandleObserver nav_handle_observer(web_contents, blocked_url);
+ EXPECT_TRUE(NavigateIframeToURL(web_contents, "child0", blocked_url));
+
+ // Verify that the NavigationHandle / NavigationRequest didn't leak.
+ RenderFrameHostImpl* frame = static_cast<RenderFrameHostImpl*>(
+ shell()->web_contents()->GetAllFrames()[1]);
+ EXPECT_EQ(0u, frame->GetNavigationEntryIdsPendingCommit().size());
+
+ // TODO(lukasza, clamy): https://crbug.com/784904: Verify that
+ // WebContentsObserver::DidFinishNavigation was called with the same
+ // NavigationHandle as WebContentsObserver::DidStartNavigation. This requires
+ // properly matching the commit IPC to the NavigationHandle (ignoring that
+ // their URLs do not match - matching instead using navigation id or mojo
+ // interface identity).
+ //
+ // Subsequent checks don't make sense before WCO::DidFinishNavigation is
+ // called - this is why ASSERT_TRUE is used here.
+ // ASSERT_TRUE(nav_handle_observer.has_committed());
+ // EXPECT_EQ(net::ERR_BLOCKED_BY_RESPONSE,
+ // nav_handle_observer.net_error_code());
+
+ // TODO(lukasza): https://crbug.com/759184: Verify
+ // |nav_handle_observer.last_committed_url()| below - this should be possible
+ // once we handle frame-ancestors CSP in the browser process and commit it
+ // with the original URL.
+ // EXPECT_EQ(blocked_url, nav_handle_observer.last_committed_url());
+}
+
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
+ NotifiesProcessHostOfAudibleAudio) {
+ const auto RunPostedTasks = []() {
+ base::RunLoop run_loop;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ run_loop.QuitClosure());
+ run_loop.Run();
+ };
+
+ // Note: Just using the beforeunload.html test document to spin-up a
+ // renderer. Any document will do.
+ EXPECT_TRUE(NavigateToURL(
+ shell(), GetTestUrl("render_frame_host", "beforeunload.html")));
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+ auto* frame = static_cast<RenderFrameHostImpl*>(
+ shell()->web_contents()->GetMainFrame());
+ auto* process = static_cast<RenderProcessHostImpl*>(frame->GetProcess());
+ ASSERT_EQ(0, process->get_media_stream_count_for_testing());
+
+ // Audible audio output should cause the media stream count to increment.
+ frame->OnAudibleStateChanged(true);
+ RunPostedTasks();
+ EXPECT_EQ(1, process->get_media_stream_count_for_testing());
+
+ // Silence should cause the media stream count to decrement.
+ frame->OnAudibleStateChanged(false);
+ RunPostedTasks();
+ EXPECT_EQ(0, process->get_media_stream_count_for_testing());
+
+ // Start audible audio output again, and then crash the renderer. Expect the
+ // media stream count to be zero after the crash.
+ frame->OnAudibleStateChanged(true);
+ RunPostedTasks();
+ EXPECT_EQ(1, process->get_media_stream_count_for_testing());
+ RenderProcessHostWatcher crash_observer(
+ process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+ process->Shutdown(0);
+ crash_observer.Wait();
+ RunPostedTasks();
+ EXPECT_EQ(0, process->get_media_stream_count_for_testing());
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/render_frame_host_manager.cc b/chromium/content/browser/frame_host/render_frame_host_manager.cc
index 872e4609c94..49ad391a313 100644
--- a/chromium/content/browser/frame_host/render_frame_host_manager.cc
+++ b/chromium/content/browser/frame_host/render_frame_host_manager.cc
@@ -1218,7 +1218,8 @@ RenderFrameHostManager::DetermineSiteInstanceForURL(
// thus use the correct process.
bool use_process_per_site =
RenderProcessHost::ShouldUseProcessPerSite(browser_context, dest_url) &&
- RenderProcessHostImpl::GetProcessHostForSite(browser_context, dest_url);
+ RenderProcessHostImpl::GetSoleProcessHostForURL(browser_context,
+ dest_url);
if (current_instance_impl->HasRelatedSiteInstance(dest_url) ||
use_process_per_site) {
return SiteInstanceDescriptor(browser_context, dest_url,
@@ -1540,22 +1541,22 @@ bool RenderFrameHostManager::IsCurrentlySameSite(RenderFrameHostImpl* candidate,
const GURL& dest_url) {
BrowserContext* browser_context =
delegate_->GetControllerForRenderManager().GetBrowserContext();
- // Don't compare effective URLs for all subframe navigations, since we don't
- // want to create OOPIFs based on that mechanism (e.g., for hosted apps). For
- // main frames, don't compare effective URLs when transitioning from app to
- // non-app URLs if there exists another app WebContents that might script
- // this one. These navigations should stay in the app process to not break
- // scripting when a hosted app opens a same-site popup. See
- // https://crbug.com/718516 and https://crbug.com/828720.
+
+ // Ask embedder whether effective URLs should be used when determining if
+ // |dest_url| should end up in |candidate|'s SiteInstance.
+ // This is used to keep same-site scripting working for hosted apps.
+ bool should_compare_effective_urls =
+ GetContentClient()
+ ->browser()
+ ->ShouldCompareEffectiveURLsForSiteInstanceSelection(
+ browser_context, candidate->GetSiteInstance(),
+ frame_tree_node_->IsMainFrame(),
+ candidate->GetSiteInstance()->original_url(), dest_url);
+
bool src_has_effective_url = SiteInstanceImpl::HasEffectiveURL(
browser_context, candidate->GetSiteInstance()->original_url());
bool dest_has_effective_url =
SiteInstanceImpl::HasEffectiveURL(browser_context, dest_url);
- bool should_compare_effective_urls = true;
- if (!frame_tree_node_->IsMainFrame() ||
- (src_has_effective_url && !dest_has_effective_url &&
- candidate->GetSiteInstance()->GetRelatedActiveContentsCount() > 1u))
- should_compare_effective_urls = false;
// If the process type is incorrect, reject the candidate even if |dest_url|
// is same-site. (The URL may have been installed as an app since
@@ -2163,6 +2164,13 @@ void RenderFrameHostManager::CommitPending() {
render_frame_host_->GetView() &&
render_frame_host_->GetView()->HasFocus();
+ // Remove the current frame and its descendants from the set of fullscreen
+ // frames immediately. They can stay in pending deletion for some time.
+ // Removing them when they are deleted is too late.
+ // This needs to be done before updating the frame tree structure, else it
+ // will have trouble removing the descendants.
+ render_frame_delegate_->FullscreenStateChanged(current_frame_host(), false);
+
// While the old frame is still current, remove its children from the tree.
frame_tree_node_->ResetForNewProcess();
diff --git a/chromium/content/browser/frame_host/render_frame_host_manager_browsertest.cc b/chromium/content/browser/frame_host/render_frame_host_manager_browsertest.cc
index c49de36a819..a6821503c3e 100644
--- a/chromium/content/browser/frame_host/render_frame_host_manager_browsertest.cc
+++ b/chromium/content/browser/frame_host/render_frame_host_manager_browsertest.cc
@@ -12,12 +12,14 @@
#include "base/json/json_reader.h"
#include "base/location.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
#include "base/values.h"
#include "build/build_config.h"
#include "content/browser/child_process_security_policy_impl.h"
@@ -30,6 +32,8 @@
#include "content/browser/webui/web_ui_controller_factory_registry.h"
#include "content/browser/webui/web_ui_impl.h"
#include "content/common/content_constants_internal.h"
+#include "content/public/browser/browser_child_process_host.h"
+#include "content/public/browser/child_process_launcher_utils.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/render_process_host.h"
@@ -181,17 +185,8 @@ class RenderFrameHostManagerTest : public ContentBrowserTest {
std::unique_ptr<content::URLLoaderInterceptor> SetupRequestFailForURL(
const GURL& url) {
- return std::make_unique<content::URLLoaderInterceptor>(base::BindRepeating(
- [](const GURL& url,
- content::URLLoaderInterceptor::RequestParams* params) {
- if (params->url_request.url != url)
- return false;
- network::URLLoaderCompletionStatus status;
- status.error_code = net::ERR_DNS_TIMED_OUT;
- params->client->OnComplete(status);
- return true;
- },
- url));
+ return URLLoaderInterceptor::SetupRequestFailForURL(url,
+ net::ERR_DNS_TIMED_OUT);
}
// Returns a URL on foo.com with the given path.
@@ -2370,7 +2365,7 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, WebUIGetsBindings) {
GURL url1(std::string(kChromeUIScheme) + "://" +
std::string(kChromeUIGpuHost));
GURL url2(std::string(kChromeUIScheme) + "://" +
- std::string(kChromeUIAccessibilityHost));
+ std::string(kChromeUIHistogramHost));
// Visit a WebUI page with bindings.
NavigateToURL(shell(), url1);
@@ -4575,6 +4570,103 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
EXPECT_EQ(error_url.spec(), result);
}
+// Test to verify that navigation to existing history entry, which results in
+// an error page, is correctly placed in the error page SiteInstance.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
+ ErrorPageNavigationHistoryNavigationFailure) {
+ // This test is only valid if error page isolation is enabled.
+ if (!SiteIsolationPolicy::IsErrorPageIsolationEnabled(true))
+ return;
+
+ StartEmbeddedServer();
+
+ // Perform successful navigations to two URLs to establish session history.
+ GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), url1));
+
+ GURL url2(embedded_test_server()->GetURL("b.com", "/title2.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), url2));
+
+ WebContents* web_contents = shell()->web_contents();
+ NavigationControllerImpl& nav_controller =
+ static_cast<NavigationControllerImpl&>(web_contents->GetController());
+
+ // There should be two NavigationEntries.
+ EXPECT_EQ(2, nav_controller.GetEntryCount());
+
+ // Create an interceptor to cause navigations to url1 to fail and go back
+ // in session history.
+ std::unique_ptr<URLLoaderInterceptor> url_interceptor =
+ SetupRequestFailForURL(url1);
+ TestNavigationObserver back_observer(web_contents);
+ nav_controller.GoBack();
+ back_observer.Wait();
+ EXPECT_FALSE(back_observer.last_navigation_succeeded());
+ EXPECT_EQ(2, nav_controller.GetEntryCount());
+ EXPECT_EQ(0, nav_controller.GetLastCommittedEntryIndex());
+
+ EXPECT_EQ(GURL(kUnreachableWebDataURL),
+ web_contents->GetMainFrame()->GetSiteInstance()->GetSiteURL());
+ EXPECT_EQ(GURL(kUnreachableWebDataURL),
+ ChildProcessSecurityPolicyImpl::GetInstance()->GetOriginLock(
+ web_contents->GetSiteInstance()->GetProcess()->GetID()));
+}
+
+// Test to verify that a successful navigation to existing history entry,
+// which initially resulted in an error page, is correctly placed in a
+// SiteInstance different than the error page one.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
+ ErrorPageNavigationHistoryNavigationSuccess) {
+ // This test is only valid if error page isolation is enabled.
+ if (!SiteIsolationPolicy::IsErrorPageIsolationEnabled(true))
+ return;
+
+ StartEmbeddedServer();
+ WebContents* web_contents = shell()->web_contents();
+
+ // Start with a successful navigation.
+ GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), url1));
+
+ // Navigate to URL that results in an error page and verify its SiteInstance.
+ GURL url2(embedded_test_server()->GetURL("b.com", "/title2.html"));
+ std::unique_ptr<URLLoaderInterceptor> url_interceptor =
+ SetupRequestFailForURL(url2);
+
+ EXPECT_FALSE(NavigateToURL(shell(), url2));
+ EXPECT_EQ(GURL(kUnreachableWebDataURL),
+ web_contents->GetMainFrame()->GetSiteInstance()->GetSiteURL());
+ EXPECT_EQ(GURL(kUnreachableWebDataURL),
+ ChildProcessSecurityPolicyImpl::GetInstance()->GetOriginLock(
+ web_contents->GetSiteInstance()->GetProcess()->GetID()));
+
+ // There should be two NavigationEntries.
+ NavigationControllerImpl& nav_controller =
+ static_cast<NavigationControllerImpl&>(web_contents->GetController());
+ EXPECT_EQ(2, nav_controller.GetEntryCount());
+
+ // Navigate once more to create another session history entry.
+ GURL url3(embedded_test_server()->GetURL("c.com", "/title3.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), url3));
+ EXPECT_EQ(3, nav_controller.GetEntryCount());
+
+ // Navigate back, this time remove the interceptor so the navigation will
+ // succeed.
+ url_interceptor.reset();
+ TestNavigationObserver back_observer(web_contents);
+ nav_controller.GoBack();
+ back_observer.Wait();
+ EXPECT_TRUE(back_observer.last_navigation_succeeded());
+ EXPECT_EQ(3, nav_controller.GetEntryCount());
+ EXPECT_EQ(1, nav_controller.GetLastCommittedEntryIndex());
+
+ EXPECT_NE(GURL(kUnreachableWebDataURL),
+ web_contents->GetMainFrame()->GetSiteInstance()->GetSiteURL());
+ EXPECT_NE(GURL(kUnreachableWebDataURL),
+ ChildProcessSecurityPolicyImpl::GetInstance()->GetOriginLock(
+ web_contents->GetSiteInstance()->GetProcess()->GetID()));
+}
+
// A NavigationThrottle implementation that blocks all outgoing navigation
// requests for a specific WebContents. It is used to block navigations to
// WebUI URLs in the following test.
@@ -5001,4 +5093,286 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerUnloadBrowserTest,
EXPECT_EQ("bar", message);
}
+// Ensure that when a pending delete RenderFrameHost's process dies, the
+// current RenderFrameHost does not lose its child frames. See
+// https://crbug.com/867274.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerUnloadBrowserTest,
+ PendingDeleteRFHProcessShutdownDoesNotRemoveSubframes) {
+ GURL first_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), first_url));
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ RenderFrameHostImpl* rfh = root->current_frame_host();
+
+ // Set up an unload handler which never finishes to force |rfh| to stay
+ // around in pending delete state and never receive the swapout ACK.
+ EXPECT_TRUE(
+ ExecuteScript(rfh, "window.onunload = function(e) { while(1); };\n"));
+ rfh->DisableSwapOutTimerForTesting();
+
+ // Navigate to another page with two subframes.
+ RenderFrameDeletedObserver rfh_observer(rfh);
+ GURL second_url(embedded_test_server()->GetURL(
+ "b.com", "/cross_site_iframe_factory.html?b(c,b)"));
+ EXPECT_TRUE(NavigateToURL(shell(), second_url));
+
+ // At this point, |rfh| should still be live and pending deletion.
+ EXPECT_FALSE(rfh_observer.deleted());
+ EXPECT_FALSE(rfh->is_active());
+ EXPECT_TRUE(rfh->IsRenderFrameLive());
+
+ // Meanwhile, the new page should have two subframes.
+ EXPECT_EQ(2U, root->child_count());
+
+ // Kill the pending delete RFH's process.
+ RenderProcessHostWatcher crash_observer(
+ rfh->GetProcess(), RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+ rfh->GetProcess()->Shutdown(0);
+ crash_observer.Wait();
+
+ // The process kill should simulate a swapout ACK and trigger destruction of
+ // the pending delete RFH.
+ rfh_observer.WaitUntilDeleted();
+
+ // Ensure that the process kill didn't incorrectly remove subframes from the
+ // new page.
+ ASSERT_EQ(2U, root->child_count());
+ EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
+ EXPECT_TRUE(root->child_at(1)->current_frame_host()->IsRenderFrameLive());
+}
+
+namespace {
+
+// A helper to post a recurring check that a renderer process is foregrounded.
+// The recurring check uses WeakPtr semantic and will die when this class goes
+// out of scope.
+class AssertForegroundHelper {
+ public:
+ AssertForegroundHelper() : weak_ptr_factory_(this) {}
+
+#if defined(OS_MACOSX)
+ // Asserts that |renderer_process| isn't backgrounded and reposts self to
+ // check again shortly. |renderer_process| must outlive this
+ // AssertForegroundHelper instance.
+ void AssertForegroundAndRepost(const base::Process& renderer_process,
+ base::PortProvider* port_provider) {
+ ASSERT_FALSE(renderer_process.IsProcessBackgrounded(port_provider));
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&AssertForegroundHelper::AssertForegroundAndRepost,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::ConstRef(renderer_process), port_provider),
+ base::TimeDelta::FromMilliseconds(1));
+ }
+#else // defined(OS_MACOSX)
+ // Same as above without the Mac specific base::PortProvider.
+ void AssertForegroundAndRepost(const base::Process& renderer_process) {
+ ASSERT_FALSE(renderer_process.IsProcessBackgrounded());
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&AssertForegroundHelper::AssertForegroundAndRepost,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::ConstRef(renderer_process)),
+ base::TimeDelta::FromMilliseconds(1));
+ }
+#endif // defined(OS_MACOSX)
+
+ private:
+ base::WeakPtrFactory<AssertForegroundHelper> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(AssertForegroundHelper);
+};
+
+// Observer class that waits until the OS process for a specific
+// RenderProcessHost is ready to be used.
+// TODO(nasko): Consider moving this into RenderProcessHostWatcher.
+class RenderProcessReadyObserver : public RenderProcessHostObserver {
+ public:
+ RenderProcessReadyObserver(RenderProcessHost* render_process_host)
+ : render_process_host_(render_process_host),
+ quit_closure_(run_loop_.QuitClosure()) {
+ render_process_host_->AddObserver(this);
+ }
+ ~RenderProcessReadyObserver() override {
+ render_process_host_->RemoveObserver(this);
+ }
+
+ // Waits until the renderer process is ready.
+ void Wait() { run_loop_.Run(); }
+
+ private:
+ // RenderProcessHostObserver overrides.
+ void RenderProcessReady(RenderProcessHost* host) override {
+ std::move(quit_closure_).Run();
+ }
+
+ RenderProcessHost* render_process_host_;
+ base::RunLoop run_loop_;
+ base::OnceClosure quit_closure_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderProcessReadyObserver);
+};
+
+} // namespace
+
+// This is a regression test for https://crbug.com/560446. It ensures the
+// newly launched process for cross-process navigation in the foreground
+// WebContents isn't backgrounded prior to the navigation committing and a
+// "visible" widget being added to the process. This test discards the spare
+// RenderProcessHost if present, to ensure that it is not used in the
+// cross-process navigation.
+IN_PROC_BROWSER_TEST_F(
+ RenderFrameHostManagerTest,
+ ForegroundNavigationIsNeverBackgroundedWithoutSpareProcess) {
+ StartEmbeddedServer();
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+
+#if defined(OS_MACOSX)
+ base::PortProvider* port_provider =
+ BrowserChildProcessHost::GetPortProvider();
+#endif // defined(OS_MACOSX)
+
+ // Start off navigating to a.com and capture the process used to commit.
+ EXPECT_TRUE(NavigateToURL(
+ shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
+ RenderProcessHost* start_rph = web_contents->GetMainFrame()->GetProcess();
+
+ // Discard the spare RenderProcessHost to ensure a new RenderProcessHost
+ // is created and has the right prioritization.
+ RenderProcessHostImpl::DiscardSpareRenderProcessHostForTesting();
+ EXPECT_FALSE(RenderProcessHostImpl::GetSpareRenderProcessHostForTesting());
+
+ // Start a navigation to b.com to ensure a cross-process navigation is
+ // in progress and ensure the process for the speculative host is different.
+ GURL url(embedded_test_server()->GetURL("b.com", "/title2.html"));
+ content::TestNavigationManager navigation_manager(web_contents, url);
+
+ shell()->LoadURL(url);
+ RenderProcessHost* speculative_rph = web_contents->GetFrameTree()
+ ->root()
+ ->render_manager()
+ ->speculative_frame_host()
+ ->GetProcess();
+ EXPECT_NE(start_rph, speculative_rph);
+ EXPECT_FALSE(speculative_rph->IsReady());
+
+#if !defined(OS_ANDROID)
+ // TODO(gab, nasko): On Android IsProcessBackgrounded is currently giving
+ // incorrect value at this stage of the process lifetime. This should be
+ // fixed in follow up cleanup work. See https://crbug.com/560446.
+ EXPECT_FALSE(speculative_rph->IsProcessBackgrounded());
+#endif
+
+ // Wait for the underlying OS process to have launched and be ready to
+ // receive IPCs.
+ RenderProcessReadyObserver process_observer(speculative_rph);
+ process_observer.Wait();
+
+ // Kick off an infinite check against self that the process used for
+ // navigation is never backgrounded. The WaitForNavigationFinished will wait
+ // inside a RunLoop() and hence perform this check regularly throughout the
+ // navigation.
+ const base::Process& process = speculative_rph->GetProcess();
+ EXPECT_TRUE(process.IsValid());
+ AssertForegroundHelper assert_foreground_helper;
+#if defined(OS_MACOSX)
+ assert_foreground_helper.AssertForegroundAndRepost(process, port_provider);
+#else
+ assert_foreground_helper.AssertForegroundAndRepost(process);
+#endif
+
+ // The process should be foreground priority before commit because it is
+ // pending, and foreground after commit because it has a visible widget.
+ navigation_manager.WaitForNavigationFinished();
+ EXPECT_NE(start_rph, web_contents->GetMainFrame()->GetProcess());
+ EXPECT_EQ(speculative_rph, web_contents->GetMainFrame()->GetProcess());
+}
+
+// Similar to the test above, but verifies the spare RenderProcessHost uses the
+// right priority.
+IN_PROC_BROWSER_TEST_F(
+ RenderFrameHostManagerTest,
+ ForegroundNavigationIsNeverBackgroundedWithSpareProcess) {
+ // This test applies only when spare RenderProcessHost is enabled and in use.
+ if (!RenderProcessHostImpl::IsSpareProcessKeptAtAllTimes())
+ return;
+
+ StartEmbeddedServer();
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+
+#if defined(OS_MACOSX)
+ base::PortProvider* port_provider =
+ BrowserChildProcessHost::GetPortProvider();
+#endif // defined(OS_MACOSX)
+
+ // Start off navigating to a.com and capture the process used to commit.
+ EXPECT_TRUE(NavigateToURL(
+ shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
+ RenderProcessHost* start_rph = web_contents->GetMainFrame()->GetProcess();
+
+ // At this time, there should be a spare RenderProcesHost. Capture it for
+ // testing expectations later.
+ RenderProcessHost* spare_rph =
+ RenderProcessHostImpl::GetSpareRenderProcessHostForTesting();
+ EXPECT_TRUE(spare_rph);
+ EXPECT_TRUE(spare_rph->IsProcessBackgrounded());
+
+ // Start a navigation to b.com to ensure a cross-process navigation is
+ // in progress and ensure the process for the speculative host is
+ // different, but matches the spare RenderProcessHost.
+ GURL url(embedded_test_server()->GetURL("b.com", "/title2.html"));
+ content::TestNavigationManager navigation_manager(web_contents, url);
+
+ shell()->LoadURL(url);
+ RenderProcessHost* speculative_rph = web_contents->GetFrameTree()
+ ->root()
+ ->render_manager()
+ ->speculative_frame_host()
+ ->GetProcess();
+ EXPECT_NE(start_rph, speculative_rph);
+
+ // In this test case, the spare RenderProcessHost will be used, so verify it
+ // and ensure it is ready.
+ EXPECT_EQ(spare_rph, speculative_rph);
+ EXPECT_TRUE(spare_rph->IsReady());
+
+ // The creation of the speculative RenderFrameHost should change the
+ // RenderProcessHost's copy of the priority of the spare process from
+ // background to foreground.
+ EXPECT_FALSE(spare_rph->IsProcessBackgrounded());
+
+ // The OS process itself is updated on the process launcher thread, so it
+ // cannot be observed immediately here. Perform a thread hop to and back to
+ // allow for the priority change to occur before using the
+ // AssertForegroundHelper object to check the OS process priority.
+ {
+ base::RunLoop run_loop;
+ GetProcessLauncherTaskRunner()->PostTaskAndReply(
+ FROM_HERE, base::DoNothing(), run_loop.QuitWhenIdleClosure());
+ run_loop.Run();
+ }
+
+ // Kick off an infinite check against self that the process used for
+ // navigation is never backgrounded. The WaitForNavigationFinished will wait
+ // inside a RunLoop() and hence perform this check regularly throughout the
+ // navigation.
+ const base::Process& process = spare_rph->GetProcess();
+ EXPECT_TRUE(process.IsValid());
+ AssertForegroundHelper assert_foreground_helper;
+#if defined(OS_MACOSX)
+ assert_foreground_helper.AssertForegroundAndRepost(process, port_provider);
+#else
+ assert_foreground_helper.AssertForegroundAndRepost(process);
+#endif
+
+ // The process should be foreground priority before commit because it is
+ // pending, and foreground after commit because it has a visible widget.
+ navigation_manager.WaitForNavigationFinished();
+ EXPECT_NE(start_rph, web_contents->GetMainFrame()->GetProcess());
+ EXPECT_EQ(speculative_rph, web_contents->GetMainFrame()->GetProcess());
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/render_frame_host_manager_unittest.cc b/chromium/content/browser/frame_host/render_frame_host_manager_unittest.cc
index b4fb251d110..bc5e48e26e0 100644
--- a/chromium/content/browser/frame_host/render_frame_host_manager_unittest.cc
+++ b/chromium/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -3159,13 +3159,17 @@ TEST_F(RenderFrameHostManagerTest,
// Simulate a browser-initiated navigation to an app URL, which should swap
// processes and create a new SiteInstance in a new BrowsingInstance.
- // This new SiteInstance should have correct site URL and |original_url()|.
+ // This new SiteInstance should have correct |original_url()| and site URL.
+ // The site URL should include both the |original_url()|'s site and the
+ // translated URL's site.
NavigationSimulator::NavigateAndCommitFromBrowser(contents(), kOriginalUrl);
EXPECT_NE(initial_instance.get(), main_test_rfh()->GetSiteInstance());
EXPECT_FALSE(initial_instance->IsRelatedSiteInstance(
main_test_rfh()->GetSiteInstance()));
EXPECT_EQ(kOriginalUrl, main_test_rfh()->GetSiteInstance()->original_url());
- EXPECT_EQ(kTranslatedUrl, main_test_rfh()->GetSiteInstance()->GetSiteURL());
+ GURL expected_site_url(kTranslatedUrl.spec() + "#" + kOriginalUrl.spec());
+ EXPECT_EQ(expected_site_url,
+ main_test_rfh()->GetSiteInstance()->GetSiteURL());
SetBrowserClientForTesting(regular_client);
}
diff --git a/chromium/content/browser/frame_host/render_frame_message_filter.cc b/chromium/content/browser/frame_host/render_frame_message_filter.cc
index 2f32390f0b4..dfd9bb1aa8c 100644
--- a/chromium/content/browser/frame_host/render_frame_message_filter.cc
+++ b/chromium/content/browser/frame_host/render_frame_message_filter.cc
@@ -271,19 +271,6 @@ RenderFrameMessageFilter::RenderFrameMessageFilter(
render_widget_helper_(render_widget_helper),
incognito_(browser_context->IsOffTheRecord()),
render_process_id_(render_process_id) {
- network::mojom::CookieManagerPtr cookie_manager;
- storage_partition->GetNetworkContext()->GetCookieManager(
- mojo::MakeRequest(&cookie_manager));
-
- // The PostTask below could finish before the constructor returns which would
- // lead to this object being destructed prematurely.
- AddRef();
- base::ThreadTaskRunnerHandle::Get()->ReleaseSoon(FROM_HERE, this);
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(&RenderFrameMessageFilter::InitializeOnIO, this,
- cookie_manager.PassInterface()));
}
RenderFrameMessageFilter::~RenderFrameMessageFilter() {
@@ -291,9 +278,26 @@ RenderFrameMessageFilter::~RenderFrameMessageFilter() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
}
-void RenderFrameMessageFilter::InitializeOnIO(
- network::mojom::CookieManagerPtrInfo cookie_manager) {
- cookie_manager_.Bind(std::move(cookie_manager));
+network::mojom::CookieManagerPtr* RenderFrameMessageFilter::GetCookieManager() {
+ if (!cookie_manager_ || cookie_manager_.encountered_error()) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&RenderFrameMessageFilter::InitializeCookieManager, this,
+ mojo::MakeRequest(&cookie_manager_)));
+ }
+ return &cookie_manager_;
+}
+
+void RenderFrameMessageFilter::InitializeCookieManager(
+ network::mojom::CookieManagerRequest cookie_manager_request) {
+ RenderProcessHost* render_process_host =
+ RenderProcessHost::FromID(render_process_id_);
+ if (!render_process_host)
+ return;
+
+ render_process_host->GetStoragePartition()
+ ->GetNetworkContext()
+ ->GetCookieManager(std::move(cookie_manager_request));
}
bool RenderFrameMessageFilter::OnMessageReceived(const IPC::Message& message) {
@@ -556,9 +560,10 @@ void RenderFrameMessageFilter::SetCookie(int32_t render_frame_id,
// this process' StoragePartition.
if (base::FeatureList::IsEnabled(network::features::kNetworkService) &&
context == request_context_->GetURLRequestContext()) {
- cookie_manager_->SetCanonicalCookie(*cookie, url.SchemeIsCryptographic(),
- !options.exclude_httponly(),
- net::CookieStore::SetCookiesCallback());
+ (*GetCookieManager())
+ ->SetCanonicalCookie(*cookie, url.SchemeIsCryptographic(),
+ !options.exclude_httponly(),
+ net::CookieStore::SetCookiesCallback());
return;
}
@@ -605,11 +610,12 @@ void RenderFrameMessageFilter::GetCookies(int render_frame_id,
context == request_context_->GetURLRequestContext()) {
// TODO(jam): modify GetRequestContextForURL to work with network service.
// Merge this with code path below for non-network service.
- cookie_manager_->GetCookieList(
- url, options,
- base::BindOnce(&RenderFrameMessageFilter::CheckPolicyForCookies, this,
- render_frame_id, url, site_for_cookies,
- std::move(callback)));
+ (*GetCookieManager())
+ ->GetCookieList(
+ url, options,
+ base::BindOnce(&RenderFrameMessageFilter::CheckPolicyForCookies,
+ this, render_frame_id, url, site_for_cookies,
+ std::move(callback)));
return;
}
diff --git a/chromium/content/browser/frame_host/render_frame_message_filter.h b/chromium/content/browser/frame_host/render_frame_message_filter.h
index 9716b200806..a661ac52665 100644
--- a/chromium/content/browser/frame_host/render_frame_message_filter.h
+++ b/chromium/content/browser/frame_host/render_frame_message_filter.h
@@ -73,6 +73,8 @@ class CONTENT_EXPORT RenderFrameMessageFilter
bool OnMessageReceived(const IPC::Message& message) override;
void OnDestruct() const override;
+ network::mojom::CookieManagerPtr* GetCookieManager();
+
protected:
friend class TestSaveImageFromDataURL;
@@ -97,7 +99,8 @@ class CONTENT_EXPORT RenderFrameMessageFilter
~RenderFrameMessageFilter() override;
- void InitializeOnIO(network::mojom::CookieManagerPtrInfo cookie_manager);
+ void InitializeCookieManager(
+ network::mojom::CookieManagerRequest cookie_manager_request);
// |new_render_frame_id| and |devtools_frame_token| are out parameters.
// Browser process defines them for the renderer process.
diff --git a/chromium/content/browser/frame_host/render_frame_proxy_host.cc b/chromium/content/browser/frame_host/render_frame_proxy_host.cc
index b06a4b9242d..bad4c9fc4eb 100644
--- a/chromium/content/browser/frame_host/render_frame_proxy_host.cc
+++ b/chromium/content/browser/frame_host/render_frame_proxy_host.cc
@@ -8,8 +8,6 @@
#include <vector>
#include "base/callback.h"
-#include "base/debug/alias.h"
-#include "base/debug/dump_without_crashing.h"
#include "base/lazy_instance.h"
#include "content/browser/bad_message.h"
#include "content/browser/blob_storage/chrome_blob_storage_context.h"
@@ -204,30 +202,6 @@ bool RenderFrameProxyHost::InitRenderFrameProxy() {
site_instance_.get());
}
- // Temporary debugging code for https://crbug.com/794625 to see if we're ever
- // sending a message to create a RenderFrameProxy when one already exists.
- // TODO(alexmos): Remove after the investigation.
- if (render_frame_proxy_created_) {
- SiteInstanceImpl* site_instance =
- static_cast<SiteInstanceImpl*>(site_instance_.get());
- GURL site_url(site_instance->GetSiteURL());
- DEBUG_ALIAS_FOR_GURL(site_url_copy, site_url);
- GURL current_rfh_site_url(frame_tree_node_->render_manager()
- ->current_frame_host()
- ->GetSiteInstance()
- ->GetSiteURL());
- DEBUG_ALIAS_FOR_GURL(current_rfh_site_url_copy, current_rfh_site_url);
-
- int routing_id_copy = routing_id_;
- base::debug::Alias(&routing_id_copy);
- int parent_routing_id_copy = parent_routing_id;
- base::debug::Alias(&parent_routing_id_copy);
- int active_frame_count = site_instance->active_frame_count();
- base::debug::Alias(&active_frame_count);
-
- base::debug::DumpWithoutCrashing();
- }
-
int view_routing_id = frame_tree_node_->frame_tree()
->GetRenderViewHost(site_instance_.get())->GetRoutingID();
GetProcess()->GetRendererInterface()->CreateFrameProxy(
@@ -235,7 +209,7 @@ bool RenderFrameProxyHost::InitRenderFrameProxy() {
frame_tree_node_->current_replication_state(),
frame_tree_node_->devtools_frame_token());
- render_frame_proxy_created_ = true;
+ set_render_frame_proxy_created(true);
// For subframes, initialize the proxy's FrameOwnerProperties only if they
// differ from default values.
diff --git a/chromium/content/browser/frame_host/render_widget_host_view_guest.cc b/chromium/content/browser/frame_host/render_widget_host_view_guest.cc
index 7c08ae7a4ee..86c4876e2d4 100644
--- a/chromium/content/browser/frame_host/render_widget_host_view_guest.cc
+++ b/chromium/content/browser/frame_host/render_widget_host_view_guest.cc
@@ -186,15 +186,6 @@ bool RenderWidgetHostViewGuest::HasFocus() const {
return guest_->focused();
}
-#if defined(USE_AURA)
-void RenderWidgetHostViewGuest::ProcessAckedTouchEvent(
- const TouchEventWithLatencyInfo& touch, InputEventAckState ack_result) {
- // TODO(tdresser): Since all ProcessAckedTouchEvent() uses is the event id,
- // don't pass the full event object here. https://crbug.com/550581.
- GetOwnerRenderWidgetHostView()->ProcessAckedTouchEvent(touch, ack_result);
-}
-#endif
-
void RenderWidgetHostViewGuest::PreProcessMouseEvent(
const blink::WebMouseEvent& event) {
if (event.GetType() == blink::WebInputEvent::kMouseDown) {
@@ -354,6 +345,10 @@ gfx::Range RenderWidgetHostViewGuest::GetSelectedRange() {
return platform_view_->GetSelectedRange();
}
+size_t RenderWidgetHostViewGuest::GetOffsetForSurroundingText() {
+ return platform_view_->GetOffsetForSurroundingText();
+}
+
void RenderWidgetHostViewGuest::SetNeedsBeginFrames(bool needs_begin_frames) {
if (platform_view_)
platform_view_->SetNeedsBeginFrames(needs_begin_frames);
@@ -392,7 +387,7 @@ void RenderWidgetHostViewGuest::OnDidUpdateVisualPropertiesComplete(
void RenderWidgetHostViewGuest::OnAttached() {
RegisterFrameSinkId();
#if defined(USE_AURA)
- if (!features::IsAshInBrowserProcess()) {
+ if (features::IsUsingWindowService()) {
aura::Env::GetInstance()->ScheduleEmbed(
GetWindowTreeClientFromRenderer(),
base::BindOnce(&RenderWidgetHostViewGuest::OnGotEmbedToken,
@@ -412,6 +407,10 @@ bool RenderWidgetHostViewGuest::OnMessageReceived(const IPC::Message& msg) {
return platform_view_->OnMessageReceived(msg);
}
+RenderWidgetHostViewBase* RenderWidgetHostViewGuest::GetRootView() {
+ return GetRootView(this);
+}
+
void RenderWidgetHostViewGuest::InitAsChild(
gfx::NativeView parent_view) {
// This should never get called.
@@ -616,11 +615,17 @@ RenderWidgetHostViewGuest::GetOwnerRenderWidgetHostView() const {
: nullptr;
}
+void RenderWidgetHostViewGuest::MaybeSendSyntheticTapGestureForTest(
+ const blink::WebFloatPoint& position,
+ const blink::WebFloatPoint& screen_position) const {
+ MaybeSendSyntheticTapGesture(position, screen_position);
+}
+
// TODO(wjmaclean): When we remove BrowserPlugin, delete this code.
// http://crbug.com/533069
void RenderWidgetHostViewGuest::MaybeSendSyntheticTapGesture(
const blink::WebFloatPoint& position,
- const blink::WebFloatPoint& screenPosition) const {
+ const blink::WebFloatPoint& screen_position) const {
if (!HasFocus()) {
// We need to a account for the position of the guest view within the
// embedder, as well as the fact that the embedder's host will add its
@@ -636,7 +641,14 @@ void RenderWidgetHostViewGuest::MaybeSendSyntheticTapGesture(
blink::kWebGestureDeviceTouchscreen);
gesture_tap_event.SetPositionInWidget(
blink::WebFloatPoint(position.x + offset.x(), position.y + offset.y()));
- gesture_tap_event.SetPositionInScreen(screenPosition);
+ gesture_tap_event.SetPositionInScreen(screen_position);
+ // The touch action may not be set yet because this is still at the
+ // Pre-processing stage of a mouse or a touch event. In this case, set the
+ // touch action to Auto to prevent crashing.
+ static_cast<RenderWidgetHostImpl*>(
+ GetOwnerRenderWidgetHostView()->GetRenderWidgetHost())
+ ->input_router()
+ ->ForceSetTouchActionAuto();
GetOwnerRenderWidgetHostView()->ProcessGestureEvent(
gesture_tap_event, ui::LatencyInfo(ui::SourceEventType::TOUCH));
diff --git a/chromium/content/browser/frame_host/render_widget_host_view_guest.h b/chromium/content/browser/frame_host/render_widget_host_view_guest.h
index 864dd4bed93..db521ae67fb 100644
--- a/chromium/content/browser/frame_host/render_widget_host_view_guest.h
+++ b/chromium/content/browser/frame_host/render_widget_host_view_guest.h
@@ -82,6 +82,7 @@ class CONTENT_EXPORT RenderWidgetHostViewGuest
base::string16 GetSelectedText() override;
base::string16 GetSurroundingText() override;
gfx::Range GetSelectedRange() override;
+ size_t GetOffsetForSurroundingText() override;
void SetNeedsBeginFrames(bool needs_begin_frames) override;
TouchSelectionControllerClientManager*
GetTouchSelectionControllerClientManager() override;
@@ -95,6 +96,7 @@ class CONTENT_EXPORT RenderWidgetHostViewGuest
const gfx::PointF& point) override;
// RenderWidgetHostViewBase implementation.
+ RenderWidgetHostViewBase* GetRootView() override;
void InitAsPopup(RenderWidgetHostView* parent_host_view,
const gfx::Rect& bounds) override;
void InitAsFullscreen(RenderWidgetHostView* reference_host_view) override;
@@ -117,10 +119,6 @@ class CONTENT_EXPORT RenderWidgetHostViewGuest
const gfx::Range& range) override;
void SelectionBoundsChanged(
const ViewHostMsg_SelectionBounds_Params& params) override;
-#if defined(USE_AURA)
- void ProcessAckedTouchEvent(const TouchEventWithLatencyInfo& touch,
- InputEventAckState ack_result) override;
-#endif
void PreProcessMouseEvent(const blink::WebMouseEvent& event) override;
void PreProcessTouchEvent(const blink::WebTouchEvent& event) override;
@@ -161,6 +159,10 @@ class CONTENT_EXPORT RenderWidgetHostViewGuest
viz::ScopedSurfaceIdAllocator DidUpdateVisualProperties(
const cc::RenderFrameMetadata& metadata) override;
+ void MaybeSendSyntheticTapGestureForTest(
+ const blink::WebFloatPoint& position,
+ const blink::WebFloatPoint& screen_position) const;
+
private:
friend class RenderWidgetHostView;
@@ -182,7 +184,7 @@ class CONTENT_EXPORT RenderWidgetHostViewGuest
// http://crbug.com/533069
void MaybeSendSyntheticTapGesture(
const blink::WebFloatPoint& position,
- const blink::WebFloatPoint& screenPosition) const;
+ const blink::WebFloatPoint& screen_position) const;
void OnHandleInputEvent(RenderWidgetHostImpl* embedder,
int browser_plugin_instance_id,
diff --git a/chromium/content/browser/frame_host/render_widget_host_view_guest_unittest.cc b/chromium/content/browser/frame_host/render_widget_host_view_guest_unittest.cc
index fa97ccfa39b..bfa0b5f3cf9 100644
--- a/chromium/content/browser/frame_host/render_widget_host_view_guest_unittest.cc
+++ b/chromium/content/browser/frame_host/render_widget_host_view_guest_unittest.cc
@@ -198,6 +198,12 @@ class RenderWidgetHostViewGuestSurfaceTest
};
TEST_F(RenderWidgetHostViewGuestSurfaceTest, TestGuestSurface) {
+ // Early out because RenderWidgetHostViewChildFrame::SendSurfaceInfoToEmbedder
+ // is no-op on mash and the test expects it call into FirstSurfaceActivation
+ // of BrowserPluginGuest.
+ if (features::IsUsingWindowService())
+ return;
+
gfx::Size view_size(100, 100);
gfx::Rect view_rect(view_size);
float scale_factor = 1.f;
diff --git a/chromium/content/browser/geolocation/geolocation_service_impl.cc b/chromium/content/browser/geolocation/geolocation_service_impl.cc
index 342e68a8317..6bd741016f3 100644
--- a/chromium/content/browser/geolocation/geolocation_service_impl.cc
+++ b/chromium/content/browser/geolocation/geolocation_service_impl.cc
@@ -7,7 +7,6 @@
#include "content/browser/permissions/permission_controller_impl.h"
#include "content/public/browser/permission_type.h"
#include "content/public/browser/render_frame_host.h"
-#include "content/public/common/content_features.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom.h"
namespace content {
@@ -72,8 +71,7 @@ void GeolocationServiceImpl::Bind(
void GeolocationServiceImpl::CreateGeolocation(
mojo::InterfaceRequest<device::mojom::Geolocation> request,
bool user_gesture) {
- if (base::FeatureList::IsEnabled(features::kUseFeaturePolicyForPermissions) &&
- !render_frame_host_->IsFeatureEnabled(
+ if (!render_frame_host_->IsFeatureEnabled(
blink::mojom::FeaturePolicyFeature::kGeolocation)) {
return;
}
diff --git a/chromium/content/browser/geolocation/geolocation_service_impl_unittest.cc b/chromium/content/browser/geolocation/geolocation_service_impl_unittest.cc
index bb1ec33adf4..9499af1083b 100644
--- a/chromium/content/browser/geolocation/geolocation_service_impl_unittest.cc
+++ b/chromium/content/browser/geolocation/geolocation_service_impl_unittest.cc
@@ -6,11 +6,9 @@
#include "base/bind_helpers.h"
#include "base/run_loop.h"
-#include "base/test/scoped_feature_list.h"
#include "content/browser/permissions/permission_controller_impl.h"
#include "content/public/browser/permission_controller.h"
#include "content/public/browser/permission_type.h"
-#include "content/public/common/content_features.h"
#include "content/public/common/service_manager_connection.h"
#include "content/public/test/mock_permission_manager.h"
#include "content/public/test/navigation_simulator.h"
@@ -27,7 +25,6 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom.h"
-using base::test::ScopedFeatureList;
using blink::mojom::PermissionStatus;
using device::mojom::GeolocationPtr;
using device::mojom::GeopositionPtr;
@@ -155,9 +152,6 @@ class GeolocationServiceTest : public RenderViewHostImplTestHarness {
TEST_F(GeolocationServiceTest, PermissionGrantedPolicyViolation) {
// The embedded frame is not whitelisted.
- ScopedFeatureList feature_list;
- feature_list.InitFromCommandLine(
- features::kUseFeaturePolicyForPermissions.name, std::string());
CreateEmbeddedFrameAndGeolocationService(/*allow_via_feature_policy=*/false);
permission_manager()->SetRequestCallback(
@@ -178,9 +172,6 @@ TEST_F(GeolocationServiceTest, PermissionGrantedPolicyViolation) {
TEST_F(GeolocationServiceTest, PermissionGrantedNoPolicyViolation) {
// Whitelist the embedded frame.
- ScopedFeatureList feature_list;
- feature_list.InitFromCommandLine(
- features::kUseFeaturePolicyForPermissions.name, std::string());
CreateEmbeddedFrameAndGeolocationService(/*allow_via_feature_policy=*/true);
permission_manager()->SetRequestCallback(
diff --git a/chromium/content/browser/gpu/browser_gpu_channel_host_factory.cc b/chromium/content/browser/gpu/browser_gpu_channel_host_factory.cc
index ca32413b3f3..f141ce1abbd 100644
--- a/chromium/content/browser/gpu/browser_gpu_channel_host_factory.cc
+++ b/chromium/content/browser/gpu/browser_gpu_channel_host_factory.cc
@@ -4,6 +4,8 @@
#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
+#include <utility>
+
#include "base/android/orderfile/orderfile_buildflags.h"
#include "base/bind.h"
#include "base/command_line.h"
@@ -17,8 +19,9 @@
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "components/viz/common/features.h"
-#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
+#include "components/viz/host/gpu_host_impl.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
+#include "content/browser/gpu/gpu_memory_buffer_manager_singleton.h"
#include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/gpu/shader_cache_factory.h"
#include "content/common/child_process_host_impl.h"
@@ -28,6 +31,8 @@
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
#include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/config/gpu_finch_features.h"
+#include "gpu/ipc/common/gpu_client_ids.h"
#include "gpu/ipc/in_process_command_buffer.h"
#include "services/resource_coordinator/public/mojom/memory_instrumentation/constants.mojom.h"
#include "services/service_manager/runner/common/client_util.h"
@@ -74,7 +79,7 @@ class BrowserGpuChannelHostFactory::EstablishRequest
void OnEstablishedOnIO(mojo::ScopedMessagePipeHandle channel_handle,
const gpu::GPUInfo& gpu_info,
const gpu::GpuFeatureInfo& gpu_feature_info,
- GpuProcessHost::EstablishChannelStatus status);
+ viz::GpuHostImpl::EstablishChannelStatus status);
void FinishOnIO();
void FinishAndRunCallbacksOnMain();
void FinishOnMain();
@@ -134,13 +139,10 @@ void BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO() {
return;
}
- bool preempts = true;
- bool allow_view_command_buffers = true;
- bool allow_real_time_streams = true;
- host->EstablishGpuChannel(
- gpu_client_id_, gpu_client_tracing_id_, preempts,
- allow_view_command_buffers, allow_real_time_streams,
- base::Bind(
+ bool is_gpu_host = true;
+ host->gpu_host()->EstablishGpuChannel(
+ gpu_client_id_, gpu_client_tracing_id_, is_gpu_host,
+ base::BindOnce(
&BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO,
this));
}
@@ -149,9 +151,9 @@ void BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO(
mojo::ScopedMessagePipeHandle channel_handle,
const gpu::GPUInfo& gpu_info,
const gpu::GpuFeatureInfo& gpu_feature_info,
- GpuProcessHost::EstablishChannelStatus status) {
+ viz::GpuHostImpl::EstablishChannelStatus status) {
if (!channel_handle.is_valid() &&
- status == GpuProcessHost::EstablishChannelStatus::GPU_HOST_INVALID &&
+ status == viz::GpuHostImpl::EstablishChannelStatus::kGpuHostInvalid &&
// Ask client every time instead of passing this down from UI thread to
// avoid having the value be stale.
GetContentClient()->browser()->AllowGpuLaunchRetryOnIOThread()) {
@@ -229,14 +231,6 @@ void BrowserGpuChannelHostFactory::EstablishRequest::Cancel() {
established_callbacks_.clear();
}
-void BrowserGpuChannelHostFactory::CloseChannel() {
- DCHECK(instance_);
- if (instance_->gpu_channel_) {
- instance_->gpu_channel_->DestroyChannel();
- instance_->gpu_channel_ = nullptr;
- }
-}
-
void BrowserGpuChannelHostFactory::Initialize(bool establish_gpu_channel) {
DCHECK(!instance_);
instance_ = new BrowserGpuChannelHostFactory();
@@ -251,13 +245,20 @@ void BrowserGpuChannelHostFactory::Terminate() {
instance_ = nullptr;
}
+void BrowserGpuChannelHostFactory::CloseChannel() {
+ if (gpu_channel_) {
+ gpu_channel_->DestroyChannel();
+ gpu_channel_ = nullptr;
+ }
+ gpu_memory_buffer_manager_ = nullptr;
+}
+
BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory()
: gpu_client_id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()),
gpu_client_tracing_id_(
memory_instrumentation::mojom::kServiceTracingProcessId),
gpu_memory_buffer_manager_(
- new BrowserGpuMemoryBufferManager(gpu_client_id_,
- gpu_client_tracing_id_)) {
+ new GpuMemoryBufferManagerSingleton(gpu_client_id_)) {
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableGpuShaderDiskCache)) {
DCHECK(GetContentClient());
@@ -270,6 +271,19 @@ BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory()
&BrowserGpuChannelHostFactory::InitializeShaderDiskCacheOnIO,
gpu_client_id_, cache_dir));
}
+
+ if (base::FeatureList::IsEnabled(
+ features::kDefaultEnableOopRasterization)) {
+ base::FilePath gr_cache_dir =
+ GetContentClient()->browser()->GetGrShaderDiskCacheDirectory();
+ if (!gr_cache_dir.empty()) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(
+ &BrowserGpuChannelHostFactory::InitializeGrShaderDiskCacheOnIO,
+ gr_cache_dir));
+ }
+ }
}
}
@@ -286,7 +300,7 @@ BrowserGpuChannelHostFactory::~BrowserGpuChannelHostFactory() {
void BrowserGpuChannelHostFactory::EstablishGpuChannel(
gpu::GpuChannelEstablishedCallback callback) {
#if defined(USE_AURA)
- DCHECK(features::IsAshInBrowserProcess());
+ DCHECK(!features::IsMultiProcessMash());
#endif
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (gpu_channel_.get() && gpu_channel_->IsLost()) {
@@ -386,8 +400,15 @@ void BrowserGpuChannelHostFactory::InitializeShaderDiskCacheOnIO(
GetShaderCacheFactorySingleton()->SetCacheInfo(gpu_client_id, cache_dir);
if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor)) {
GetShaderCacheFactorySingleton()->SetCacheInfo(
- gpu::InProcessCommandBuffer::kGpuClientId, cache_dir);
+ gpu::kInProcessCommandBufferClientId, cache_dir);
}
}
+// static
+void BrowserGpuChannelHostFactory::InitializeGrShaderDiskCacheOnIO(
+ const base::FilePath& cache_dir) {
+ GetShaderCacheFactorySingleton()->SetCacheInfo(gpu::kGrShaderCacheClientId,
+ cache_dir);
+}
+
} // namespace content
diff --git a/chromium/content/browser/gpu/browser_gpu_channel_host_factory.h b/chromium/content/browser/gpu/browser_gpu_channel_host_factory.h
index 12aa00c7bb0..6386420710d 100644
--- a/chromium/content/browser/gpu/browser_gpu_channel_host_factory.h
+++ b/chromium/content/browser/gpu/browser_gpu_channel_host_factory.h
@@ -17,11 +17,15 @@
#include "base/single_thread_task_runner.h"
#include "build/build_config.h"
#include "content/common/content_export.h"
+#include "content/public/browser/browser_thread.h"
#include "gpu/ipc/client/gpu_channel_host.h"
#include "ipc/message_filter.h"
+namespace gpu {
+class GpuMemoryBufferManager;
+}
+
namespace content {
-class BrowserGpuMemoryBufferManager;
class CONTENT_EXPORT BrowserGpuChannelHostFactory
: public gpu::GpuChannelEstablishFactory {
@@ -57,11 +61,13 @@ class CONTENT_EXPORT BrowserGpuChannelHostFactory
static void InitializeShaderDiskCacheOnIO(int gpu_client_id,
const base::FilePath& cache_dir);
+ static void InitializeGrShaderDiskCacheOnIO(const base::FilePath& cache_dir);
const int gpu_client_id_;
const uint64_t gpu_client_tracing_id_;
scoped_refptr<gpu::GpuChannelHost> gpu_channel_;
- std::unique_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager_;
+ std::unique_ptr<gpu::GpuMemoryBufferManager, BrowserThread::DeleteOnIOThread>
+ gpu_memory_buffer_manager_;
scoped_refptr<EstablishRequest> pending_request_;
base::OneShotTimer timeout_;
diff --git a/chromium/content/browser/gpu/browser_gpu_client_delegate.cc b/chromium/content/browser/gpu/browser_gpu_client_delegate.cc
new file mode 100644
index 00000000000..20da7388187
--- /dev/null
+++ b/chromium/content/browser/gpu/browser_gpu_client_delegate.cc
@@ -0,0 +1,82 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/gpu/browser_gpu_client_delegate.h"
+
+#include <utility>
+
+#include "components/viz/host/gpu_host_impl.h"
+#include "content/browser/gpu/gpu_memory_buffer_manager_singleton.h"
+#include "content/browser/gpu/gpu_process_host.h"
+#include "gpu/config/gpu_feature_info.h"
+#include "gpu/config/gpu_info.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+
+namespace content {
+namespace {
+
+void OnEstablishGpuChannel(
+ viz::GpuClientDelegate::EstablishGpuChannelCallback callback,
+ mojo::ScopedMessagePipeHandle channel_handle,
+ const gpu::GPUInfo& gpu_info,
+ const gpu::GpuFeatureInfo& gpu_feature_info,
+ viz::GpuHostImpl::EstablishChannelStatus status) {
+ if (!callback)
+ return;
+
+ viz::GpuClientDelegate::EstablishGpuChannelStatus delegate_status;
+ switch (status) {
+ case viz::GpuHostImpl::EstablishChannelStatus::kGpuAccessDenied:
+ delegate_status =
+ viz::GpuClientDelegate::EstablishGpuChannelStatus::kGpuAccessDenied;
+ break;
+ case viz::GpuHostImpl::EstablishChannelStatus::kGpuHostInvalid:
+ delegate_status =
+ viz::GpuClientDelegate::EstablishGpuChannelStatus::kGpuHostInvalid;
+ break;
+ case viz::GpuHostImpl::EstablishChannelStatus::kSuccess:
+ delegate_status =
+ viz::GpuClientDelegate::EstablishGpuChannelStatus::kSuccess;
+ break;
+ }
+ std::move(callback).Run(std::move(channel_handle), gpu_info, gpu_feature_info,
+ delegate_status);
+}
+
+} // namespace
+
+BrowserGpuClientDelegate::BrowserGpuClientDelegate() = default;
+
+BrowserGpuClientDelegate::~BrowserGpuClientDelegate() = default;
+
+viz::mojom::GpuService* BrowserGpuClientDelegate::EnsureGpuService() {
+ if (auto* host = GpuProcessHost::Get())
+ return host->gpu_service();
+ return nullptr;
+}
+
+void BrowserGpuClientDelegate::EstablishGpuChannel(
+ int client_id,
+ uint64_t client_tracing_id,
+ EstablishGpuChannelCallback callback) {
+ auto* host = GpuProcessHost::Get();
+ if (!host) {
+ std::move(callback).Run(mojo::ScopedMessagePipeHandle(), gpu::GPUInfo(),
+ gpu::GpuFeatureInfo(),
+ EstablishGpuChannelStatus::kGpuAccessDenied);
+ return;
+ }
+
+ const bool is_gpu_host = false;
+ host->gpu_host()->EstablishGpuChannel(
+ client_id, client_tracing_id, is_gpu_host,
+ base::BindOnce(&OnEstablishGpuChannel, std::move(callback)));
+}
+
+viz::HostGpuMemoryBufferManager*
+BrowserGpuClientDelegate::GetGpuMemoryBufferManager() {
+ return GpuMemoryBufferManagerSingleton::GetInstance();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/gpu/browser_gpu_client_delegate.h b/chromium/content/browser/gpu/browser_gpu_client_delegate.h
new file mode 100644
index 00000000000..18150dc6e19
--- /dev/null
+++ b/chromium/content/browser/gpu/browser_gpu_client_delegate.h
@@ -0,0 +1,30 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_GPU_BROWSER_GPU_CLIENT_DELEGATE_H_
+#define CONTENT_BROWSER_GPU_BROWSER_GPU_CLIENT_DELEGATE_H_
+
+#include "components/viz/host/gpu_client_delegate.h"
+
+namespace content {
+
+class BrowserGpuClientDelegate : public viz::GpuClientDelegate {
+ public:
+ BrowserGpuClientDelegate();
+ ~BrowserGpuClientDelegate() override;
+
+ // GpuClientDelegate:
+ viz::mojom::GpuService* EnsureGpuService() override;
+ void EstablishGpuChannel(int client_id,
+ uint64_t client_tracing_id,
+ EstablishGpuChannelCallback callback) override;
+ viz::HostGpuMemoryBufferManager* GetGpuMemoryBufferManager() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserGpuClientDelegate);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_GPU_BROWSER_GPU_CLIENT_DELEGATE_H_
diff --git a/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.cc b/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
deleted file mode 100644
index 8568d3f5885..00000000000
--- a/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
+++ /dev/null
@@ -1,498 +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 "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/stringprintf.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread_restrictions.h"
-#include "base/trace_event/memory_dump_manager.h"
-#include "base/trace_event/process_memory_dump.h"
-#include "base/trace_event/trace_event.h"
-#include "build/build_config.h"
-#include "content/browser/gpu/gpu_process_host.h"
-#include "content/common/child_process_host_impl.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/common/content_switches.h"
-#include "gpu/ipc/common/gpu_memory_buffer_impl.h"
-#include "gpu/ipc/common/gpu_memory_buffer_impl_shared_memory.h"
-#include "gpu/ipc/common/gpu_memory_buffer_support.h"
-#include "ui/gfx/buffer_format_util.h"
-#include "ui/gl/gl_switches.h"
-
-namespace content {
-namespace {
-
-void GpuMemoryBufferDeleted(
- scoped_refptr<base::SingleThreadTaskRunner> destruction_task_runner,
- const gpu::GpuMemoryBufferImpl::DestructionCallback& destruction_callback,
- const gpu::SyncToken& sync_token) {
- destruction_task_runner->PostTask(
- FROM_HERE, base::BindOnce(destruction_callback, sync_token));
-}
-
-BrowserGpuMemoryBufferManager* g_gpu_memory_buffer_manager = nullptr;
-
-} // namespace
-
-struct BrowserGpuMemoryBufferManager::CreateGpuMemoryBufferRequest {
- CreateGpuMemoryBufferRequest(const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- int client_id,
- gpu::SurfaceHandle surface_handle)
- : event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED),
- size(size),
- format(format),
- usage(usage),
- client_id(client_id),
- surface_handle(surface_handle) {}
- ~CreateGpuMemoryBufferRequest() {}
- base::WaitableEvent event;
- gfx::Size size;
- gfx::BufferFormat format;
- gfx::BufferUsage usage;
- int client_id;
- gpu::SurfaceHandle surface_handle;
- std::unique_ptr<gfx::GpuMemoryBuffer> result;
-};
-
-BrowserGpuMemoryBufferManager::BrowserGpuMemoryBufferManager(
- int gpu_client_id,
- uint64_t gpu_client_tracing_id)
- : gpu_memory_buffer_support_(new gpu::GpuMemoryBufferSupport()),
- native_configurations_(gpu::GetNativeGpuMemoryBufferConfigurations(
- gpu_memory_buffer_support_.get())),
- gpu_client_id_(gpu_client_id),
- gpu_client_tracing_id_(gpu_client_tracing_id) {
- DCHECK(!g_gpu_memory_buffer_manager);
- g_gpu_memory_buffer_manager = this;
-
- // Enable the dump provider with IO thread affinity. Note that
- // unregistration happens on the IO thread (See
- // BrowserProcessSubThread::IOThreadPreCleanUp).
- DCHECK(BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
- base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
- this, "BrowserGpuMemoryBufferManager",
- BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
-}
-
-BrowserGpuMemoryBufferManager::~BrowserGpuMemoryBufferManager() {
- g_gpu_memory_buffer_manager = nullptr;
-}
-
-// static
-BrowserGpuMemoryBufferManager* BrowserGpuMemoryBufferManager::current() {
- return g_gpu_memory_buffer_manager;
-}
-
-std::unique_ptr<gfx::GpuMemoryBuffer>
-BrowserGpuMemoryBufferManager::CreateGpuMemoryBuffer(
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- gpu::SurfaceHandle surface_handle) {
- return AllocateGpuMemoryBufferForSurface(size, format, usage, surface_handle);
-}
-
-void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForChildProcess(
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- int child_client_id,
- AllocationCallback callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- // Use service side allocation for native configurations.
- if (IsNativeGpuMemoryBufferConfiguration(format, usage)) {
- CreateGpuMemoryBufferOnIO(id, size, format, usage, gpu::kNullSurfaceHandle,
- child_client_id, std::move(callback));
- return;
- }
-
- // Early out if we cannot fallback to shared memory buffer.
- if (!gpu::GpuMemoryBufferImplSharedMemory::IsUsageSupported(usage) ||
- !gpu::GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat(size,
- format)) {
- std::move(callback).Run(gfx::GpuMemoryBufferHandle());
- return;
- }
-
- BufferMap& buffers = clients_[child_client_id];
-
- // Allocate shared memory buffer as fallback.
- auto insert_result = buffers.insert(std::make_pair(
- id, BufferInfo(size, gfx::SHARED_MEMORY_BUFFER, format, usage, 0)));
- if (!insert_result.second) {
- DLOG(ERROR) << "Child process attempted to allocate a GpuMemoryBuffer with "
- "an existing ID.";
- std::move(callback).Run(gfx::GpuMemoryBufferHandle());
- return;
- }
-
- auto handle = gpu::GpuMemoryBufferImplSharedMemory::CreateGpuMemoryBuffer(
- id, size, format, usage);
- buffers.find(id)->second.shared_memory_guid = handle.handle.GetGUID();
- std::move(callback).Run(std::move(handle));
-}
-
-void BrowserGpuMemoryBufferManager::SetDestructionSyncToken(
- gfx::GpuMemoryBuffer* buffer,
- const gpu::SyncToken& sync_token) {
- static_cast<gpu::GpuMemoryBufferImpl*>(buffer)->set_destruction_sync_token(
- sync_token);
-}
-
-bool BrowserGpuMemoryBufferManager::OnMemoryDump(
- const base::trace_event::MemoryDumpArgs& args,
- base::trace_event::ProcessMemoryDump* pmd) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- for (const auto& client : clients_) {
- int client_id = client.first;
-
- for (const auto& buffer : client.second) {
- if (buffer.second.type == gfx::EMPTY_BUFFER)
- continue;
-
- gfx::GpuMemoryBufferId buffer_id = buffer.first;
- base::trace_event::MemoryAllocatorDump* dump =
- pmd->CreateAllocatorDump(base::StringPrintf(
- "gpumemorybuffer/client_%d/buffer_%d", client_id, buffer_id.id));
- if (!dump)
- return false;
-
- size_t buffer_size_in_bytes = gfx::BufferSizeForBufferFormat(
- buffer.second.size, buffer.second.format);
- dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
- base::trace_event::MemoryAllocatorDump::kUnitsBytes,
- buffer_size_in_bytes);
-
- // Create the cross-process ownership edge. If the client creates a
- // corresponding dump for the same buffer, this will avoid to
- // double-count them in tracing. If, instead, no other process will emit a
- // dump with the same guid, the segment will be accounted to the browser.
- uint64_t client_tracing_process_id =
- ClientIdToTracingProcessId(client_id);
-
- if (buffer.second.type == gfx::SHARED_MEMORY_BUFFER) {
- pmd->CreateSharedMemoryOwnershipEdge(
- dump->guid(), buffer.second.shared_memory_guid, 0 /* importance */);
- } else {
- auto shared_buffer_guid = gfx::GetGenericSharedGpuMemoryGUIDForTracing(
- client_tracing_process_id, buffer_id);
- pmd->CreateSharedGlobalAllocatorDump(shared_buffer_guid);
- pmd->AddOwnershipEdge(dump->guid(), shared_buffer_guid);
- }
- }
- }
-
- return true;
-}
-
-void BrowserGpuMemoryBufferManager::ChildProcessDeletedGpuMemoryBuffer(
- gfx::GpuMemoryBufferId id,
- int child_client_id,
- const gpu::SyncToken& sync_token) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- DestroyGpuMemoryBufferOnIO(id, child_client_id, sync_token);
-}
-
-void BrowserGpuMemoryBufferManager::ProcessRemoved(
- int client_id) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- ClientMap::iterator client_it = clients_.find(client_id);
- if (client_it == clients_.end())
- return;
-
- for (const auto& buffer : client_it->second) {
- // This might happen if buffer is currenlty in the process of being
- // allocated. The buffer will in that case be cleaned up when allocation
- // completes.
- if (buffer.second.type == gfx::EMPTY_BUFFER)
- continue;
-
- GpuProcessHost* host = GpuProcessHost::FromID(buffer.second.gpu_host_id);
- if (host)
- host->DestroyGpuMemoryBuffer(buffer.first, client_id, gpu::SyncToken());
- }
-
- clients_.erase(client_it);
-}
-
-bool BrowserGpuMemoryBufferManager::IsNativeGpuMemoryBufferConfiguration(
- gfx::BufferFormat format,
- gfx::BufferUsage usage) const {
- return native_configurations_.find(std::make_pair(format, usage)) !=
- native_configurations_.end();
-}
-
-std::unique_ptr<gfx::GpuMemoryBuffer>
-BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurface(
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- gpu::SurfaceHandle surface_handle) {
- DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- CreateGpuMemoryBufferRequest request(size, format, usage, gpu_client_id_,
- surface_handle);
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(
- &BrowserGpuMemoryBufferManager::HandleCreateGpuMemoryBufferOnIO,
- base::Unretained(this), // Safe as we wait for result below.
- base::Unretained(&request)));
-
- // We're blocking the UI thread, which is generally undesirable.
- TRACE_EVENT0(
- "browser",
- "BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurface");
- base::ThreadRestrictions::ScopedAllowWait allow_wait;
- request.event.Wait();
- return std::move(request.result);
-}
-
-void BrowserGpuMemoryBufferManager::HandleCreateGpuMemoryBufferOnIO(
- CreateGpuMemoryBufferRequest* request) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- gfx::GpuMemoryBufferId new_id(next_gpu_memory_id_++);
- // Use service side allocation for native configurations.
- if (IsNativeGpuMemoryBufferConfiguration(request->format, request->usage)) {
- // Note: Unretained is safe as this is only used for synchronous allocation
- // from a non-IO thread.
- CreateGpuMemoryBufferOnIO(
- new_id, request->size, request->format, request->usage,
- request->surface_handle, request->client_id,
- base::BindOnce(
- &BrowserGpuMemoryBufferManager::HandleGpuMemoryBufferCreatedOnIO,
- base::Unretained(this), base::Unretained(request)));
- return;
- }
-
- DCHECK(gpu::GpuMemoryBufferImplSharedMemory::IsUsageSupported(request->usage))
- << static_cast<int>(request->usage);
-
- BufferMap& buffers = clients_[request->client_id];
-
- // Allocate shared memory buffer as fallback.
- auto insert_result = buffers.insert(std::make_pair(
- new_id, BufferInfo(request->size, gfx::SHARED_MEMORY_BUFFER,
- request->format, request->usage, 0)));
- DCHECK(insert_result.second);
-
- // Note: Unretained is safe as IO thread is stopped before manager is
- // destroyed.
- request->result = gpu::GpuMemoryBufferImplSharedMemory::Create(
- new_id, request->size, request->format, request->usage,
- base::Bind(
- &GpuMemoryBufferDeleted,
- BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
- base::Bind(&BrowserGpuMemoryBufferManager::DestroyGpuMemoryBufferOnIO,
- base::Unretained(this), new_id, request->client_id)));
- if (request->result) {
- buffers.find(new_id)->second.shared_memory_guid =
- request->result->GetHandle().handle.GetGUID();
- }
- request->event.Signal();
-}
-
-void BrowserGpuMemoryBufferManager::HandleGpuMemoryBufferCreatedOnIO(
- CreateGpuMemoryBufferRequest* request,
- gfx::GpuMemoryBufferHandle handle) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- // Early out if factory failed to create the buffer.
- if (handle.is_null()) {
- request->event.Signal();
- return;
- }
-
- // Note: Unretained is safe as IO thread is stopped before manager is
- // destroyed.
- auto handle_id = handle.id;
- request->result =
- gpu_memory_buffer_support_->CreateGpuMemoryBufferImplFromHandle(
- std::move(handle), request->size, request->format, request->usage,
- base::Bind(
- &GpuMemoryBufferDeleted,
- BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
- base::Bind(
- &BrowserGpuMemoryBufferManager::DestroyGpuMemoryBufferOnIO,
- base::Unretained(this), handle_id, request->client_id)));
- request->event.Signal();
-}
-
-void BrowserGpuMemoryBufferManager::CreateGpuMemoryBufferOnIO(
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- gpu::SurfaceHandle surface_handle,
- int client_id,
- CreateCallback callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- BufferMap& buffers = clients_[client_id];
-
- // Note: Handling of cases where the client is removed before the allocation
- // completes is less subtle if we set the buffer type to EMPTY_BUFFER here
- // and verify that this has not changed when creation completes.
- auto insert_result = buffers.insert(std::make_pair(
- id, BufferInfo(size, gfx::EMPTY_BUFFER, format, usage, 0)));
- if (!insert_result.second) {
- DLOG(ERROR) << "Child process attempted to create a GpuMemoryBuffer with "
- "an existing ID.";
- std::move(callback).Run(gfx::GpuMemoryBufferHandle());
- return;
- }
-
- GpuProcessHost* host = GpuProcessHost::Get();
- if (!host) {
- DLOG(ERROR) << "Cannot allocate GpuMemoryBuffer with no GpuProcessHost.";
- std::move(callback).Run(gfx::GpuMemoryBufferHandle());
- return;
- }
- // Note: Unretained is safe as IO thread is stopped before manager is
- // destroyed.
- host->CreateGpuMemoryBuffer(
- id, size, format, usage, client_id, surface_handle,
- base::BindOnce(&BrowserGpuMemoryBufferManager::GpuMemoryBufferCreatedOnIO,
- base::Unretained(this), id, surface_handle, client_id,
- host->host_id(), std::move(callback)));
-}
-
-void BrowserGpuMemoryBufferManager::GpuMemoryBufferCreatedOnIO(
- gfx::GpuMemoryBufferId id,
- gpu::SurfaceHandle surface_handle,
- int client_id,
- int gpu_host_id,
- CreateCallback callback,
- gfx::GpuMemoryBufferHandle handle,
- GpuProcessHost::BufferCreationStatus status) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- ClientMap::iterator client_it = clients_.find(client_id);
-
- // This can happen if client is removed while the buffer is being allocated.
- if (client_it == clients_.end()) {
- if (!handle.is_null()) {
- GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id);
- if (host)
- host->DestroyGpuMemoryBuffer(handle.id, client_id, gpu::SyncToken());
- }
- std::move(callback).Run(gfx::GpuMemoryBufferHandle());
- return;
- }
-
- BufferMap& buffers = client_it->second;
-
- BufferMap::iterator buffer_it = buffers.find(id);
- DCHECK(buffer_it != buffers.end());
- DCHECK_EQ(buffer_it->second.type, gfx::EMPTY_BUFFER);
-
- // If the handle isn't valid, that means that the GPU process crashed or is
- // misbehaving.
- bool valid_handle = !handle.is_null() && handle.id == id;
- if (!valid_handle) {
- // If we failed after re-using the GPU process, it may have died in the
- // mean time. Retry to have a chance to create a fresh GPU process.
- if (handle.is_null() &&
- status == GpuProcessHost::BufferCreationStatus::GPU_HOST_INVALID) {
- DVLOG(1) << "Failed to create buffer through existing GPU process. "
- "Trying to restart GPU process.";
- gfx::Size size = buffer_it->second.size;
- gfx::BufferFormat format = buffer_it->second.format;
- gfx::BufferUsage usage = buffer_it->second.usage;
- // Remove the buffer entry and call CreateGpuMemoryBufferOnIO again.
- buffers.erase(buffer_it);
- CreateGpuMemoryBufferOnIO(id, size, format, usage, surface_handle,
- client_id, std::move(callback));
- } else {
- // Remove the buffer entry and run the allocation callback with an empty
- // handle to indicate failure.
- buffers.erase(buffer_it);
- std::move(callback).Run(gfx::GpuMemoryBufferHandle());
- }
- return;
- }
-
- // Store the type and host id of this buffer so it can be cleaned up if the
- // client is removed.
- buffer_it->second.type = handle.type;
- buffer_it->second.gpu_host_id = gpu_host_id;
- buffer_it->second.shared_memory_guid = handle.handle.GetGUID();
-
- std::move(callback).Run(std::move(handle));
-}
-
-void BrowserGpuMemoryBufferManager::DestroyGpuMemoryBufferOnIO(
- gfx::GpuMemoryBufferId id,
- int client_id,
- const gpu::SyncToken& sync_token) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(clients_.find(client_id) != clients_.end());
-
- BufferMap& buffers = clients_[client_id];
-
- BufferMap::iterator buffer_it = buffers.find(id);
- if (buffer_it == buffers.end()) {
- LOG(ERROR) << "Invalid GpuMemoryBuffer ID for client.";
- return;
- }
-
- // This can happen if a client managed to call this while a buffer is in the
- // process of being allocated.
- if (buffer_it->second.type == gfx::EMPTY_BUFFER) {
- LOG(ERROR) << "Invalid GpuMemoryBuffer type.";
- return;
- }
-
- GpuProcessHost* host = GpuProcessHost::FromID(buffer_it->second.gpu_host_id);
- if (host)
- host->DestroyGpuMemoryBuffer(id, client_id, sync_token);
-
- buffers.erase(buffer_it);
-}
-
-uint64_t BrowserGpuMemoryBufferManager::ClientIdToTracingProcessId(
- int client_id) const {
- if (client_id == gpu_client_id_) {
- // The gpu_client uses a fixed tracing ID.
- return gpu_client_tracing_id_;
- }
-
- // In normal cases, |client_id| is a child process id, so we can perform
- // the standard conversion.
- return ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(
- client_id);
-}
-
-BrowserGpuMemoryBufferManager::BufferInfo::BufferInfo(
- const gfx::Size& size,
- gfx::GpuMemoryBufferType type,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- int gpu_host_id)
- : size(size),
- type(type),
- format(format),
- usage(usage),
- gpu_host_id(gpu_host_id) {}
-
-BrowserGpuMemoryBufferManager::BufferInfo::BufferInfo(const BufferInfo& other) =
- default;
-
-BrowserGpuMemoryBufferManager::BufferInfo::~BufferInfo() {}
-
-} // namespace content
diff --git a/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.h b/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.h
deleted file mode 100644
index 4cf2b632fb0..00000000000
--- a/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.h
+++ /dev/null
@@ -1,143 +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 CONTENT_BROWSER_GPU_BROWSER_GPU_MEMORY_BUFFER_MANAGER_H_
-#define CONTENT_BROWSER_GPU_BROWSER_GPU_MEMORY_BUFFER_MANAGER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-#include <utility>
-
-#include "base/callback.h"
-#include "base/containers/hash_tables.h"
-#include "base/hash.h"
-#include "base/macros.h"
-#include "base/trace_event/memory_dump_provider.h"
-#include "content/browser/gpu/gpu_process_host.h"
-#include "content/common/content_export.h"
-#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
-#include "gpu/ipc/common/surface_handle.h"
-#include "gpu/ipc/host/gpu_memory_buffer_support.h"
-
-namespace gpu {
-class GpuMemoryBufferSupport;
-}
-
-namespace content {
-
-class CONTENT_EXPORT BrowserGpuMemoryBufferManager
- : public gpu::GpuMemoryBufferManager,
- public base::trace_event::MemoryDumpProvider {
- public:
- using CreateCallback =
- base::OnceCallback<void(gfx::GpuMemoryBufferHandle handle)>;
- using AllocationCallback = CreateCallback;
-
- BrowserGpuMemoryBufferManager(int gpu_client_id,
- uint64_t gpu_client_tracing_id);
- ~BrowserGpuMemoryBufferManager() override;
-
- static BrowserGpuMemoryBufferManager* current();
-
- // Overridden from gpu::GpuMemoryBufferManager:
- std::unique_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- gpu::SurfaceHandle surface_handle) override;
- void SetDestructionSyncToken(gfx::GpuMemoryBuffer* buffer,
- const gpu::SyncToken& sync_token) override;
-
- // Overridden from base::trace_event::MemoryDumpProvider:
- bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
- base::trace_event::ProcessMemoryDump* pmd) override;
-
- void AllocateGpuMemoryBufferForChildProcess(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- int child_client_id,
- AllocationCallback callback);
- void ChildProcessDeletedGpuMemoryBuffer(
- gfx::GpuMemoryBufferId id,
- int child_client_id,
- const gpu::SyncToken& sync_token);
- void ProcessRemoved(int client_id);
-
- bool IsNativeGpuMemoryBufferConfiguration(gfx::BufferFormat format,
- gfx::BufferUsage usage) const;
-
- private:
- struct BufferInfo {
- BufferInfo(const gfx::Size& size,
- gfx::GpuMemoryBufferType type,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- int gpu_host_id);
- BufferInfo(const BufferInfo& other);
- ~BufferInfo();
-
- gfx::Size size;
- gfx::GpuMemoryBufferType type = gfx::EMPTY_BUFFER;
- gfx::BufferFormat format = gfx::BufferFormat::RGBA_8888;
- gfx::BufferUsage usage = gfx::BufferUsage::GPU_READ;
- int gpu_host_id = 0;
- base::UnguessableToken shared_memory_guid;
- };
-
- struct CreateGpuMemoryBufferRequest;
-
- std::unique_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBufferForSurface(
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- gpu::SurfaceHandle surface_handle);
-
- // Functions that handle synchronous buffer creation requests.
- void HandleCreateGpuMemoryBufferOnIO(CreateGpuMemoryBufferRequest* request);
- void HandleGpuMemoryBufferCreatedOnIO(CreateGpuMemoryBufferRequest* request,
- gfx::GpuMemoryBufferHandle handle);
-
- // Functions that implement asynchronous buffer creation.
- void CreateGpuMemoryBufferOnIO(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- gpu::SurfaceHandle surface_handle,
- int client_id,
- CreateCallback callback);
- void GpuMemoryBufferCreatedOnIO(gfx::GpuMemoryBufferId id,
- gpu::SurfaceHandle surface_handle,
- int client_id,
- int gpu_host_id,
- CreateCallback callback,
- gfx::GpuMemoryBufferHandle handle,
- GpuProcessHost::BufferCreationStatus status);
- void DestroyGpuMemoryBufferOnIO(gfx::GpuMemoryBufferId id,
- int client_id,
- const gpu::SyncToken& sync_token);
-
- uint64_t ClientIdToTracingProcessId(int client_id) const;
-
- std::unique_ptr<gpu::GpuMemoryBufferSupport> gpu_memory_buffer_support_;
-
- const gpu::GpuMemoryBufferConfigurationSet native_configurations_;
- const int gpu_client_id_;
- const uint64_t gpu_client_tracing_id_;
- int next_gpu_memory_id_ = 1;
-
- // Stores info about buffers for all clients. This should only be accessed
- // on the IO thread.
- using BufferMap = base::hash_map<gfx::GpuMemoryBufferId, BufferInfo>;
- using ClientMap = base::hash_map<int, BufferMap>;
- ClientMap clients_;
-
- DISALLOW_COPY_AND_ASSIGN(BrowserGpuMemoryBufferManager);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_GPU_BROWSER_GPU_MEMORY_BUFFER_MANAGER_H_
diff --git a/chromium/content/browser/gpu/compositor_util.cc b/chromium/content/browser/gpu/compositor_util.cc
index 9773ec885ea..9bcf1916304 100644
--- a/chromium/content/browser/gpu/compositor_util.cc
+++ b/chromium/content/browser/gpu/compositor_util.cc
@@ -17,6 +17,7 @@
#include "base/metrics/field_trial.h"
#include "base/numerics/ranges.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
#include "base/sys_info.h"
#include "build/build_config.h"
#include "cc/base/switches.h"
@@ -334,6 +335,25 @@ std::vector<std::string> GetDriverBugWorkaroundsImpl(GpuFeatureInfoType type) {
workarounds.push_back(gpu::GpuDriverBugWorkaroundTypeToString(
static_cast<gpu::GpuDriverBugWorkaroundType>(workaround)));
}
+ // Tell clients about the disabled extensions and disabled WebGL
+ // extensions as well, to avoid confusion. Do this in a way that's
+ // compatible with the current reporting of driver bug workarounds
+ // to DevTools and Telemetry, and from there to the GPU tests.
+ //
+ // This code must be kept in sync with
+ // GpuBenchmarking::GetGpuDriverBugWorkarounds.
+ for (auto ext : base::SplitString(gpu_feature_info.disabled_extensions,
+ " ",
+ base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY)) {
+ workarounds.push_back("disabled_extension_" + ext);
+ }
+ for (auto ext : base::SplitString(gpu_feature_info.disabled_webgl_extensions,
+ " ",
+ base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY)) {
+ workarounds.push_back("disabled_webgl_extension_" + ext);
+ }
return workarounds;
}
diff --git a/chromium/content/browser/gpu/gpu_client.cc b/chromium/content/browser/gpu/gpu_client.cc
new file mode 100644
index 00000000000..abd24754947
--- /dev/null
+++ b/chromium/content/browser/gpu/gpu_client.cc
@@ -0,0 +1,28 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/browser/gpu_client.h"
+
+#include "content/browser/gpu/browser_gpu_client_delegate.h"
+#include "content/common/child_process_host_impl.h"
+
+namespace content {
+
+std::unique_ptr<viz::GpuClient, base::OnTaskRunnerDeleter> CreateGpuClient(
+ ws::mojom::GpuRequest request,
+ viz::GpuClient::ConnectionErrorHandlerClosure connection_error_handler,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ const int client_id = ChildProcessHostImpl::GenerateChildProcessUniqueId();
+ const uint64_t client_tracing_id =
+ ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(client_id);
+ std::unique_ptr<viz::GpuClient, base::OnTaskRunnerDeleter> gpu_client(
+ new viz::GpuClient(std::make_unique<BrowserGpuClientDelegate>(),
+ client_id, client_tracing_id, task_runner),
+ base::OnTaskRunnerDeleter(task_runner));
+ gpu_client->SetConnectionErrorHandler(std::move(connection_error_handler));
+ gpu_client->Add(std::move(request));
+ return gpu_client;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/gpu/gpu_client_impl.cc b/chromium/content/browser/gpu/gpu_client_impl.cc
deleted file mode 100644
index c2ef9591cd3..00000000000
--- a/chromium/content/browser/gpu/gpu_client_impl.cc
+++ /dev/null
@@ -1,220 +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 "content/browser/gpu/gpu_client_impl.h"
-
-#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
-#include "content/browser/gpu/gpu_process_host.h"
-#include "content/common/child_process_host_impl.h"
-#include "gpu/ipc/client/gpu_channel_host.h"
-#include "gpu/ipc/common/gpu_memory_buffer_impl.h"
-#include "gpu/ipc/common/gpu_memory_buffer_impl_shared_memory.h"
-
-namespace content {
-
-// static
-std::unique_ptr<GpuClient, base::OnTaskRunnerDeleter> GpuClient::Create(
- ui::mojom::GpuRequest request,
- ConnectionErrorHandlerClosure connection_error_handler,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- const int client_id = ChildProcessHostImpl::GenerateChildProcessUniqueId();
- const uint64_t client_tracing_id =
- ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(client_id);
- std::unique_ptr<GpuClientImpl, base::OnTaskRunnerDeleter> gpu_client(
- new GpuClientImpl(client_id, client_tracing_id, task_runner),
- base::OnTaskRunnerDeleter(task_runner));
- gpu_client->SetConnectionErrorHandler(std::move(connection_error_handler));
- gpu_client->Add(std::move(request));
- return gpu_client;
-}
-
-GpuClientImpl::GpuClientImpl(
- int client_id,
- uint64_t client_tracing_id,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : client_id_(client_id),
- client_tracing_id_(client_tracing_id),
- task_runner_(std::move(task_runner)),
- weak_factory_(this) {
- gpu_bindings_.set_connection_error_handler(
- base::BindRepeating(&GpuClientImpl::OnError, base::Unretained(this),
- ErrorReason::kConnectionLost));
-}
-
-GpuClientImpl::~GpuClientImpl() {
- DCHECK(task_runner_->RunsTasksInCurrentSequence());
- gpu_bindings_.CloseAllBindings();
- OnError(ErrorReason::kInDestructor);
-}
-
-void GpuClientImpl::Add(ui::mojom::GpuRequest request) {
- DCHECK(task_runner_->RunsTasksInCurrentSequence());
- gpu_bindings_.AddBinding(this, std::move(request));
-}
-
-void GpuClientImpl::OnError(ErrorReason reason) {
- DCHECK(task_runner_->RunsTasksInCurrentSequence());
- ClearCallback();
- if (gpu_bindings_.empty()) {
- BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager =
- BrowserGpuMemoryBufferManager::current();
- if (gpu_memory_buffer_manager)
- gpu_memory_buffer_manager->ProcessRemoved(client_id_);
- }
- if (reason == ErrorReason::kConnectionLost && connection_error_handler_)
- std::move(connection_error_handler_).Run(this);
-}
-
-void GpuClientImpl::PreEstablishGpuChannel() {
- if (task_runner_->RunsTasksInCurrentSequence()) {
- EstablishGpuChannel(EstablishGpuChannelCallback());
- } else {
- task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&GpuClientImpl::EstablishGpuChannel,
- base::Unretained(this), EstablishGpuChannelCallback()));
- }
-}
-
-void GpuClientImpl::SetConnectionErrorHandler(
- ConnectionErrorHandlerClosure connection_error_handler) {
- connection_error_handler_ = std::move(connection_error_handler);
-}
-
-void GpuClientImpl::OnEstablishGpuChannel(
- mojo::ScopedMessagePipeHandle channel_handle,
- const gpu::GPUInfo& gpu_info,
- const gpu::GpuFeatureInfo& gpu_feature_info,
- GpuProcessHost::EstablishChannelStatus status) {
- DCHECK_EQ(channel_handle.is_valid(),
- status == GpuProcessHost::EstablishChannelStatus::SUCCESS);
- gpu_channel_requested_ = false;
- EstablishGpuChannelCallback callback = std::move(callback_);
- DCHECK(!callback_);
-
- if (status == GpuProcessHost::EstablishChannelStatus::GPU_HOST_INVALID) {
- // GPU process may have crashed or been killed. Try again.
- EstablishGpuChannel(std::move(callback));
- return;
- }
- if (callback) {
- // A request is waiting.
- std::move(callback).Run(client_id_, std::move(channel_handle), gpu_info,
- gpu_feature_info);
- return;
- }
- if (status == GpuProcessHost::EstablishChannelStatus::SUCCESS) {
- // This is the case we pre-establish a channel before a request arrives.
- // Cache the channel for a future request.
- channel_handle_ = std::move(channel_handle);
- gpu_info_ = gpu_info;
- gpu_feature_info_ = gpu_feature_info;
- }
-}
-
-void GpuClientImpl::OnCreateGpuMemoryBuffer(
- CreateGpuMemoryBufferCallback callback,
- gfx::GpuMemoryBufferHandle handle) {
- std::move(callback).Run(std::move(handle));
-}
-
-void GpuClientImpl::ClearCallback() {
- if (!callback_)
- return;
- EstablishGpuChannelCallback callback = std::move(callback_);
- std::move(callback).Run(client_id_, mojo::ScopedMessagePipeHandle(),
- gpu::GPUInfo(), gpu::GpuFeatureInfo());
- DCHECK(!callback_);
-}
-
-void GpuClientImpl::EstablishGpuChannel(EstablishGpuChannelCallback callback) {
- DCHECK(task_runner_->RunsTasksInCurrentSequence());
- // At most one channel should be requested. So clear previous request first.
- ClearCallback();
- if (channel_handle_.is_valid()) {
- // If a channel has been pre-established and cached,
- // 1) if callback is valid, return it right away.
- // 2) if callback is empty, it's PreEstablishGpyChannel() being called
- // more than once, no need to do anything.
- if (callback) {
- std::move(callback).Run(client_id_, std::move(channel_handle_), gpu_info_,
- gpu_feature_info_);
- DCHECK(!channel_handle_.is_valid());
- }
- return;
- }
- GpuProcessHost* host = GpuProcessHost::Get();
- if (!host) {
- if (callback) {
- std::move(callback).Run(client_id_, mojo::ScopedMessagePipeHandle(),
- gpu::GPUInfo(), gpu::GpuFeatureInfo());
- }
- return;
- }
- callback_ = std::move(callback);
- if (gpu_channel_requested_)
- return;
- gpu_channel_requested_ = true;
- bool preempts = false;
- bool allow_view_command_buffers = false;
- bool allow_real_time_streams = false;
- host->EstablishGpuChannel(
- client_id_, client_tracing_id_, preempts, allow_view_command_buffers,
- allow_real_time_streams,
- base::BindRepeating(&GpuClientImpl::OnEstablishGpuChannel,
- weak_factory_.GetWeakPtr()));
-}
-
-void GpuClientImpl::CreateJpegDecodeAccelerator(
- media::mojom::JpegDecodeAcceleratorRequest jda_request) {
- GpuProcessHost* host = GpuProcessHost::Get();
- if (host)
- host->gpu_service()->CreateJpegDecodeAccelerator(std::move(jda_request));
-}
-
-void GpuClientImpl::CreateVideoEncodeAcceleratorProvider(
- media::mojom::VideoEncodeAcceleratorProviderRequest vea_provider_request) {
- GpuProcessHost* host = GpuProcessHost::Get();
- if (!host)
- return;
- host->gpu_service()->CreateVideoEncodeAcceleratorProvider(
- std::move(vea_provider_request));
-}
-
-void GpuClientImpl::CreateGpuMemoryBuffer(
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- ui::mojom::GpuMemoryBufferFactory::CreateGpuMemoryBufferCallback callback) {
- DCHECK(BrowserGpuMemoryBufferManager::current());
-
- base::CheckedNumeric<int> bytes = size.width();
- bytes *= size.height();
- if (!bytes.IsValid()) {
- OnCreateGpuMemoryBuffer(std::move(callback), gfx::GpuMemoryBufferHandle());
- return;
- }
-
- BrowserGpuMemoryBufferManager::current()
- ->AllocateGpuMemoryBufferForChildProcess(
- id, size, format, usage, client_id_,
- base::BindOnce(&GpuClientImpl::OnCreateGpuMemoryBuffer,
- weak_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void GpuClientImpl::DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
- const gpu::SyncToken& sync_token) {
- DCHECK(BrowserGpuMemoryBufferManager::current());
-
- BrowserGpuMemoryBufferManager::current()->ChildProcessDeletedGpuMemoryBuffer(
- id, client_id_, sync_token);
-}
-
-void GpuClientImpl::CreateGpuMemoryBufferFactory(
- ui::mojom::GpuMemoryBufferFactoryRequest request) {
- gpu_memory_buffer_factory_bindings_.AddBinding(this, std::move(request));
-}
-
-} // namespace content
diff --git a/chromium/content/browser/gpu/gpu_client_impl.h b/chromium/content/browser/gpu/gpu_client_impl.h
deleted file mode 100644
index 70e684a68be..00000000000
--- a/chromium/content/browser/gpu/gpu_client_impl.h
+++ /dev/null
@@ -1,95 +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 CONTENT_BROWSER_GPU_GPU_CLIENT_IMPL_H_
-#define CONTENT_BROWSER_GPU_GPU_CLIENT_IMPL_H_
-
-#include "base/callback_forward.h"
-#include "base/memory/weak_ptr.h"
-#include "content/browser/gpu/gpu_process_host.h"
-#include "content/public/browser/gpu_client.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-
-namespace content {
-
-class GpuClientImpl : public ui::mojom::GpuMemoryBufferFactory,
- public ui::mojom::Gpu,
- public GpuClient {
- public:
- // GpuClientImpl must be destroyed on the thread associated with
- // |task_runner|.
- GpuClientImpl(int client_id,
- uint64_t client_tracing_id,
- scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
-
- ~GpuClientImpl() override;
-
- // This needs to be run on the thread associated with |task_runner_|.
- void Add(ui::mojom::GpuRequest request);
-
- void PreEstablishGpuChannel();
-
- void SetConnectionErrorHandler(
- ConnectionErrorHandlerClosure connection_error_handler);
-
- // ui::mojom::GpuMemoryBufferFactory overrides:
- void CreateGpuMemoryBuffer(
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- ui::mojom::GpuMemoryBufferFactory::CreateGpuMemoryBufferCallback callback)
- override;
- void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
- const gpu::SyncToken& sync_token) override;
-
- // ui::mojom::Gpu overrides:
- void CreateGpuMemoryBufferFactory(
- ui::mojom::GpuMemoryBufferFactoryRequest request) override;
- void EstablishGpuChannel(EstablishGpuChannelCallback callback) override;
- void CreateJpegDecodeAccelerator(
- media::mojom::JpegDecodeAcceleratorRequest jda_request) override;
- void CreateVideoEncodeAcceleratorProvider(
- media::mojom::VideoEncodeAcceleratorProviderRequest vea_provider_request)
- override;
-
- private:
- enum class ErrorReason {
- // OnError() is being called from the destructor.
- kInDestructor,
- // OnError() is being called because the connection was lost.
- kConnectionLost
- };
- void OnError(ErrorReason reason);
- void OnEstablishGpuChannel(mojo::ScopedMessagePipeHandle channel_handle,
- const gpu::GPUInfo& gpu_info,
- const gpu::GpuFeatureInfo& gpu_feature_info,
- GpuProcessHost::EstablishChannelStatus status);
- void OnCreateGpuMemoryBuffer(CreateGpuMemoryBufferCallback callback,
- gfx::GpuMemoryBufferHandle handle);
- void ClearCallback();
-
- const int client_id_;
- const uint64_t client_tracing_id_;
- mojo::BindingSet<ui::mojom::GpuMemoryBufferFactory>
- gpu_memory_buffer_factory_bindings_;
- mojo::BindingSet<ui::mojom::Gpu> gpu_bindings_;
- bool gpu_channel_requested_ = false;
- EstablishGpuChannelCallback callback_;
- mojo::ScopedMessagePipeHandle channel_handle_;
- gpu::GPUInfo gpu_info_;
- gpu::GpuFeatureInfo gpu_feature_info_;
- ConnectionErrorHandlerClosure connection_error_handler_;
- // |task_runner_| is associated with the thread |gpu_bindings_| is bound on.
- // GpuClientImpl instance is bound to this thread, and must be destroyed on
- // this thread.
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- base::WeakPtrFactory<GpuClientImpl> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(GpuClientImpl);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_GPU_GPU_CLIENT_IMPL_H_
diff --git a/chromium/content/browser/gpu/gpu_data_manager_impl_private.cc b/chromium/content/browser/gpu/gpu_data_manager_impl_private.cc
index 63797576500..4541da4f15c 100644
--- a/chromium/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/chromium/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -23,7 +23,7 @@
#include "build/build_config.h"
#include "cc/base/switches.h"
#include "components/viz/common/features.h"
-#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
+#include "content/browser/gpu/gpu_memory_buffer_manager_singleton.h"
#include "content/browser/gpu/gpu_process_host.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/gpu_data_manager_observer.h"
@@ -584,11 +584,10 @@ void GpuDataManagerImplPrivate::UpdateGpuPreferences(
gpu::GpuPreferences* gpu_preferences) const {
DCHECK(gpu_preferences);
- BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager =
- BrowserGpuMemoryBufferManager::current();
// For performance reasons, discourage storing VideoFrames in a biplanar
// GpuMemoryBuffer if this is not native, see https://crbug.com/791676.
- if (gpu_memory_buffer_manager) {
+ if (auto* gpu_memory_buffer_manager =
+ GpuMemoryBufferManagerSingleton::GetInstance()) {
gpu_preferences->disable_biplanar_gpu_memory_buffers_for_video_frames =
!gpu_memory_buffer_manager->IsNativeGpuMemoryBufferConfiguration(
gfx::BufferFormat::YUV_420_BIPLANAR,
diff --git a/chromium/content/browser/gpu/gpu_internals_ui.cc b/chromium/content/browser/gpu/gpu_internals_ui.cc
index a64a4419064..02779864950 100644
--- a/chromium/content/browser/gpu/gpu_internals_ui.cc
+++ b/chromium/content/browser/gpu/gpu_internals_ui.cc
@@ -226,6 +226,9 @@ std::unique_ptr<base::ListValue> BasicGpuInfoAsListValue(
NewDescriptionValuePair("Driver version", active_gpu.driver_version));
basic_info->Append(
NewDescriptionValuePair("Driver date", active_gpu.driver_date));
+ basic_info->Append(NewDescriptionValuePair(
+ "GPU CUDA compute capability major version",
+ std::make_unique<base::Value>(active_gpu.cuda_compute_capability_major)));
basic_info->Append(NewDescriptionValuePair("Pixel shader version",
gpu_info.pixel_shader_version));
basic_info->Append(NewDescriptionValuePair("Vertex shader version",
diff --git a/chromium/content/browser/gpu/gpu_ipc_browsertests.cc b/chromium/content/browser/gpu/gpu_ipc_browsertests.cc
index 31f2ab76871..5c930b2e7da 100644
--- a/chromium/content/browser/gpu/gpu_ipc_browsertests.cc
+++ b/chromium/content/browser/gpu/gpu_ipc_browsertests.cc
@@ -17,8 +17,8 @@
#include "content/test/gpu_browsertest_helpers.h"
#include "gpu/ipc/client/command_buffer_proxy_impl.h"
#include "gpu/ipc/client/gpu_channel_host.h"
-#include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
#include "services/viz/privileged/interfaces/gl/gpu_service.mojom.h"
+#include "services/ws/public/cpp/gpu/context_provider_command_buffer.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkSurface.h"
@@ -81,7 +81,7 @@ class ContextTestBase : public content::ContentBrowserTest {
gpu::ContextSupport* context_support_ = nullptr;
private:
- scoped_refptr<ui::ContextProviderCommandBuffer> provider_;
+ scoped_refptr<ws::ContextProviderCommandBuffer> provider_;
};
} // namespace
@@ -221,7 +221,7 @@ IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest,
MAYBE_GrContextKeepsGpuChannelAlive) {
// Test for crbug.com/551143
// This test verifies that holding a reference to the GrContext created by
- // a ui::ContextProviderCommandBuffer will keep the gpu channel alive after
+ // a ws::ContextProviderCommandBuffer will keep the gpu channel alive after
// the
// provider has been destroyed. Without this behavior, user code would have
// to be careful to destroy objects in the right order to avoid using freed
@@ -231,7 +231,7 @@ IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest,
// Step 2: verify that holding onto the provider's GrContext will
// retain the host after provider is destroyed.
- scoped_refptr<ui::ContextProviderCommandBuffer> provider =
+ scoped_refptr<ws::ContextProviderCommandBuffer> provider =
content::GpuBrowsertestCreateContext(GetGpuChannel());
ASSERT_EQ(provider->BindToCurrentThread(), gpu::ContextResult::kSuccess);
@@ -278,7 +278,7 @@ IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest,
EstablishAndWait();
scoped_refptr<gpu::GpuChannelHost> host = GetGpuChannel();
- scoped_refptr<ui::ContextProviderCommandBuffer> provider =
+ scoped_refptr<ws::ContextProviderCommandBuffer> provider =
content::GpuBrowsertestCreateContext(GetGpuChannel());
ContextLostRunLoop run_loop(provider.get());
ASSERT_EQ(provider->BindToCurrentThread(), gpu::ContextResult::kSuccess);
@@ -367,4 +367,24 @@ IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest, CreateTransferBuffer) {
}
#endif
+class GpuProcessHostDisableGLBrowserTest : public GpuProcessHostBrowserTest {
+ public:
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ GpuProcessHostBrowserTest::SetUpCommandLine(command_line);
+ command_line->AppendSwitchASCII(switches::kUseGL,
+ gl::kGLImplementationDisabledName);
+ }
+};
+
+// Android and CrOS don't support disabling GL.
+#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+IN_PROC_BROWSER_TEST_F(GpuProcessHostDisableGLBrowserTest, CreateAndDestroy) {
+ DCHECK(!IsChannelEstablished());
+ EstablishAndWait();
+ base::RunLoop run_loop;
+ StopGpuProcess(run_loop.QuitClosure());
+ run_loop.Run();
+}
+#endif
+
} // namespace content
diff --git a/chromium/content/browser/gpu/gpu_memory_buffer_manager_singleton.cc b/chromium/content/browser/gpu/gpu_memory_buffer_manager_singleton.cc
new file mode 100644
index 00000000000..780450a72bc
--- /dev/null
+++ b/chromium/content/browser/gpu/gpu_memory_buffer_manager_singleton.cc
@@ -0,0 +1,50 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/gpu/gpu_memory_buffer_manager_singleton.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "content/browser/gpu/gpu_process_host.h"
+#include "content/public/browser/browser_thread.h"
+#include "gpu/ipc/common/gpu_memory_buffer_support.h"
+
+namespace content {
+namespace {
+
+GpuMemoryBufferManagerSingleton* g_gpu_memory_buffer_manager;
+
+viz::mojom::GpuService* GetGpuService(
+ base::OnceClosure connection_error_handler) {
+ if (auto* host = GpuProcessHost::Get()) {
+ host->AddConnectionErrorHandler(std::move(connection_error_handler));
+ return host->gpu_service();
+ }
+ return nullptr;
+}
+
+} // namespace
+
+GpuMemoryBufferManagerSingleton::GpuMemoryBufferManagerSingleton(int client_id)
+ : HostGpuMemoryBufferManager(
+ base::BindRepeating(&content::GetGpuService),
+ client_id,
+ std::make_unique<gpu::GpuMemoryBufferSupport>(),
+ BrowserThread::GetTaskRunnerForThread(BrowserThread::IO)) {
+ DCHECK(!g_gpu_memory_buffer_manager);
+ g_gpu_memory_buffer_manager = this;
+}
+
+GpuMemoryBufferManagerSingleton::~GpuMemoryBufferManagerSingleton() {
+ DCHECK_EQ(this, g_gpu_memory_buffer_manager);
+ g_gpu_memory_buffer_manager = nullptr;
+}
+
+// static
+GpuMemoryBufferManagerSingleton*
+GpuMemoryBufferManagerSingleton::GetInstance() {
+ return g_gpu_memory_buffer_manager;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/gpu/gpu_memory_buffer_manager_singleton.h b/chromium/content/browser/gpu/gpu_memory_buffer_manager_singleton.h
new file mode 100644
index 00000000000..3a662ef1536
--- /dev/null
+++ b/chromium/content/browser/gpu/gpu_memory_buffer_manager_singleton.h
@@ -0,0 +1,28 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_GPU_GPU_MEMORY_BUFFER_MANAGER_SINGLETON_H_
+#define CONTENT_BROWSER_GPU_GPU_MEMORY_BUFFER_MANAGER_SINGLETON_H_
+
+#include "components/viz/host/host_gpu_memory_buffer_manager.h"
+
+namespace content {
+
+// This class ensures that there is at most one instance of
+// |viz::HostGpuMemoryBufferManager| in content at any given time. Code in
+// content must use this class to access the instance.
+class GpuMemoryBufferManagerSingleton : public viz::HostGpuMemoryBufferManager {
+ public:
+ explicit GpuMemoryBufferManagerSingleton(int client_id);
+ ~GpuMemoryBufferManagerSingleton() override;
+
+ static GpuMemoryBufferManagerSingleton* GetInstance();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferManagerSingleton);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_GPU_GPU_MEMORY_BUFFER_MANAGER_SINGLETON_H_
diff --git a/chromium/content/browser/gpu/gpu_process_host.cc b/chromium/content/browser/gpu/gpu_process_host.cc
index bdecceea7e6..9511100e607 100644
--- a/chromium/content/browser/gpu/gpu_process_host.cc
+++ b/chromium/content/browser/gpu/gpu_process_host.cc
@@ -41,6 +41,7 @@
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/gpu/gpu_main_thread_factory.h"
+#include "content/browser/gpu/gpu_memory_buffer_manager_singleton.h"
#include "content/browser/gpu/shader_cache_factory.h"
#include "content/browser/memory/memory_coordinator_impl.h"
#include "content/browser/service_manager/service_manager_context.h"
@@ -63,7 +64,9 @@
#include "gpu/command_buffer/service/gpu_switches.h"
#include "gpu/config/gpu_driver_bug_list.h"
#include "gpu/config/gpu_driver_bug_workaround_type.h"
+#include "gpu/config/gpu_finch_features.h"
#include "gpu/config/gpu_preferences.h"
+#include "gpu/ipc/common/gpu_client_ids.h"
#include "gpu/ipc/host/shader_disk_cache.h"
#include "gpu/ipc/in_process_command_buffer.h"
#include "media/base/media_switches.h"
@@ -74,7 +77,7 @@
#include "services/service_manager/runner/common/client_util.h"
#include "services/service_manager/sandbox/sandbox_type.h"
#include "services/service_manager/sandbox/switches.h"
-#include "services/ui/public/interfaces/constants.mojom.h"
+#include "services/ws/public/mojom/constants.mojom.h"
#include "ui/base/ui_base_features.h"
#include "ui/base/ui_base_switches.h"
#include "ui/display/display_switches.h"
@@ -84,7 +87,6 @@
#include "ui/latency/latency_info.h"
#if defined(OS_ANDROID)
-#include "base/android/build_info.h"
#include "content/public/browser/android/java_interfaces.h"
#include "media/mojo/interfaces/android_overlay.mojom.h"
#endif
@@ -92,7 +94,6 @@
#if defined(OS_WIN)
#include "sandbox/win/src/sandbox_policy.h"
#include "services/service_manager/sandbox/win/sandbox_win.h"
-#include "ui/gfx/switches.h"
#include "ui/gfx/win/rendering_window_manager.h"
#endif
@@ -237,7 +238,6 @@ static const char* const kSwitchNames[] = {
switches::kShowMacOverlayBorders,
#endif
#if defined(USE_OZONE)
- switches::kEnableDrmMojo,
switches::kOzonePlatform,
switches::kOzoneDumpFile,
#endif
@@ -305,7 +305,7 @@ void OzoneRegisterStartupCallbackHelper(
}
},
base::RetainedRef(base::ThreadTaskRunnerHandle::Get()),
- base::Passed(&io_callback));
+ std::move(io_callback));
ui::OzonePlatform::RegisterStartupCallback(std::move(bounce_callback));
}
#endif // defined(USE_OZONE)
@@ -471,9 +471,9 @@ void BindDiscardableMemoryRequestOnUI(
DCHECK_CURRENTLY_ON(BrowserThread::UI);
#if defined(USE_AURA)
- if (!features::IsAshInBrowserProcess()) {
+ if (features::IsMultiProcessMash()) {
ServiceManagerConnection::GetForProcess()->GetConnector()->BindInterface(
- ui::mojom::kServiceName, std::move(request));
+ ws::mojom::kServiceName, std::move(request));
return;
}
#endif
@@ -484,16 +484,6 @@ void BindDiscardableMemoryRequestOnUI(
BrowserMainLoop::GetInstance()->discardable_shared_memory_manager()));
}
-struct FontRenderParamsOnIO {
- bool initialized = false;
- gfx::FontRenderParams params;
-};
-
-FontRenderParamsOnIO& GetFontRenderParamsOnIO() {
- static base::NoDestructor<FontRenderParamsOnIO> instance;
- return *instance;
-}
-
void CreateMemoryCoordinatorHandleForGpuProcess(
int gpu_process_id,
mojom::MemoryCoordinatorHandleRequest request) {
@@ -539,16 +529,6 @@ class GpuProcessHost::ConnectionFilterImpl : public ConnectionFilter {
};
// static
-void GpuProcessHost::InitFontRenderParamsOnIO(
- const gfx::FontRenderParams& params) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(!GetFontRenderParamsOnIO().initialized);
-
- GetFontRenderParamsOnIO().initialized = true;
- GetFontRenderParamsOnIO().params = params;
-}
-
-// static
bool GpuProcessHost::ValidateHost(GpuProcessHost* host) {
// The Gpu process is invalid if it's not using SwiftShader, the card is
// blacklisted, and we can kill it and start over.
@@ -654,6 +634,14 @@ void GpuProcessHost::BindInterface(
std::move(interface_pipe));
}
+void GpuProcessHost::TerminateGpuProcess(const std::string& message) {
+ // At the moment, this path is only used by Ozone/Wayland. Once others start
+ // to use this, start to distinguish the origin of termination. By default,
+ // it's unknown.
+ termination_origin_ = GpuTerminationOrigin::kOzoneWaylandProxy;
+ process_->TerminateOnBadMessageReceived(message);
+}
+
// static
GpuProcessHost* GpuProcessHost::FromID(int host_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -700,8 +688,6 @@ GpuProcessHost::GpuProcessHost(int host_id, GpuProcessKind kind)
in_process_(false),
kind_(kind),
process_launched_(false),
- status_(UNKNOWN),
- gpu_host_binding_(this),
weak_ptr_factory_(this) {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSingleProcess) ||
@@ -725,7 +711,7 @@ GpuProcessHost::~GpuProcessHost() {
if (in_process_gpu_thread_)
DCHECK(process_);
- SendOutstandingReplies(EstablishChannelStatus::GPU_HOST_INVALID);
+ SendOutstandingReplies();
#if defined(OS_MACOSX)
if (ca_transaction_gpu_coordinator_) {
@@ -734,12 +720,6 @@ GpuProcessHost::~GpuProcessHost() {
}
#endif
- if (status_ == UNKNOWN) {
- RunRequestGPUInfoCallbacks(gpu::GPUInfo());
- } else {
- DCHECK(request_gpu_info_callbacks_.empty());
- }
-
// In case we never started, clean up.
while (!queued_messages_.empty()) {
delete queued_messages_.front();
@@ -758,7 +738,8 @@ GpuProcessHost::~GpuProcessHost() {
std::string message;
bool block_offscreen_contexts = true;
- if (!in_process_ && process_launched_) {
+ if (!in_process_ && process_launched_ &&
+ kind_ == GPU_PROCESS_KIND_SANDBOXED) {
ChildProcessTerminationInfo info =
process_->GetTerminationInfo(false /* known_dead */);
UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessTerminationStatus2",
@@ -791,6 +772,9 @@ GpuProcessHost::~GpuProcessHost() {
info.exit_code);
break;
case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
+ UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessTerminationOrigin",
+ termination_origin_,
+ GpuTerminationOrigin::kMax);
message = "You killed the GPU process! Why?";
break;
#if defined(OS_CHROMEOS)
@@ -809,11 +793,11 @@ GpuProcessHost::~GpuProcessHost() {
}
}
- // If there are any remaining offscreen contexts at the point the
- // GPU process exits, assume something went wrong, and block their
- // URLs from accessing client 3D APIs without prompting.
- if (block_offscreen_contexts)
- BlockLiveOffscreenContexts();
+ // If there are any remaining offscreen contexts at the point the GPU process
+ // exits, assume something went wrong, and block their URLs from accessing
+ // client 3D APIs without prompting.
+ if (block_offscreen_contexts && gpu_host_)
+ gpu_host_->BlockLiveOffscreenContexts();
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
@@ -826,26 +810,31 @@ void GpuProcessHost::InitOzone() {
// possible to ensure the latter always has a valid device. crbug.com/608839
// When running with mus, the OzonePlatform may not have been created yet. So
// defer the callback until OzonePlatform instance is created.
- base::CommandLine* browser_command_line =
- base::CommandLine::ForCurrentProcess();
- if (browser_command_line->HasSwitch(switches::kEnableDrmMojo)) {
+ bool using_mojo = true;
+#if defined(OS_CHROMEOS)
+ using_mojo = features::IsOzoneDrmMojo();
+#endif
+ if (using_mojo) {
// TODO(rjkroege): Remove the legacy IPC code paths when no longer
// necessary. https://crbug.com/806092
auto interface_binder = base::BindRepeating(&GpuProcessHost::BindInterface,
weak_ptr_factory_.GetWeakPtr());
+ auto terminate_cb = base::BindOnce(&GpuProcessHost::TerminateGpuProcess,
+ weak_ptr_factory_.GetWeakPtr());
auto io_callback = base::BindOnce(
[](const base::RepeatingCallback<void(const std::string&,
mojo::ScopedMessagePipeHandle)>&
interface_binder,
+ base::OnceCallback<void(const std::string&)> terminate_cb,
ui::OzonePlatform* platform) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
platform->GetGpuPlatformSupportHost()->OnGpuServiceLaunched(
BrowserThread::GetTaskRunnerForThread(BrowserThread::UI),
BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
- interface_binder);
+ interface_binder, std::move(terminate_cb));
},
- interface_binder);
+ interface_binder, std::move(terminate_cb));
OzoneRegisterStartupCallbackHelper(std::move(io_callback));
} else {
@@ -911,24 +900,17 @@ bool GpuProcessHost::Init() {
return false;
}
- process_->child_channel()
- ->GetAssociatedInterfaceSupport()
- ->GetRemoteAssociatedInterface(&gpu_main_ptr_);
- viz::mojom::GpuHostPtr host_proxy;
- gpu_host_binding_.Bind(mojo::MakeRequest(&host_proxy));
-
- discardable_memory::mojom::DiscardableSharedMemoryManagerPtr
- discardable_manager_ptr;
- auto discardable_request = mojo::MakeRequest(&discardable_manager_ptr);
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::BindOnce(&BindDiscardableMemoryRequestOnUI,
- std::move(discardable_request)));
-
- DCHECK(GetFontRenderParamsOnIO().initialized);
- gpu_main_ptr_->CreateGpuService(
- mojo::MakeRequest(&gpu_service_ptr_), std::move(host_proxy),
- std::move(discardable_manager_ptr), activity_flags_.CloneHandle(),
- GetFontRenderParamsOnIO().params.subpixel_rendering);
+ viz::GpuHostImpl::InitParams params;
+ params.restart_id = host_id_;
+ params.in_process = in_process_;
+ params.disable_gpu_shader_disk_cache =
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableGpuShaderDiskCache);
+ params.product = GetContentClient()->GetProduct();
+ params.deadline_to_synchronize_surfaces =
+ switches::GetDeadlineToSynchronizeSurfaces();
+ gpu_host_ = std::make_unique<viz::GpuHostImpl>(
+ this, process_->child_channel(), std::move(params));
#if defined(USE_OZONE)
InitOzone();
@@ -953,7 +935,7 @@ bool GpuProcessHost::Send(IPC::Message* msg) {
// Channel is hosed, but we may not get destroyed for a while. Send
// outstanding channel creation failures now so that the caller can restart
// with a new process/channel without waiting.
- SendOutstandingReplies(EstablishChannelStatus::GPU_HOST_INVALID);
+ SendOutstandingReplies();
}
return result;
}
@@ -977,144 +959,8 @@ void GpuProcessHost::OnChannelConnected(int32_t peer_pid) {
}
}
-void GpuProcessHost::EstablishGpuChannel(
- int client_id,
- uint64_t client_tracing_id,
- bool preempts,
- bool allow_view_command_buffers,
- bool allow_real_time_streams,
- const EstablishChannelCallback& callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- TRACE_EVENT0("gpu", "GpuProcessHost::EstablishGpuChannel");
-
- // If GPU features are already blacklisted, no need to establish the channel.
- if (!GpuDataManagerImpl::GetInstance()->GpuAccessAllowed(nullptr)) {
- DVLOG(1) << "GPU blacklisted, refusing to open a GPU channel.";
- callback.Run(mojo::ScopedMessagePipeHandle(), gpu::GPUInfo(),
- gpu::GpuFeatureInfo(),
- EstablishChannelStatus::GPU_ACCESS_DENIED);
- return;
- }
-
- bool oopd_enabled =
- base::FeatureList::IsEnabled(features::kVizDisplayCompositor);
- if (oopd_enabled && client_id == gpu::InProcessCommandBuffer::kGpuClientId) {
- // The display-compositor in the gpu process uses this special client id.
- callback.Run(mojo::ScopedMessagePipeHandle(), gpu::GPUInfo(),
- gpu::GpuFeatureInfo(),
- EstablishChannelStatus::GPU_ACCESS_DENIED);
- return;
- }
-
- DCHECK_EQ(preempts, allow_view_command_buffers);
- DCHECK_EQ(preempts, allow_real_time_streams);
- bool is_gpu_host = preempts;
-
- channel_requests_.push(callback);
- gpu_service_ptr_->EstablishGpuChannel(
- client_id, client_tracing_id, is_gpu_host,
- base::BindOnce(&GpuProcessHost::OnChannelEstablished,
- weak_ptr_factory_.GetWeakPtr(), client_id, callback));
-
- if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableGpuShaderDiskCache)) {
- CreateChannelCache(client_id);
- if (oopd_enabled)
- CreateChannelCache(gpu::InProcessCommandBuffer::kGpuClientId);
- }
-}
-
-void GpuProcessHost::CreateGpuMemoryBuffer(
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- int client_id,
- gpu::SurfaceHandle surface_handle,
- CreateGpuMemoryBufferCallback callback) {
- TRACE_EVENT0("gpu", "GpuProcessHost::CreateGpuMemoryBuffer");
-
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- create_gpu_memory_buffer_requests_.push(std::move(callback));
- gpu_service_ptr_->CreateGpuMemoryBuffer(
- id, size, format, usage, client_id, surface_handle,
- base::BindOnce(&GpuProcessHost::OnGpuMemoryBufferCreated,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
-void GpuProcessHost::DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
- int client_id,
- const gpu::SyncToken& sync_token) {
- TRACE_EVENT0("gpu", "GpuProcessHost::DestroyGpuMemoryBuffer");
- gpu_service_ptr_->DestroyGpuMemoryBuffer(id, client_id, sync_token);
-}
-
-void GpuProcessHost::ConnectFrameSinkManager(
- viz::mojom::FrameSinkManagerRequest request,
- viz::mojom::FrameSinkManagerClientPtrInfo client) {
- TRACE_EVENT0("gpu", "GpuProcessHost::ConnectFrameSinkManager");
- viz::mojom::FrameSinkManagerParamsPtr params =
- viz::mojom::FrameSinkManagerParams::New();
- params->restart_id = host_id_;
- base::Optional<uint32_t> activation_deadline_in_frames =
- switches::GetDeadlineToSynchronizeSurfaces();
- params->use_activation_deadline = activation_deadline_in_frames.has_value();
- params->activation_deadline_in_frames =
- activation_deadline_in_frames.value_or(0u);
- params->frame_sink_manager = std::move(request);
- params->frame_sink_manager_client = std::move(client);
- gpu_main_ptr_->CreateFrameSinkManager(std::move(params));
-}
-
-void GpuProcessHost::RequestGPUInfo(RequestGPUInfoCallback request_cb) {
- if (status_ == SUCCESS || status_ == FAILURE) {
- std::move(request_cb).Run(GpuDataManagerImpl::GetInstance()->GetGPUInfo());
- return;
- }
-
- request_gpu_info_callbacks_.push_back(std::move(request_cb));
-}
-
-void GpuProcessHost::RequestHDRStatus(RequestHDRStatusCallback request_cb) {
- gpu_service_ptr_->RequestHDRStatus(std::move(request_cb));
-}
-
-void GpuProcessHost::OnChannelEstablished(
- int client_id,
- const EstablishChannelCallback& callback,
- mojo::ScopedMessagePipeHandle channel_handle) {
- TRACE_EVENT0("gpu", "GpuProcessHost::OnChannelEstablished");
- DCHECK(!channel_requests_.empty());
- DCHECK(channel_requests_.front().Equals(callback));
- channel_requests_.pop();
-
- auto* gpu_data_manager = GpuDataManagerImpl::GetInstance();
- // Currently if any of the GPU features are blacklisted, we don't establish a
- // GPU channel.
- if (channel_handle.is_valid() &&
- !gpu_data_manager->GpuAccessAllowed(nullptr)) {
- gpu_service_ptr_->CloseChannel(client_id);
- callback.Run(mojo::ScopedMessagePipeHandle(), gpu::GPUInfo(),
- gpu::GpuFeatureInfo(),
- EstablishChannelStatus::GPU_ACCESS_DENIED);
- RecordLogMessage(logging::LOG_WARNING, "WARNING",
- "Hardware acceleration is unavailable.");
- return;
- }
-
- callback.Run(std::move(channel_handle), gpu_data_manager->GetGPUInfo(),
- gpu_data_manager->GetGpuFeatureInfo(),
- EstablishChannelStatus::SUCCESS);
-}
-
-void GpuProcessHost::OnGpuMemoryBufferCreated(
- gfx::GpuMemoryBufferHandle handle) {
- TRACE_EVENT0("gpu", "GpuProcessHost::OnGpuMemoryBufferCreated");
-
- DCHECK(!create_gpu_memory_buffer_requests_.empty());
- auto callback = std::move(create_gpu_memory_buffer_requests_.front());
- create_gpu_memory_buffer_requests_.pop();
- std::move(callback).Run(std::move(handle), BufferCreationStatus::SUCCESS);
+void GpuProcessHost::AddConnectionErrorHandler(base::OnceClosure handler) {
+ connection_error_handlers_.push_back(std::move(handler));
}
#if defined(OS_ANDROID)
@@ -1132,6 +978,12 @@ void GpuProcessHost::OnProcessLaunched() {
if (kind_ == GPU_PROCESS_KIND_SANDBOXED)
RecordAppContainerStatus(sandbox::SBOX_ALL_OK, crashed_before_);
#endif // defined(OS_WIN)
+
+ if (!in_process_) {
+ process_id_ = process_->GetProcess().Pid();
+ DCHECK_NE(base::kNullProcessId, process_id_);
+ gpu_host_->OnProcessLaunched(process_id_);
+ }
}
void GpuProcessHost::OnProcessLaunchFailed(int error_code) {
@@ -1156,61 +1008,40 @@ void GpuProcessHost::OnProcessCrashed(int exit_code) {
// Record crash before doing anything that could start a new GPU process.
RecordProcessCrash();
- // If the GPU process crashed while compiling a shader, we may have invalid
- // cached binaries. Completely clear the shader cache to force shader binaries
- // to be re-created.
- if (activity_flags_.IsFlagSet(
- gpu::ActivityFlagsBase::FLAG_LOADING_PROGRAM_BINARY)) {
- for (auto cache_key : client_id_to_shader_cache_) {
- // This call will temporarily extend the lifetime of the cache (kept
- // alive in the factory), and may drop loads of cached shader binaries if
- // it takes a while to complete. As we are intentionally dropping all
- // binaries, this behavior is fine.
- GetShaderCacheFactorySingleton()->ClearByClientId(
- cache_key.first, base::Time(), base::Time::Max(), base::Bind([] {}));
- }
- }
- SendOutstandingReplies(EstablishChannelStatus::GPU_HOST_INVALID);
+ gpu_host_->OnProcessCrashed();
+
+ SendOutstandingReplies();
ChildProcessTerminationInfo info =
process_->GetTerminationInfo(true /* known_dead */);
GpuDataManagerImpl::GetInstance()->ProcessCrashed(info.status);
}
-void GpuProcessHost::DidInitialize(
+gpu::GPUInfo GpuProcessHost::GetGPUInfo() const {
+ return GpuDataManagerImpl::GetInstance()->GetGPUInfo();
+}
+
+gpu::GpuFeatureInfo GpuProcessHost::GetGpuFeatureInfo() const {
+ return GpuDataManagerImpl::GetInstance()->GetGpuFeatureInfo();
+}
+
+void GpuProcessHost::UpdateGpuInfo(
const gpu::GPUInfo& gpu_info,
const gpu::GpuFeatureInfo& gpu_feature_info,
const base::Optional<gpu::GPUInfo>& gpu_info_for_hardware_gpu,
const base::Optional<gpu::GpuFeatureInfo>&
gpu_feature_info_for_hardware_gpu) {
- UMA_HISTOGRAM_BOOLEAN("GPU.GPUProcessInitialized", true);
- status_ = SUCCESS;
-
- // Set GPU driver bug workaround flags that are checked on the browser side.
- if (gpu_feature_info.IsWorkaroundEnabled(gpu::WAKE_UP_GPU_BEFORE_DRAWING)) {
- wake_up_gpu_before_drawing_ = true;
- }
- if (gpu_feature_info.IsWorkaroundEnabled(
- gpu::DONT_DISABLE_WEBGL_WHEN_COMPOSITOR_CONTEXT_LOST)) {
- dont_disable_webgl_when_compositor_context_lost_ = true;
- }
-
- GpuDataManagerImpl* gpu_data_manager = GpuDataManagerImpl::GetInstance();
+ auto* gpu_data_manager = GpuDataManagerImpl::GetInstance();
// Update GpuFeatureInfo first, because UpdateGpuInfo() will notify all
// listeners.
gpu_data_manager->UpdateGpuFeatureInfo(gpu_feature_info,
gpu_feature_info_for_hardware_gpu);
gpu_data_manager->UpdateGpuInfo(gpu_info, gpu_info_for_hardware_gpu);
- RunRequestGPUInfoCallbacks(gpu_data_manager->GetGPUInfo());
}
void GpuProcessHost::DidFailInitialize() {
- UMA_HISTOGRAM_BOOLEAN("GPU.GPUProcessInitialized", false);
- status_ = FAILURE;
- GpuDataManagerImpl* gpu_data_manager = GpuDataManagerImpl::GetInstance();
if (kind_ == GPU_PROCESS_KIND_SANDBOXED)
- gpu_data_manager->FallBackToNextGpuMode();
- RunRequestGPUInfoCallbacks(gpu_data_manager->GetGPUInfo());
+ GpuDataManagerImpl::GetInstance()->FallBackToNextGpuMode();
}
void GpuProcessHost::DidCreateContextSuccessfully() {
@@ -1222,67 +1053,22 @@ void GpuProcessHost::DidCreateContextSuccessfully() {
#endif
}
-void GpuProcessHost::DidCreateOffscreenContext(const GURL& url) {
- urls_with_live_offscreen_contexts_.insert(url);
-}
-
-void GpuProcessHost::DidDestroyOffscreenContext(const GURL& url) {
- // We only want to remove *one* of the entries in the multiset for
- // this particular URL, so can't use the erase method taking a key.
- auto candidate = urls_with_live_offscreen_contexts_.find(url);
- if (candidate != urls_with_live_offscreen_contexts_.end()) {
- urls_with_live_offscreen_contexts_.erase(candidate);
- }
-}
-
-void GpuProcessHost::DidDestroyChannel(int32_t client_id) {
- TRACE_EVENT0("gpu", "GpuProcessHost::DidDestroyChannel");
- client_id_to_shader_cache_.erase(client_id);
-}
-
-void GpuProcessHost::DidLoseContext(bool offscreen,
- gpu::error::ContextLostReason reason,
- const GURL& active_url) {
- // TODO(kbr): would be nice to see the "offscreen" flag too.
- TRACE_EVENT2("gpu", "GpuProcessHost::DidLoseContext", "reason", reason, "url",
- active_url.possibly_invalid_spec());
-
- if (!offscreen || active_url.is_empty()) {
- // Assume that the loss of the compositor's or accelerated canvas'
- // context is a serious event and blame the loss on all live
- // offscreen contexts. This more robustly handles situations where
- // the GPU process may not actually detect the context loss in the
- // offscreen context. However, situations have been seen where the
- // compositor's context can be lost due to driver bugs (as of this
- // writing, on Android), so allow that possibility.
- if (!dont_disable_webgl_when_compositor_context_lost_) {
- BlockLiveOffscreenContexts();
- }
- return;
- }
-
- GpuDataManagerImpl::DomainGuilt guilt =
- GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN;
- switch (reason) {
- case gpu::error::kGuilty:
- guilt = GpuDataManagerImpl::DOMAIN_GUILT_KNOWN;
+void GpuProcessHost::BlockDomainFrom3DAPIs(const GURL& url,
+ Delegate::DomainGuilt guilt) {
+ GpuDataManagerImpl::DomainGuilt gpu_data_manager_guilt;
+ switch (guilt) {
+ case Delegate::DomainGuilt::kKnown:
+ gpu_data_manager_guilt = GpuDataManagerImpl::DOMAIN_GUILT_KNOWN;
break;
- // Treat most other error codes as though they had unknown provenance.
- // In practice this doesn't affect the user experience. A lost context
- // of either known or unknown guilt still causes user-level 3D APIs
- // (e.g. WebGL) to be blocked on that domain until the user manually
- // reenables them.
- case gpu::error::kUnknown:
- case gpu::error::kOutOfMemory:
- case gpu::error::kMakeCurrentFailed:
- case gpu::error::kGpuChannelLost:
- case gpu::error::kInvalidGpuMessage:
- break;
- case gpu::error::kInnocent:
- return;
+ case Delegate::DomainGuilt::kUnknown:
+ gpu_data_manager_guilt = GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN;
}
+ GpuDataManagerImpl::GetInstance()->BlockDomainFrom3DAPIs(
+ url, gpu_data_manager_guilt);
+}
- GpuDataManagerImpl::GetInstance()->BlockDomainFrom3DAPIs(active_url, guilt);
+bool GpuProcessHost::GpuAccessAllowed() const {
+ return GpuDataManagerImpl::GetInstance()->GpuAccessAllowed(nullptr);
}
void GpuProcessHost::DisableGpuCompositing() {
@@ -1297,47 +1083,8 @@ void GpuProcessHost::DisableGpuCompositing() {
#endif
}
-void GpuProcessHost::SetChildSurface(gpu::SurfaceHandle parent_handle,
- gpu::SurfaceHandle window_handle) {
-#if defined(OS_WIN)
- constexpr char kBadMessageError[] = "Bad parenting request from gpu process.";
- if (!in_process_) {
- DCHECK(process_);
-
- DWORD parent_process_id = 0;
- DWORD parent_thread_id =
- GetWindowThreadProcessId(parent_handle, &parent_process_id);
- if (!parent_thread_id || parent_process_id != ::GetCurrentProcessId()) {
- LOG(ERROR) << kBadMessageError;
- return;
- }
-
- DWORD child_process_id = 0;
- DWORD child_thread_id =
- GetWindowThreadProcessId(window_handle, &child_process_id);
- if (!child_thread_id || child_process_id != process_->GetProcess().Pid()) {
- LOG(ERROR) << kBadMessageError;
- return;
- }
- }
-
- if (!gfx::RenderingWindowManager::GetInstance()->RegisterChild(
- parent_handle, window_handle)) {
- LOG(ERROR) << kBadMessageError;
- }
-#endif
-}
-
-void GpuProcessHost::StoreShaderToDisk(int32_t client_id,
- const std::string& key,
- const std::string& shader) {
- TRACE_EVENT0("gpu", "GpuProcessHost::StoreShaderToDisk");
- ClientIdToShaderCacheMap::iterator iter =
- client_id_to_shader_cache_.find(client_id);
- // If the cache doesn't exist then this is an off the record profile.
- if (iter == client_id_to_shader_cache_.end())
- return;
- iter->second->Cache(GetShaderPrefixKey() + ":" + key, shader);
+gpu::ShaderCacheFactory* GpuProcessHost::GetShaderCacheFactory() {
+ return GetShaderCacheFactorySingleton();
}
void GpuProcessHost::RecordLogMessage(int32_t severity,
@@ -1346,6 +1093,13 @@ void GpuProcessHost::RecordLogMessage(int32_t severity,
GpuDataManagerImpl::GetInstance()->AddLogMessage(severity, header, message);
}
+void GpuProcessHost::BindDiscardableMemoryRequest(
+ discardable_memory::mojom::DiscardableSharedMemoryManagerRequest request) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&BindDiscardableMemoryRequestOnUI, std::move(request)));
+}
+
GpuProcessHost::GpuProcessKind GpuProcessHost::kind() {
return kind_;
}
@@ -1460,46 +1214,20 @@ bool GpuProcessHost::LaunchGpuProcess() {
return true;
}
-void GpuProcessHost::SendOutstandingReplies(
- EstablishChannelStatus failure_status) {
- DCHECK_NE(failure_status, EstablishChannelStatus::SUCCESS);
+void GpuProcessHost::SendOutstandingReplies() {
valid_ = false;
- // First send empty channel handles for all EstablishChannel requests.
- while (!channel_requests_.empty()) {
- auto callback = channel_requests_.front();
- channel_requests_.pop();
- std::move(callback).Run(mojo::ScopedMessagePipeHandle(), gpu::GPUInfo(),
- gpu::GpuFeatureInfo(), failure_status);
- }
+ for (auto& handler : connection_error_handlers_)
+ std::move(handler).Run();
+ connection_error_handlers_.clear();
- while (!create_gpu_memory_buffer_requests_.empty()) {
- auto callback = std::move(create_gpu_memory_buffer_requests_.front());
- create_gpu_memory_buffer_requests_.pop();
- std::move(callback).Run(gfx::GpuMemoryBufferHandle(),
- BufferCreationStatus::GPU_HOST_INVALID);
- }
+ if (gpu_host_)
+ gpu_host_->SendOutstandingReplies();
if (!send_destroying_video_surface_done_cb_.is_null())
base::ResetAndReturn(&send_destroying_video_surface_done_cb_).Run();
}
-void GpuProcessHost::RunRequestGPUInfoCallbacks(const gpu::GPUInfo& gpu_info) {
- for (auto& callback : request_gpu_info_callbacks_)
- std::move(callback).Run(gpu_info);
-
- request_gpu_info_callbacks_.clear();
-}
-
-void GpuProcessHost::BlockLiveOffscreenContexts() {
- for (std::multiset<GURL>::iterator iter =
- urls_with_live_offscreen_contexts_.begin();
- iter != urls_with_live_offscreen_contexts_.end(); ++iter) {
- GpuDataManagerImpl::GetInstance()->BlockDomainFrom3DAPIs(
- *iter, GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN);
- }
-}
-
void GpuProcessHost::RecordProcessCrash() {
#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
// Maximum number of times the GPU process can crash before we try something
@@ -1559,7 +1287,7 @@ void GpuProcessHost::RecordProcessCrash() {
base::debug::Alias(&display_compositor_crash_count);
// GPU process initialization failed and fallback already happened.
- if (status_ == FAILURE)
+ if (!gpu_host_ || !gpu_host_->initialized())
return;
bool disable_crash_limit = base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -1571,57 +1299,9 @@ void GpuProcessHost::RecordProcessCrash() {
GpuDataManagerImpl::GetInstance()->FallBackToNextGpuMode();
}
-std::string GpuProcessHost::GetShaderPrefixKey() {
- if (shader_prefix_key_.empty()) {
- const gpu::GPUInfo info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
- const gpu::GPUInfo::GPUDevice& active_gpu = info.active_gpu();
-
- shader_prefix_key_ = GetContentClient()->GetProduct() + "-" +
- info.gl_vendor + "-" + info.gl_renderer + "-" +
- active_gpu.driver_version + "-" +
- active_gpu.driver_vendor;
-
-#if defined(OS_ANDROID)
- std::string build_fp =
- base::android::BuildInfo::GetInstance()->android_build_fp();
- // TODO(ericrk): Remove this after it's up for a few days. crbug.com/699122
- CHECK(!build_fp.empty());
- shader_prefix_key_ += "-" + build_fp;
-#endif
- }
-
- return shader_prefix_key_;
-}
-
-void GpuProcessHost::LoadedShader(const std::string& key,
- const std::string& data) {
- std::string prefix = GetShaderPrefixKey();
- bool prefix_ok = !key.compare(0, prefix.length(), prefix);
- UMA_HISTOGRAM_BOOLEAN("GPU.ShaderLoadPrefixOK", prefix_ok);
- if (prefix_ok) {
- // Remove the prefix from the key before load.
- std::string key_no_prefix = key.substr(prefix.length() + 1);
- gpu_service_ptr_->LoadedShader(key_no_prefix, data);
- }
-}
-
viz::mojom::GpuService* GpuProcessHost::gpu_service() {
- DCHECK(gpu_service_ptr_.is_bound());
- return gpu_service_ptr_.get();
-}
-
-void GpuProcessHost::CreateChannelCache(int32_t client_id) {
- TRACE_EVENT0("gpu", "GpuProcessHost::CreateChannelCache");
-
- scoped_refptr<gpu::ShaderDiskCache> cache =
- GetShaderCacheFactorySingleton()->Get(client_id);
- if (!cache.get())
- return;
-
- cache->set_shader_loaded_callback(base::Bind(&GpuProcessHost::LoadedShader,
- weak_ptr_factory_.GetWeakPtr()));
-
- client_id_to_shader_cache_[client_id] = cache;
+ DCHECK(gpu_host_);
+ return gpu_host_->gpu_service();
}
int GpuProcessHost::GetIDForTesting() const {
diff --git a/chromium/content/browser/gpu/gpu_process_host.h b/chromium/content/browser/gpu/gpu_process_host.h
index 3ca9cf5c561..d79907844e1 100644
--- a/chromium/content/browser/gpu/gpu_process_host.h
+++ b/chromium/content/browser/gpu/gpu_process_host.h
@@ -11,6 +11,7 @@
#include <memory>
#include <set>
#include <string>
+#include <vector>
#include "base/atomicops.h"
#include "base/callback.h"
@@ -21,6 +22,7 @@
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "build/build_config.h"
+#include "components/viz/host/gpu_host_impl.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_child_process_host_delegate.h"
#include "content/public/browser/gpu_data_manager.h"
@@ -36,23 +38,12 @@
#include "services/viz/privileged/interfaces/gl/gpu_host.mojom.h"
#include "services/viz/privileged/interfaces/gl/gpu_service.mojom.h"
#include "services/viz/privileged/interfaces/viz_main.mojom.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/gpu_memory_buffer.h"
#include "url/gurl.h"
namespace base {
class Thread;
}
-namespace gfx {
-struct FontRenderParams;
-}
-
-namespace gpu {
-class ShaderDiskCache;
-struct SyncToken;
-}
-
namespace content {
class BrowserChildProcessHostImpl;
@@ -62,7 +53,7 @@ class CATransactionGPUCoordinator;
class GpuProcessHost : public BrowserChildProcessHostDelegate,
public IPC::Sender,
- public viz::mojom::GpuHost {
+ public viz::GpuHostImpl::Delegate {
public:
enum GpuProcessKind {
GPU_PROCESS_KIND_UNSANDBOXED,
@@ -70,31 +61,6 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
GPU_PROCESS_KIND_COUNT
};
- enum class EstablishChannelStatus {
- GPU_ACCESS_DENIED, // GPU access was not allowed.
- GPU_HOST_INVALID, // Request failed because the gpu host became invalid
- // while processing the request (e.g. the gpu process
- // may have been killed). The caller should normally
- // make another request to establish a new channel.
- SUCCESS
- };
- using EstablishChannelCallback =
- base::Callback<void(mojo::ScopedMessagePipeHandle channel_handle,
- const gpu::GPUInfo&,
- const gpu::GpuFeatureInfo&,
- EstablishChannelStatus status)>;
-
- enum class BufferCreationStatus {
- GPU_HOST_INVALID,
- SUCCESS,
- };
- using CreateGpuMemoryBufferCallback =
- base::OnceCallback<void(gfx::GpuMemoryBufferHandle handle,
- BufferCreationStatus status)>;
-
- using RequestGPUInfoCallback = base::Callback<void(const gpu::GPUInfo&)>;
- using RequestHDRStatusCallback = base::RepeatingCallback<void(bool)>;
-
static int GetGpuCrashCount();
// Creates a new GpuProcessHost (if |force_create| is turned on) or gets an
@@ -119,52 +85,21 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
bool force_create,
const base::Callback<void(GpuProcessHost*)>& callback);
- static void InitFontRenderParamsOnIO(const gfx::FontRenderParams& params);
-
void BindInterface(const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe);
+ void TerminateGpuProcess(const std::string& message);
// Get the GPU process host for the GPU process with the given ID. Returns
// null if the process no longer exists.
static GpuProcessHost* FromID(int host_id);
int host_id() const { return host_id_; }
+ base::ProcessId process_id() const { return process_id_; }
// IPC::Sender implementation.
bool Send(IPC::Message* msg) override;
- // Tells the GPU process to create a new channel for communication with a
- // client. Once the GPU process responds asynchronously with the IPC handle
- // and GPUInfo, we call the callback.
- void EstablishGpuChannel(int client_id,
- uint64_t client_tracing_id,
- bool preempts,
- bool allow_view_command_buffers,
- bool allow_real_time_streams,
- const EstablishChannelCallback& callback);
-
- // Tells the GPU process to create a new GPU memory buffer.
- void CreateGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- int client_id,
- gpu::SurfaceHandle surface_handle,
- CreateGpuMemoryBufferCallback callback);
-
- // Tells the GPU process to destroy GPU memory buffer.
- void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
- int client_id,
- const gpu::SyncToken& sync_token);
-
- // Connects to FrameSinkManager running in the viz process. In this
- // configuration the display compositor runs in the viz process and the
- // browser must submit CompositorFrames over IPC.
- void ConnectFrameSinkManager(
- viz::mojom::FrameSinkManagerRequest request,
- viz::mojom::FrameSinkManagerClientPtrInfo client);
-
- void RequestGPUInfo(RequestGPUInfoCallback request_cb);
- void RequestHDRStatus(RequestHDRStatusCallback request_cb);
+ // Adds a connection error handler for the GpuService.
+ void AddConnectionErrorHandler(base::OnceClosure handler);
// What kind of GPU process, e.g. sandboxed or unsandboxed.
GpuProcessKind kind();
@@ -172,20 +107,20 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
// Forcefully terminates the GPU process.
void ForceShutdown();
- void LoadedShader(const std::string& key, const std::string& data);
-
CONTENT_EXPORT viz::mojom::GpuService* gpu_service();
- bool wake_up_gpu_before_drawing() const {
- return wake_up_gpu_before_drawing_;
- }
-
CONTENT_EXPORT int GetIDForTesting() const;
+ viz::GpuHostImpl* gpu_host() { return gpu_host_.get(); }
+
private:
class ConnectionFilterImpl;
- enum GpuInitializationStatus { UNKNOWN, SUCCESS, FAILURE };
+ enum class GpuTerminationOrigin {
+ kUnknownOrigin = 0,
+ kOzoneWaylandProxy = 1,
+ kMax = 2,
+ };
static bool ValidateHost(GpuProcessHost* host);
@@ -210,8 +145,10 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
void OnProcessLaunchFailed(int error_code) override;
void OnProcessCrashed(int exit_code) override;
- // viz::mojom::GpuHost:
- void DidInitialize(
+ // viz::GpuHostImpl::Delegate:
+ gpu::GPUInfo GetGPUInfo() const override;
+ gpu::GpuFeatureInfo GetGpuFeatureInfo() const override;
+ void UpdateGpuInfo(
const gpu::GPUInfo& gpu_info,
const gpu::GpuFeatureInfo& gpu_feature_info,
const base::Optional<gpu::GPUInfo>& gpu_info_for_hardware_gpu,
@@ -219,26 +156,17 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
gpu_feature_info_for_hardware_gpu) override;
void DidFailInitialize() override;
void DidCreateContextSuccessfully() override;
- void DidCreateOffscreenContext(const GURL& url) override;
- void DidDestroyOffscreenContext(const GURL& url) override;
- void DidDestroyChannel(int32_t client_id) override;
- void DidLoseContext(bool offscreen,
- gpu::error::ContextLostReason reason,
- const GURL& active_url) override;
+ void BlockDomainFrom3DAPIs(const GURL& url,
+ Delegate::DomainGuilt guilt) override;
void DisableGpuCompositing() override;
- void SetChildSurface(gpu::SurfaceHandle parent,
- gpu::SurfaceHandle child) override;
- void StoreShaderToDisk(int32_t client_id,
- const std::string& key,
- const std::string& shader) override;
+ bool GpuAccessAllowed() const override;
+ gpu::ShaderCacheFactory* GetShaderCacheFactory() override;
void RecordLogMessage(int32_t severity,
const std::string& header,
const std::string& message) override;
-
- void OnChannelEstablished(int client_id,
- const EstablishChannelCallback& callback,
- mojo::ScopedMessagePipeHandle channel_handle);
- void OnGpuMemoryBufferCreated(gfx::GpuMemoryBufferHandle handle);
+ void BindDiscardableMemoryRequest(
+ discardable_memory::mojom::DiscardableSharedMemoryManagerRequest request)
+ override;
// Message handlers.
#if defined(OS_ANDROID)
@@ -246,36 +174,27 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
#endif
void OnFieldTrialActivated(const std::string& trial_name);
- void CreateChannelCache(int32_t client_id);
-
bool LaunchGpuProcess();
- void SendOutstandingReplies(EstablishChannelStatus failure_status);
-
- void RunRequestGPUInfoCallbacks(const gpu::GPUInfo& gpu_info);
+ void SendOutstandingReplies();
void BlockLiveOffscreenContexts();
// Update GPU crash counters. Disable GPU if crash limit is reached.
void RecordProcessCrash();
- std::string GetShaderPrefixKey();
-
// The serial number of the GpuProcessHost / GpuProcessHostUIShim pair.
int host_id_;
- // These are the channel requests that we have already sent to
- // the GPU process, but haven't heard back about yet.
- base::queue<EstablishChannelCallback> channel_requests_;
+ // GPU process id in case GPU is not in-process.
+ base::ProcessId process_id_ = base::kNullProcessId;
- // The pending create gpu memory buffer requests we need to reply to.
- base::queue<CreateGpuMemoryBufferCallback> create_gpu_memory_buffer_requests_;
+ // List of connection error handlers for the GpuService.
+ std::vector<base::OnceClosure> connection_error_handlers_;
// A callback to signal the completion of a SendDestroyingVideoSurface call.
base::Closure send_destroying_video_surface_done_cb_;
- std::vector<RequestGPUInfoCallback> request_gpu_info_callbacks_;
-
// Qeueud messages to send when the process launches.
base::queue<IPC::Message*> queued_messages_;
@@ -293,7 +212,8 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
// Whether we actually launched a GPU process.
bool process_launched_;
- GpuInitializationStatus status_;
+ GpuTerminationOrigin termination_origin_ =
+ GpuTerminationOrigin::kUnknownOrigin;
// Time Init started. Used to log total GPU process startup time to UMA.
base::TimeTicks init_start_time_;
@@ -323,22 +243,7 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
// automatic execution of 3D content from those domains.
std::multiset<GURL> urls_with_live_offscreen_contexts_;
- typedef std::map<int32_t, scoped_refptr<gpu::ShaderDiskCache>>
- ClientIdToShaderCacheMap;
- ClientIdToShaderCacheMap client_id_to_shader_cache_;
-
- std::string shader_prefix_key_;
-
- // The following are a list of driver bug workarounds that will only be
- // set to true in DidInitialize(), where GPU process has started and GPU
- // driver bug workarounds have been computed and sent back.
- bool wake_up_gpu_before_drawing_ = false;
- bool dont_disable_webgl_when_compositor_context_lost_ = false;
-
- viz::mojom::VizMainAssociatedPtr gpu_main_ptr_;
- viz::mojom::GpuServicePtr gpu_service_ptr_;
- mojo::Binding<viz::mojom::GpuHost> gpu_host_binding_;
- gpu::GpuProcessHostActivityFlags activity_flags_;
+ std::unique_ptr<viz::GpuHostImpl> gpu_host_;
SEQUENCE_CHECKER(sequence_checker_);
diff --git a/chromium/content/browser/histogram_controller.cc b/chromium/content/browser/histogram_controller.cc
index 100d8863f89..7d1c1108bb7 100644
--- a/chromium/content/browser/histogram_controller.cc
+++ b/chromium/content/browser/histogram_controller.cc
@@ -153,7 +153,7 @@ void HistogramController::GetHistogramDataFromChildProcesses(
// example, the GPU process may not exist and there may instead just be a
// GPU thread in the browser process). If that's the case, then the process
// handle will be base::kNullProcessHandle and we shouldn't ask it for data.
- if (data.handle == base::kNullProcessHandle)
+ if (!data.IsHandleValid())
continue;
if (auto* child_histogram_fetcher =
diff --git a/chromium/content/browser/hyphenation/hyphenation_impl.cc b/chromium/content/browser/hyphenation/hyphenation_impl.cc
index ab21104f132..8d2cb168722 100644
--- a/chromium/content/browser/hyphenation/hyphenation_impl.cc
+++ b/chromium/content/browser/hyphenation/hyphenation_impl.cc
@@ -13,7 +13,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/timer/elapsed_timer.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
diff --git a/chromium/content/browser/indexed_db/OWNERS b/chromium/content/browser/indexed_db/OWNERS
index 5a42cf0e75b..2d25ec207c3 100644
--- a/chromium/content/browser/indexed_db/OWNERS
+++ b/chromium/content/browser/indexed_db/OWNERS
@@ -1,6 +1,7 @@
jsbell@chromium.org
cmumford@chromium.org
dmurph@chromium.org
+pwnall@chromium.org
# TEAM: storage-dev@chromium.org
# COMPONENT: Blink>Storage>IndexedDB
diff --git a/chromium/content/browser/indexed_db/cursor_impl.cc b/chromium/content/browser/indexed_db/cursor_impl.cc
index 6506a21219b..536d59b22cb 100644
--- a/chromium/content/browser/indexed_db/cursor_impl.cc
+++ b/chromium/content/browser/indexed_db/cursor_impl.cc
@@ -9,6 +9,8 @@
#include "content/browser/indexed_db/indexed_db_cursor.h"
#include "content/browser/indexed_db/indexed_db_dispatcher_host.h"
+using blink::IndexedDBKey;
+
namespace content {
// Expected to be constructed on IO thread, and used/destroyed on IDB sequence.
@@ -45,7 +47,7 @@ CursorImpl::~CursorImpl() {
void CursorImpl::Advance(
uint32_t count,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks_info) {
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info) {
scoped_refptr<IndexedDBCallbacks> callbacks(
new IndexedDBCallbacks(dispatcher_host_->AsWeakPtr(), origin_,
std::move(callbacks_info), idb_runner_));
@@ -54,10 +56,10 @@ void CursorImpl::Advance(
count, std::move(callbacks)));
}
-void CursorImpl::Continue(
+void CursorImpl::CursorContinue(
const IndexedDBKey& key,
const IndexedDBKey& primary_key,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks_info) {
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info) {
scoped_refptr<IndexedDBCallbacks> callbacks(
new IndexedDBCallbacks(dispatcher_host_->AsWeakPtr(), origin_,
std::move(callbacks_info), idb_runner_));
@@ -69,7 +71,7 @@ void CursorImpl::Continue(
void CursorImpl::Prefetch(
int32_t count,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks_info) {
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info) {
scoped_refptr<IndexedDBCallbacks> callbacks(
new IndexedDBCallbacks(dispatcher_host_->AsWeakPtr(), origin_,
std::move(callbacks_info), idb_runner_));
diff --git a/chromium/content/browser/indexed_db/cursor_impl.h b/chromium/content/browser/indexed_db/cursor_impl.h
index 99f831d0a57..bb661af379b 100644
--- a/chromium/content/browser/indexed_db/cursor_impl.h
+++ b/chromium/content/browser/indexed_db/cursor_impl.h
@@ -8,7 +8,8 @@
#include <memory>
#include "base/memory/ref_counted.h"
-#include "content/common/indexed_db/indexed_db.mojom.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
namespace base {
class SequencedTaskRunner;
@@ -18,10 +19,9 @@ namespace content {
class IndexedDBCursor;
class IndexedDBDispatcherHost;
-class IndexedDBKey;
// Expected to be constructed, called, and destructed on the IO thread.
-class CursorImpl : public ::indexed_db::mojom::Cursor {
+class CursorImpl : public blink::mojom::IDBCursor {
public:
CursorImpl(std::unique_ptr<IndexedDBCursor> cursor,
const url::Origin& origin,
@@ -29,17 +29,15 @@ class CursorImpl : public ::indexed_db::mojom::Cursor {
scoped_refptr<base::SequencedTaskRunner> idb_runner);
~CursorImpl() override;
- // ::indexed_db::mojom::Cursor implementation
- void Advance(
- uint32_t count,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks) override;
- void Continue(
- const IndexedDBKey& key,
- const IndexedDBKey& primary_key,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks) override;
- void Prefetch(
- int32_t count,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks) override;
+ // blink::mojom::IDBCursor implementation
+ void Advance(uint32_t count,
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks) override;
+ void CursorContinue(
+ const blink::IndexedDBKey& key,
+ const blink::IndexedDBKey& primary_key,
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks) override;
+ void Prefetch(int32_t count,
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks) override;
void PrefetchReset(int32_t used_prefetches,
int32_t unused_prefetches) override;
diff --git a/chromium/content/browser/indexed_db/database_impl.cc b/chromium/content/browser/indexed_db/database_impl.cc
index 9c305053f7d..20acdb148b9 100644
--- a/chromium/content/browser/indexed_db/database_impl.cc
+++ b/chromium/content/browser/indexed_db/database_impl.cc
@@ -21,8 +21,16 @@
#include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_exception.h"
+using blink::IndexedDBIndexKeys;
+using blink::IndexedDBKey;
+using blink::IndexedDBKeyPath;
+using blink::IndexedDBKeyRange;
using std::swap;
+namespace blink {
+class IndexedDBKeyRange;
+}
+
namespace content {
class IndexedDBDatabaseError;
@@ -77,8 +85,7 @@ class DatabaseImpl::IDBSequenceHelper {
scoped_refptr<IndexedDBCallbacks> callbacks);
void Put(int64_t transaction_id,
int64_t object_store_id,
- ::indexed_db::mojom::ValuePtr value,
- std::vector<std::unique_ptr<storage::BlobDataHandle>> handles,
+ blink::mojom::IDBValuePtr value,
std::vector<IndexedDBBlobInfo> blob_info,
const IndexedDBKey& key,
blink::WebIDBPutMode mode,
@@ -237,7 +244,7 @@ void DatabaseImpl::Get(
int64_t index_id,
const IndexedDBKeyRange& key_range,
bool key_only,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks_info) {
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info) {
scoped_refptr<IndexedDBCallbacks> callbacks(
new IndexedDBCallbacks(dispatcher_host_->AsWeakPtr(), origin_,
std::move(callbacks_info), idb_runner_));
@@ -255,7 +262,7 @@ void DatabaseImpl::GetAll(
const IndexedDBKeyRange& key_range,
bool key_only,
int64_t max_count,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks_info) {
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info) {
scoped_refptr<IndexedDBCallbacks> callbacks(
new IndexedDBCallbacks(dispatcher_host_->AsWeakPtr(), origin_,
std::move(callbacks_info), idb_runner_));
@@ -269,11 +276,11 @@ void DatabaseImpl::GetAll(
void DatabaseImpl::Put(
int64_t transaction_id,
int64_t object_store_id,
- ::indexed_db::mojom::ValuePtr value,
+ blink::mojom::IDBValuePtr value,
const IndexedDBKey& key,
blink::WebIDBPutMode mode,
const std::vector<IndexedDBIndexKeys>& index_keys,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks_info) {
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info) {
ChildProcessSecurityPolicyImpl* policy =
ChildProcessSecurityPolicyImpl::GetInstance();
@@ -281,12 +288,10 @@ void DatabaseImpl::Put(
new IndexedDBCallbacks(dispatcher_host_->AsWeakPtr(), origin_,
std::move(callbacks_info), idb_runner_));
- std::vector<std::unique_ptr<storage::BlobDataHandle>> handles(
- value->blob_or_file_info.size());
base::CheckedNumeric<uint64_t> total_blob_size = 0;
std::vector<IndexedDBBlobInfo> blob_info(value->blob_or_file_info.size());
for (size_t i = 0; i < value->blob_or_file_info.size(); ++i) {
- ::indexed_db::mojom::BlobInfoPtr& info = value->blob_or_file_info[i];
+ blink::mojom::IDBBlobInfoPtr& info = value->blob_or_file_info[i];
std::unique_ptr<storage::BlobDataHandle> handle =
dispatcher_host_->blob_storage_context()->GetBlobDataFromUUID(
@@ -309,7 +314,6 @@ void DatabaseImpl::Put(
uint64_t size = handle->size();
UMA_HISTOGRAM_MEMORY_KB("Storage.IndexedDB.PutBlobSizeKB", size / 1024ull);
total_blob_size += size;
- handles[i] = std::move(handle);
if (info->file) {
if (!info->file->path.empty() &&
@@ -318,14 +322,15 @@ void DatabaseImpl::Put(
mojo::ReportBadMessage(kInvalidBlobFilePath);
return;
}
- blob_info[i] = IndexedDBBlobInfo(info->uuid, info->file->path,
+ blob_info[i] = IndexedDBBlobInfo(std::move(handle), info->file->path,
info->file->name, info->mime_type);
if (info->size != -1) {
blob_info[i].set_last_modified(info->file->last_modified);
blob_info[i].set_size(info->size);
}
} else {
- blob_info[i] = IndexedDBBlobInfo(info->uuid, info->mime_type, info->size);
+ blob_info[i] =
+ IndexedDBBlobInfo(std::move(handle), info->mime_type, info->size);
}
}
UMA_HISTOGRAM_COUNTS_1000("WebCore.IndexedDB.PutBlobsCount",
@@ -340,8 +345,8 @@ void DatabaseImpl::Put(
FROM_HERE,
base::BindOnce(&IDBSequenceHelper::Put, base::Unretained(helper_),
transaction_id, object_store_id, std::move(value),
- std::move(handles), std::move(blob_info), key, mode,
- index_keys, std::move(callbacks)));
+ std::move(blob_info), key, mode, index_keys,
+ std::move(callbacks)));
}
void DatabaseImpl::SetIndexKeys(
@@ -372,7 +377,7 @@ void DatabaseImpl::OpenCursor(
blink::WebIDBCursorDirection direction,
bool key_only,
blink::WebIDBTaskType task_type,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks_info) {
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info) {
scoped_refptr<IndexedDBCallbacks> callbacks(
new IndexedDBCallbacks(dispatcher_host_->AsWeakPtr(), origin_,
std::move(callbacks_info), idb_runner_));
@@ -388,7 +393,7 @@ void DatabaseImpl::Count(
int64_t object_store_id,
int64_t index_id,
const IndexedDBKeyRange& key_range,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks_info) {
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info) {
scoped_refptr<IndexedDBCallbacks> callbacks(
new IndexedDBCallbacks(dispatcher_host_->AsWeakPtr(), origin_,
std::move(callbacks_info), idb_runner_));
@@ -403,7 +408,7 @@ void DatabaseImpl::DeleteRange(
int64_t transaction_id,
int64_t object_store_id,
const IndexedDBKeyRange& key_range,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks_info) {
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info) {
scoped_refptr<IndexedDBCallbacks> callbacks(
new IndexedDBCallbacks(dispatcher_host_->AsWeakPtr(), origin_,
std::move(callbacks_info), idb_runner_));
@@ -417,7 +422,7 @@ void DatabaseImpl::DeleteRange(
void DatabaseImpl::Clear(
int64_t transaction_id,
int64_t object_store_id,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks_info) {
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info) {
scoped_refptr<IndexedDBCallbacks> callbacks(
new IndexedDBCallbacks(dispatcher_host_->AsWeakPtr(), origin_,
std::move(callbacks_info), idb_runner_));
@@ -656,8 +661,7 @@ void DatabaseImpl::IDBSequenceHelper::GetAll(
void DatabaseImpl::IDBSequenceHelper::Put(
int64_t transaction_id,
int64_t object_store_id,
- ::indexed_db::mojom::ValuePtr mojo_value,
- std::vector<std::unique_ptr<storage::BlobDataHandle>> handles,
+ blink::mojom::IDBValuePtr mojo_value,
std::vector<IndexedDBBlobInfo> blob_info,
const IndexedDBKey& key,
blink::WebIDBPutMode mode,
@@ -681,7 +685,7 @@ void DatabaseImpl::IDBSequenceHelper::Put(
IndexedDBValue value;
swap(value.bits, mojo_value->bits);
swap(value.blob_info, blob_info);
- connection_->database()->Put(transaction, object_store_id, &value, &handles,
+ connection_->database()->Put(transaction, object_store_id, &value,
std::make_unique<IndexedDBKey>(key), mode,
std::move(callbacks), index_keys);
diff --git a/chromium/content/browser/indexed_db/database_impl.h b/chromium/content/browser/indexed_db/database_impl.h
index f0030a604db..2839306e34c 100644
--- a/chromium/content/browser/indexed_db/database_impl.h
+++ b/chromium/content/browser/indexed_db/database_impl.h
@@ -7,19 +7,27 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "content/common/indexed_db/indexed_db.mojom.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key_path.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
+
+using blink::IndexedDBKeyRange;
namespace base {
class SequencedTaskRunner;
}
+namespace blink {
+class IndexedDBKeyRange;
+}
+
namespace content {
class IndexedDBConnection;
class IndexedDBDispatcherHost;
// Expected to be constructed, called, and destructed on the IO thread.
-class DatabaseImpl : public ::indexed_db::mojom::Database {
+class DatabaseImpl : public blink::mojom::IDBDatabase {
public:
explicit DatabaseImpl(std::unique_ptr<IndexedDBConnection> connection,
const url::Origin& origin,
@@ -27,11 +35,11 @@ class DatabaseImpl : public ::indexed_db::mojom::Database {
scoped_refptr<base::SequencedTaskRunner> idb_runner);
~DatabaseImpl() override;
- // ::indexed_db::mojom::Database implementation
+ // blink::mojom::IDBDatabase implementation
void CreateObjectStore(int64_t transaction_id,
int64_t object_store_id,
const base::string16& name,
- const IndexedDBKeyPath& key_path,
+ const blink::IndexedDBKeyPath& key_path,
bool auto_increment) override;
void DeleteObjectStore(int64_t transaction_id,
int64_t object_store_id) override;
@@ -55,26 +63,26 @@ class DatabaseImpl : public ::indexed_db::mojom::Database {
int64_t index_id,
const IndexedDBKeyRange& key_range,
bool key_only,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks) override;
- void GetAll(
- int64_t transaction_id,
- int64_t object_store_id,
- int64_t index_id,
- const IndexedDBKeyRange& key_range,
- bool key_only,
- int64_t max_count,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks) override;
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks) override;
+ void GetAll(int64_t transaction_id,
+ int64_t object_store_id,
+ int64_t index_id,
+ const IndexedDBKeyRange& key_range,
+ bool key_only,
+ int64_t max_count,
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks) override;
void Put(int64_t transaction_id,
int64_t object_store_id,
- ::indexed_db::mojom::ValuePtr value,
- const IndexedDBKey& key,
+ blink::mojom::IDBValuePtr value,
+ const blink::IndexedDBKey& key,
blink::WebIDBPutMode mode,
- const std::vector<IndexedDBIndexKeys>& index_keys,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks) override;
- void SetIndexKeys(int64_t transaction_id,
- int64_t object_store_id,
- const IndexedDBKey& primary_key,
- const std::vector<IndexedDBIndexKeys>& index_keys) override;
+ const std::vector<blink::IndexedDBIndexKeys>& index_keys,
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks) override;
+ void SetIndexKeys(
+ int64_t transaction_id,
+ int64_t object_store_id,
+ const blink::IndexedDBKey& primary_key,
+ const std::vector<blink::IndexedDBIndexKeys>& index_keys) override;
void SetIndexesReady(int64_t transaction_id,
int64_t object_store_id,
const std::vector<int64_t>& index_ids) override;
@@ -86,27 +94,25 @@ class DatabaseImpl : public ::indexed_db::mojom::Database {
blink::WebIDBCursorDirection direction,
bool key_only,
blink::WebIDBTaskType task_type,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks_info) override;
- void Count(
- int64_t transaction_id,
- int64_t object_store_id,
- int64_t index_id,
- const IndexedDBKeyRange& key_range,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks) override;
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info) override;
+ void Count(int64_t transaction_id,
+ int64_t object_store_id,
+ int64_t index_id,
+ const IndexedDBKeyRange& key_range,
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks) override;
void DeleteRange(
int64_t transaction_id,
int64_t object_store_id,
const IndexedDBKeyRange& key_range,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks) override;
- void Clear(
- int64_t transaction_id,
- int64_t object_store_id,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks) override;
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks) override;
+ void Clear(int64_t transaction_id,
+ int64_t object_store_id,
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks) override;
void CreateIndex(int64_t transaction_id,
int64_t object_store_id,
int64_t index_id,
const base::string16& name,
- const IndexedDBKeyPath& key_path,
+ const blink::IndexedDBKeyPath& key_path,
bool unique,
bool multi_entry) override;
void DeleteIndex(int64_t transaction_id,
diff --git a/chromium/content/browser/indexed_db/fake_indexed_db_metadata_coding.cc b/chromium/content/browser/indexed_db/fake_indexed_db_metadata_coding.cc
index 85d68f6f9d3..f96c3311593 100644
--- a/chromium/content/browser/indexed_db/fake_indexed_db_metadata_coding.cc
+++ b/chromium/content/browser/indexed_db/fake_indexed_db_metadata_coding.cc
@@ -3,9 +3,12 @@
// found in the LICENSE file.
#include "content/browser/indexed_db/fake_indexed_db_metadata_coding.h"
-#include "content/common/indexed_db/indexed_db_key_path.h"
-#include "content/common/indexed_db/indexed_db_metadata.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key_path.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_metadata.h"
+using blink::IndexedDBDatabaseMetadata;
+using blink::IndexedDBIndexMetadata;
+using blink::IndexedDBObjectStoreMetadata;
using leveldb::Status;
namespace content {
@@ -62,7 +65,7 @@ leveldb::Status FakeIndexedDBMetadataCoding::CreateObjectStore(
int64_t database_id,
int64_t object_store_id,
base::string16 name,
- IndexedDBKeyPath key_path,
+ blink::IndexedDBKeyPath key_path,
bool auto_increment,
IndexedDBObjectStoreMetadata* metadata) {
metadata->name = std::move(name);
@@ -97,7 +100,7 @@ leveldb::Status FakeIndexedDBMetadataCoding::CreateIndex(
int64_t object_store_id,
int64_t index_id,
base::string16 name,
- IndexedDBKeyPath key_path,
+ blink::IndexedDBKeyPath key_path,
bool is_unique,
bool is_multi_entry,
IndexedDBIndexMetadata* metadata) {
diff --git a/chromium/content/browser/indexed_db/fake_indexed_db_metadata_coding.h b/chromium/content/browser/indexed_db/fake_indexed_db_metadata_coding.h
index 5129fc0f0b8..86033fe4c68 100644
--- a/chromium/content/browser/indexed_db/fake_indexed_db_metadata_coding.h
+++ b/chromium/content/browser/indexed_db/fake_indexed_db_metadata_coding.h
@@ -13,15 +13,18 @@
#include "base/macros.h"
#include "base/strings/string16.h"
#include "content/browser/indexed_db/indexed_db_metadata_coding.h"
-#include "content/common/indexed_db/indexed_db_key_path.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key_path.h"
#include "third_party/leveldatabase/src/include/leveldb/status.h"
+namespace blink {
+struct IndexedDBDatabaseMetadata;
+struct IndexedDBIndexMetadata;
+struct IndexedDBObjectStoreMetadata;
+} // namespace blink
+
namespace content {
class LevelDBDatabase;
class LevelDBTransaction;
-struct IndexedDBDatabaseMetadata;
-struct IndexedDBObjectStoreMetadata;
-struct IndexedDBIndexMetadata;
// A fake implementation of IndexedDBMetadataCoding, for testing.
class FakeIndexedDBMetadataCoding : public IndexedDBMetadataCoding {
@@ -38,18 +41,19 @@ class FakeIndexedDBMetadataCoding : public IndexedDBMetadataCoding {
LevelDBDatabase* db,
const std::string& origin_identifier,
const base::string16& name,
- IndexedDBDatabaseMetadata* metadata,
+ blink::IndexedDBDatabaseMetadata* metadata,
bool* found) override;
- leveldb::Status CreateDatabase(LevelDBDatabase* database,
- const std::string& origin_identifier,
- const base::string16& name,
- int64_t version,
- IndexedDBDatabaseMetadata* metadata) override;
+ leveldb::Status CreateDatabase(
+ LevelDBDatabase* database,
+ const std::string& origin_identifier,
+ const base::string16& name,
+ int64_t version,
+ blink::IndexedDBDatabaseMetadata* metadata) override;
void SetDatabaseVersion(LevelDBTransaction* transaction,
int64_t row_id,
int64_t version,
- IndexedDBDatabaseMetadata* metadata) override;
+ blink::IndexedDBDatabaseMetadata* metadata) override;
leveldb::Status FindDatabaseId(LevelDBDatabase* db,
const std::string& origin_identifier,
@@ -62,43 +66,44 @@ class FakeIndexedDBMetadataCoding : public IndexedDBMetadataCoding {
int64_t database_id,
int64_t object_store_id,
base::string16 name,
- IndexedDBKeyPath key_path,
+ blink::IndexedDBKeyPath key_path,
bool auto_increment,
- IndexedDBObjectStoreMetadata* metadata) override;
+ blink::IndexedDBObjectStoreMetadata* metadata) override;
leveldb::Status RenameObjectStore(
LevelDBTransaction* transaction,
int64_t database_id,
base::string16 new_name,
base::string16* old_name,
- IndexedDBObjectStoreMetadata* metadata) override;
+ blink::IndexedDBObjectStoreMetadata* metadata) override;
leveldb::Status DeleteObjectStore(
LevelDBTransaction* transaction,
int64_t database_id,
- const IndexedDBObjectStoreMetadata& object_store) override;
+ const blink::IndexedDBObjectStoreMetadata& object_store) override;
leveldb::Status CreateIndex(LevelDBTransaction* transaction,
int64_t database_id,
int64_t object_store_id,
int64_t index_id,
base::string16 name,
- IndexedDBKeyPath key_path,
+ blink::IndexedDBKeyPath key_path,
bool is_unique,
bool is_multi_entry,
- IndexedDBIndexMetadata* metadata) override;
+ blink::IndexedDBIndexMetadata* metadata) override;
leveldb::Status RenameIndex(LevelDBTransaction* transaction,
int64_t database_id,
int64_t object_store_id,
base::string16 new_name,
base::string16* old_name,
- IndexedDBIndexMetadata* metadata) override;
+ blink::IndexedDBIndexMetadata* metadata) override;
- leveldb::Status DeleteIndex(LevelDBTransaction* transaction,
- int64_t database_id,
- int64_t object_store_id,
- const IndexedDBIndexMetadata& metadata) override;
+ leveldb::Status DeleteIndex(
+ LevelDBTransaction* transaction,
+ int64_t database_id,
+ int64_t object_store_id,
+ const blink::IndexedDBIndexMetadata& metadata) override;
private:
DISALLOW_COPY_AND_ASSIGN(FakeIndexedDBMetadataCoding);
diff --git a/chromium/content/browser/indexed_db/indexed_db_backing_store.cc b/chromium/content/browser/indexed_db/indexed_db_backing_store.cc
index 8dc3131ee8a..01c03fae5ce 100644
--- a/chromium/content/browser/indexed_db/indexed_db_backing_store.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_backing_store.cc
@@ -38,9 +38,6 @@
#include "content/browser/indexed_db/leveldb/leveldb_factory.h"
#include "content/browser/indexed_db/leveldb/leveldb_iterator.h"
#include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
-#include "content/common/indexed_db/indexed_db_key.h"
-#include "content/common/indexed_db/indexed_db_key_path.h"
-#include "content/common/indexed_db/indexed_db_key_range.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_features.h"
#include "net/base/load_flags.h"
@@ -52,11 +49,15 @@
#include "storage/browser/fileapi/local_file_stream_writer.h"
#include "storage/common/database/database_identifier.h"
#include "storage/common/fileapi/file_system_mount_option.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_types.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key_range.h"
+#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
#include "third_party/leveldatabase/env_chromium.h"
using base::FilePath;
using base::StringPiece;
+using blink::IndexedDBDatabaseMetadata;
+using blink::IndexedDBKey;
+using blink::IndexedDBKeyRange;
using leveldb::Status;
using storage::FileWriterDelegate;
using url::Origin;
@@ -366,10 +367,6 @@ bool IsPathTooLong(const FilePath& leveldb_dir) {
return false;
}
-GURL GetURLFromUUID(const std::string& uuid) {
- return GURL("blob:uuid/" + uuid);
-}
-
Status DeleteBlobsInRange(IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
@@ -390,8 +387,7 @@ Status DeleteBlobsInRange(IndexedDBBackingStore::Transaction* transaction,
INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
return InternalInconsistencyStatus();
}
- transaction->PutBlobInfo(database_id, object_store_id, user_key, nullptr,
- nullptr);
+ transaction->PutBlobInfo(database_id, object_store_id, user_key, nullptr);
}
return s;
}
@@ -693,6 +689,19 @@ Status IndexedDBBackingStore::AnyDatabaseContainsBlobs(
return Status::OK();
}
+Status IndexedDBBackingStore::RevertSchemaToV2() {
+ DCHECK(task_runner_->RunsTasksInCurrentSequence());
+ const std::string schema_version_key = SchemaVersionKey::Encode();
+ scoped_refptr<LevelDBTransaction> transaction =
+ IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get());
+
+ PutInt(transaction.get(), schema_version_key, 2);
+ Status s = transaction->Commit();
+ if (!s.ok())
+ INTERNAL_WRITE_ERROR_UNTESTED(REVERT_SCHEMA_TO_V2);
+ return s;
+}
+
WARN_UNUSED_RESULT Status IndexedDBBackingStore::SetUpMetadata() {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
@@ -1288,7 +1297,6 @@ Status IndexedDBBackingStore::PutRecord(
int64_t object_store_id,
const IndexedDBKey& key,
IndexedDBValue* value,
- std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles,
RecordIdentifier* record_identifier) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
@@ -1312,14 +1320,10 @@ Status IndexedDBBackingStore::PutRecord(
v.append(value->bits);
leveldb_transaction->Put(object_store_data_key, &v);
- s = transaction->PutBlobInfoIfNeeded(database_id,
- object_store_id,
- object_store_data_key,
- &value->blob_info,
- handles);
+ s = transaction->PutBlobInfoIfNeeded(
+ database_id, object_store_id, object_store_data_key, &value->blob_info);
if (!s.ok())
return s;
- DCHECK(handles->empty());
const std::string exists_entry_key =
ExistsEntryKey::Encode(database_id, object_store_id, key);
@@ -1369,8 +1373,8 @@ Status IndexedDBBackingStore::DeleteRecord(
const std::string object_store_data_key = ObjectStoreDataKey::Encode(
database_id, object_store_id, record_identifier.primary_key());
leveldb_transaction->Remove(object_store_data_key);
- Status s = transaction->PutBlobInfoIfNeeded(
- database_id, object_store_id, object_store_data_key, nullptr, nullptr);
+ Status s = transaction->PutBlobInfoIfNeeded(database_id, object_store_id,
+ object_store_data_key, nullptr);
if (!s.ok())
return s;
@@ -1574,20 +1578,19 @@ class IndexedDBBackingStore::Transaction::ChainedBlobWriterImpl
public:
typedef IndexedDBBackingStore::Transaction::WriteDescriptorVec
WriteDescriptorVec;
- ChainedBlobWriterImpl(
+ static scoped_refptr<ChainedBlobWriterImpl> Create(
int64_t database_id,
IndexedDBBackingStore* backing_store,
WriteDescriptorVec* blobs,
- scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback)
- : waiting_for_callback_(false),
- database_id_(database_id),
- backing_store_(backing_store),
- callback_(callback),
- aborted_(false) {
- blobs_.swap(*blobs);
- iter_ = blobs_.begin();
+ scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback) {
+ auto writer = base::WrapRefCounted(new ChainedBlobWriterImpl(
+ database_id, backing_store, std::move(callback)));
+ writer->blobs_.swap(*blobs);
+ writer->iter_ = writer->blobs_.begin();
backing_store->task_runner()->PostTask(
- FROM_HERE, base::BindOnce(&ChainedBlobWriterImpl::WriteNextFile, this));
+ FROM_HERE,
+ base::BindOnce(&ChainedBlobWriterImpl::WriteNextFile, writer));
+ return writer;
}
void set_delegate(std::unique_ptr<FileWriterDelegate> delegate) override {
@@ -1623,6 +1626,15 @@ class IndexedDBBackingStore::Transaction::ChainedBlobWriterImpl
}
private:
+ ChainedBlobWriterImpl(
+ int64_t database_id,
+ IndexedDBBackingStore* backing_store,
+ scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback)
+ : waiting_for_callback_(false),
+ database_id_(database_id),
+ backing_store_(backing_store),
+ callback_(callback),
+ aborted_(false) {}
~ChainedBlobWriterImpl() override {}
void WriteNextFile() {
@@ -1702,11 +1714,9 @@ class LocalWriteClosure : public FileWriterDelegate::DelegateWriteCallback,
}
}
- void WriteBlobToFileOnIOThread(
- const FilePath& file_path,
- const GURL& blob_url,
- const base::Time& last_modified,
- scoped_refptr<net::URLRequestContextGetter> request_context_getter) {
+ void WriteBlobToFileOnIOThread(const FilePath& file_path,
+ std::unique_ptr<storage::BlobDataHandle> blob,
+ const base::Time& last_modified) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
std::unique_ptr<storage::FileStreamWriter> writer(
storage::FileStreamWriter::CreateForLocalFile(
@@ -1716,43 +1726,11 @@ class LocalWriteClosure : public FileWriterDelegate::DelegateWriteCallback,
std::make_unique<FileWriterDelegate>(
std::move(writer), storage::FlushPolicy::FLUSH_ON_COMPLETION));
- DCHECK(blob_url.is_valid());
- net::URLRequestContext* request_context =
- request_context_getter->GetURLRequestContext();
- net::NetworkTrafficAnnotationTag traffic_annotation =
- net::DefineNetworkTrafficAnnotation("persist_blob_to_indexed_db", R"(
- semantics {
- sender: "Indexed DB"
- description:
- "A web page's script has created a Blob (or File) object (either "
- "directly via constructors, or by using file upload to a form, or "
- "via a fetch()). The script has then made a request to store data "
- "including the Blob via the Indexed DB API. As part of committing "
- "the database transaction, the content of the Blob is being copied "
- "into a file in the database's directory."
- trigger:
- "The script has made a request to store data including a Blob via "
- "the Indexed DB API."
- data:
- "A Blob or File object referenced by script, either created "
- "directly via constructors, or by using file upload to a form, or "
- "drag/drop, or via a fetch() or other APIs that produce Blobs."
- destination: LOCAL
- }
- policy {
- cookies_allowed: NO
- setting: "This feature cannot be disabled by settings."
- policy_exception_justification: "Not implemented."
- })");
- std::unique_ptr<net::URLRequest> blob_request(
- request_context->CreateRequest(blob_url, net::DEFAULT_PRIORITY,
- delegate.get(), traffic_annotation));
- blob_request->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
- net::LOAD_DO_NOT_SEND_COOKIES);
+ DCHECK(blob);
this->file_path_ = file_path;
this->last_modified_ = last_modified;
- delegate->Start(std::move(blob_request),
+ delegate->Start(blob->CreateReader(),
base::Bind(&LocalWriteClosure::Run, this));
chained_blob_writer_->set_delegate(std::move(delegate));
}
@@ -1841,14 +1819,15 @@ bool IndexedDBBackingStore::WriteBlobFile(
base::BindOnce(&Transaction::ChainedBlobWriter::ReportWriteCompletion,
chained_blob_writer, true, info.size));
} else {
- DCHECK(descriptor.url().is_valid());
+ DCHECK(descriptor.blob());
scoped_refptr<LocalWriteClosure> write_closure(
new LocalWriteClosure(chained_blob_writer, task_runner_.get()));
content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE,
- base::BindOnce(&LocalWriteClosure::WriteBlobToFileOnIOThread,
- write_closure, path, descriptor.url(),
- descriptor.last_modified(), request_context_getter_));
+ base::BindOnce(
+ &LocalWriteClosure::WriteBlobToFileOnIOThread, write_closure, path,
+ std::make_unique<storage::BlobDataHandle>(*descriptor.blob()),
+ descriptor.last_modified()));
}
return true;
}
@@ -3131,8 +3110,8 @@ Status IndexedDBBackingStore::Transaction::HandleBlobPreTransaction(
entry.last_modified()));
} else {
new_files_to_write->push_back(
- WriteDescriptor(GetURLFromUUID(entry.uuid()), next_blob_key,
- entry.size(), entry.last_modified()));
+ WriteDescriptor(entry.blob_handle(), next_blob_key, entry.size(),
+ entry.last_modified()));
}
entry.set_key(next_blob_key);
new_blob_keys.push_back(&entry);
@@ -3404,7 +3383,7 @@ void IndexedDBBackingStore::Transaction::WriteNewBlobs(
}
// Creating the writer will start it going asynchronously. The transaction
// can be destructed before the callback is triggered.
- chained_blob_writer_ = new ChainedBlobWriterImpl(
+ chained_blob_writer_ = ChainedBlobWriterImpl::Create(
database_id_, backing_store_, new_files_to_write,
new BlobWriteCallbackWrapper(ptr_factory_.GetWeakPtr(), this, callback));
}
@@ -3446,23 +3425,12 @@ void IndexedDBBackingStore::BlobChangeRecord::SetBlobInfo(
blob_info_.swap(*blob_info);
}
-void IndexedDBBackingStore::BlobChangeRecord::SetHandles(
- std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles) {
- handles_.clear();
- if (handles)
- handles_.swap(*handles);
-}
-
std::unique_ptr<IndexedDBBackingStore::BlobChangeRecord>
IndexedDBBackingStore::BlobChangeRecord::Clone() const {
std::unique_ptr<IndexedDBBackingStore::BlobChangeRecord> record(
new BlobChangeRecord(key_, object_store_id_));
record->blob_info_ = blob_info_;
- for (const auto& handle : handles_) {
- record->handles_.push_back(
- std::make_unique<storage::BlobDataHandle>(*handle));
- }
return record;
}
@@ -3470,8 +3438,7 @@ Status IndexedDBBackingStore::Transaction::PutBlobInfoIfNeeded(
int64_t database_id,
int64_t object_store_id,
const std::string& object_store_data_key,
- std::vector<IndexedDBBlobInfo>* blob_info,
- std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles) {
+ std::vector<IndexedDBBlobInfo>* blob_info) {
if (!blob_info || blob_info->empty()) {
blob_change_map_.erase(object_store_data_key);
incognito_blob_map_.erase(object_store_data_key);
@@ -3491,8 +3458,7 @@ Status IndexedDBBackingStore::Transaction::PutBlobInfoIfNeeded(
if (!found)
return Status::OK();
}
- PutBlobInfo(
- database_id, object_store_id, object_store_data_key, blob_info, handles);
+ PutBlobInfo(database_id, object_store_id, object_store_data_key, blob_info);
return Status::OK();
}
@@ -3504,8 +3470,7 @@ void IndexedDBBackingStore::Transaction::PutBlobInfo(
int64_t database_id,
int64_t object_store_id,
const std::string& object_store_data_key,
- std::vector<IndexedDBBlobInfo>* blob_info,
- std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles) {
+ std::vector<IndexedDBBlobInfo>* blob_info) {
DCHECK(!object_store_data_key.empty());
if (database_id_ < 0)
database_id_ = database_id;
@@ -3524,21 +3489,18 @@ void IndexedDBBackingStore::Transaction::PutBlobInfo(
}
DCHECK_EQ(record->object_store_id(), object_store_id);
record->SetBlobInfo(blob_info);
- record->SetHandles(handles);
- DCHECK(!handles || handles->empty());
}
IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor(
- const GURL& url,
+ const storage::BlobDataHandle* blob,
int64_t key,
int64_t size,
base::Time last_modified)
: is_file_(false),
- url_(url),
+ blob_(*blob),
key_(key),
size_(size),
- last_modified_(last_modified) {
-}
+ last_modified_(last_modified) {}
IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor(
const FilePath& file_path,
@@ -3557,7 +3519,7 @@ IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor(
IndexedDBBackingStore::Transaction::WriteDescriptor::~WriteDescriptor() =
default;
IndexedDBBackingStore::Transaction::WriteDescriptor&
- IndexedDBBackingStore::Transaction::WriteDescriptor::
- operator=(const WriteDescriptor& other) = default;
+IndexedDBBackingStore::Transaction::WriteDescriptor::operator=(
+ const WriteDescriptor& other) = default;
} // namespace content
diff --git a/chromium/content/browser/indexed_db/indexed_db_backing_store.h b/chromium/content/browser/indexed_db/indexed_db_backing_store.h
index 4ec52518ce4..e5540a77658 100644
--- a/chromium/content/browser/indexed_db/indexed_db_backing_store.h
+++ b/chromium/content/browser/indexed_db/indexed_db_backing_store.h
@@ -31,11 +31,8 @@
#include "content/browser/indexed_db/leveldb/leveldb_iterator.h"
#include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
#include "content/common/content_export.h"
-#include "content/common/indexed_db/indexed_db_key.h"
-#include "content/common/indexed_db/indexed_db_key_path.h"
-#include "content/common/indexed_db/indexed_db_key_range.h"
-#include "content/common/indexed_db/indexed_db_metadata.h"
#include "storage/browser/blob/blob_data_handle.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
#include "third_party/leveldatabase/src/include/leveldb/status.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -44,6 +41,11 @@ namespace base {
class SequencedTaskRunner;
}
+namespace blink {
+class IndexedDBKeyRange;
+struct IndexedDBDatabaseMetadata;
+} // namespace blink
+
namespace storage {
class FileWriterDelegate;
}
@@ -122,15 +124,12 @@ class CONTENT_EXPORT IndexedDBBackingStore
const std::vector<IndexedDBBlobInfo>& blob_info() const {
return blob_info_;
}
- void SetHandles(
- std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles);
std::unique_ptr<BlobChangeRecord> Clone() const;
private:
std::string key_;
int64_t object_store_id_;
std::vector<IndexedDBBlobInfo> blob_info_;
- std::vector<std::unique_ptr<storage::BlobDataHandle>> handles_;
DISALLOW_COPY_AND_ASSIGN(BlobChangeRecord);
};
@@ -164,14 +163,11 @@ class CONTENT_EXPORT IndexedDBBackingStore
int64_t database_id,
int64_t object_store_id,
const std::string& object_store_data_key,
- std::vector<IndexedDBBlobInfo>*,
- std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles);
- void PutBlobInfo(
- int64_t database_id,
- int64_t object_store_id,
- const std::string& object_store_data_key,
- std::vector<IndexedDBBlobInfo>*,
- std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles);
+ std::vector<IndexedDBBlobInfo>*);
+ void PutBlobInfo(int64_t database_id,
+ int64_t object_store_id,
+ const std::string& object_store_data_key,
+ std::vector<IndexedDBBlobInfo>*);
LevelDBTransaction* transaction() { return transaction_.get(); }
@@ -189,7 +185,7 @@ class CONTENT_EXPORT IndexedDBBackingStore
class CONTENT_EXPORT WriteDescriptor {
public:
- WriteDescriptor(const GURL& url,
+ WriteDescriptor(const storage::BlobDataHandle* blob,
int64_t key,
int64_t size,
base::Time last_modified);
@@ -202,9 +198,9 @@ class CONTENT_EXPORT IndexedDBBackingStore
WriteDescriptor& operator=(const WriteDescriptor& other);
bool is_file() const { return is_file_; }
- const GURL& url() const {
+ const storage::BlobDataHandle* blob() const {
DCHECK(!is_file_);
- return url_;
+ return &blob_.value();
}
const base::FilePath& file_path() const {
DCHECK(is_file_);
@@ -216,7 +212,7 @@ class CONTENT_EXPORT IndexedDBBackingStore
private:
bool is_file_;
- GURL url_;
+ base::Optional<storage::BlobDataHandle> blob_;
base::FilePath file_path_;
int64_t key_;
int64_t size_;
@@ -321,22 +317,22 @@ class CONTENT_EXPORT IndexedDBBackingStore
bool unique;
};
- const IndexedDBKey& key() const { return *current_key_; }
+ const blink::IndexedDBKey& key() const { return *current_key_; }
bool Continue(leveldb::Status* s) { return Continue(NULL, NULL, SEEK, s); }
- bool Continue(const IndexedDBKey* key,
+ bool Continue(const blink::IndexedDBKey* key,
IteratorState state,
leveldb::Status* s) {
return Continue(key, NULL, state, s);
}
- bool Continue(const IndexedDBKey* key,
- const IndexedDBKey* primary_key,
+ bool Continue(const blink::IndexedDBKey* key,
+ const blink::IndexedDBKey* primary_key,
IteratorState state,
leveldb::Status*);
bool Advance(uint32_t count, leveldb::Status*);
bool FirstSeek(leveldb::Status*);
virtual std::unique_ptr<Cursor> Clone() const = 0;
- virtual const IndexedDBKey& primary_key() const;
+ virtual const blink::IndexedDBKey& primary_key() const;
virtual IndexedDBValue* value() = 0;
virtual const RecordIdentifier& record_identifier() const;
virtual bool LoadCurrentRow(leveldb::Status* s) = 0;
@@ -348,9 +344,9 @@ class CONTENT_EXPORT IndexedDBBackingStore
const CursorOptions& cursor_options);
explicit Cursor(const IndexedDBBackingStore::Cursor* other);
- virtual std::string EncodeKey(const IndexedDBKey& key) = 0;
- virtual std::string EncodeKey(const IndexedDBKey& key,
- const IndexedDBKey& primary_key) = 0;
+ virtual std::string EncodeKey(const blink::IndexedDBKey& key) = 0;
+ virtual std::string EncodeKey(const blink::IndexedDBKey& key,
+ const blink::IndexedDBKey& primary_key) = 0;
bool IsPastBounds() const;
bool HaveEnteredRange() const;
@@ -360,22 +356,22 @@ class CONTENT_EXPORT IndexedDBBackingStore
int64_t database_id_;
const CursorOptions cursor_options_;
std::unique_ptr<LevelDBIterator> iterator_;
- std::unique_ptr<IndexedDBKey> current_key_;
+ std::unique_ptr<blink::IndexedDBKey> current_key_;
IndexedDBBackingStore::RecordIdentifier record_identifier_;
private:
enum class ContinueResult { LEVELDB_ERROR, DONE, OUT_OF_BOUNDS };
// For cursors with direction Next or NextNoDuplicate.
- ContinueResult ContinueNext(const IndexedDBKey* key,
- const IndexedDBKey* primary_key,
+ ContinueResult ContinueNext(const blink::IndexedDBKey* key,
+ const blink::IndexedDBKey* primary_key,
IteratorState state,
leveldb::Status*);
// For cursors with direction Prev or PrevNoDuplicate. The PrevNoDuplicate
// case has additional complexity of not being symmetric with
// NextNoDuplicate.
- ContinueResult ContinuePrevious(const IndexedDBKey* key,
- const IndexedDBKey* primary_key,
+ ContinueResult ContinuePrevious(const blink::IndexedDBKey* key,
+ const blink::IndexedDBKey* primary_key,
IteratorState state,
leveldb::Status*);
@@ -448,15 +444,14 @@ class CONTENT_EXPORT IndexedDBBackingStore
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
- const IndexedDBKey& key,
+ const blink::IndexedDBKey& key,
IndexedDBValue* record) WARN_UNUSED_RESULT;
virtual leveldb::Status PutRecord(
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
- const IndexedDBKey& key,
+ const blink::IndexedDBKey& key,
IndexedDBValue* value,
- std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles,
RecordIdentifier* record) WARN_UNUSED_RESULT;
virtual leveldb::Status ClearObjectStore(
IndexedDBBackingStore::Transaction* transaction,
@@ -471,7 +466,7 @@ class CONTENT_EXPORT IndexedDBBackingStore
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
- const IndexedDBKeyRange&) WARN_UNUSED_RESULT;
+ const blink::IndexedDBKeyRange&) WARN_UNUSED_RESULT;
virtual leveldb::Status GetKeyGeneratorCurrentNumber(
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
@@ -487,7 +482,7 @@ class CONTENT_EXPORT IndexedDBBackingStore
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
- const IndexedDBKey& key,
+ const blink::IndexedDBKey& key,
RecordIdentifier* found_record_identifier,
bool* found) WARN_UNUSED_RESULT;
@@ -501,22 +496,22 @@ class CONTENT_EXPORT IndexedDBBackingStore
int64_t database_id,
int64_t object_store_id,
int64_t index_id,
- const IndexedDBKey& key,
+ const blink::IndexedDBKey& key,
const RecordIdentifier& record) WARN_UNUSED_RESULT;
virtual leveldb::Status GetPrimaryKeyViaIndex(
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
int64_t index_id,
- const IndexedDBKey& key,
- std::unique_ptr<IndexedDBKey>* primary_key) WARN_UNUSED_RESULT;
+ const blink::IndexedDBKey& key,
+ std::unique_ptr<blink::IndexedDBKey>* primary_key) WARN_UNUSED_RESULT;
virtual leveldb::Status KeyExistsInIndex(
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
int64_t index_id,
- const IndexedDBKey& key,
- std::unique_ptr<IndexedDBKey>* found_primary_key,
+ const blink::IndexedDBKey& key,
+ std::unique_ptr<blink::IndexedDBKey>* found_primary_key,
bool* exists) WARN_UNUSED_RESULT;
// Public for IndexedDBActiveBlobRegistry::ReleaseBlobRef.
@@ -528,14 +523,14 @@ class CONTENT_EXPORT IndexedDBBackingStore
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
- const IndexedDBKeyRange& key_range,
+ const blink::IndexedDBKeyRange& key_range,
blink::WebIDBCursorDirection,
leveldb::Status*);
virtual std::unique_ptr<Cursor> OpenObjectStoreCursor(
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
- const IndexedDBKeyRange& key_range,
+ const blink::IndexedDBKeyRange& key_range,
blink::WebIDBCursorDirection,
leveldb::Status*);
virtual std::unique_ptr<Cursor> OpenIndexKeyCursor(
@@ -543,7 +538,7 @@ class CONTENT_EXPORT IndexedDBBackingStore
int64_t database_id,
int64_t object_store_id,
int64_t index_id,
- const IndexedDBKeyRange& key_range,
+ const blink::IndexedDBKeyRange& key_range,
blink::WebIDBCursorDirection,
leveldb::Status*);
virtual std::unique_ptr<Cursor> OpenIndexCursor(
@@ -551,7 +546,7 @@ class CONTENT_EXPORT IndexedDBBackingStore
int64_t database_id,
int64_t object_store_id,
int64_t index_id,
- const IndexedDBKeyRange& key_range,
+ const blink::IndexedDBKeyRange& key_range,
blink::WebIDBCursorDirection,
leveldb::Status*);
@@ -585,6 +580,11 @@ class CONTENT_EXPORT IndexedDBBackingStore
// Stops the journal_cleaning_timer_ and runs its pending task.
void ForceRunBlobCleanup();
+ // RevertSchemaToV2() updates a backing store state on disk to override its
+ // metadata version to 2. This allows triggering https://crbug.com/829141 on
+ // an otherwise healthy backing store.
+ leveldb::Status RevertSchemaToV2();
+
protected:
friend class base::RefCounted<IndexedDBBackingStore>;
@@ -607,7 +607,7 @@ class CONTENT_EXPORT IndexedDBBackingStore
// TODO(dmurph): Move this completely to IndexedDBMetadataFactory.
leveldb::Status GetCompleteMetadata(
- std::vector<IndexedDBDatabaseMetadata>* output);
+ std::vector<blink::IndexedDBDatabaseMetadata>* output);
virtual bool WriteBlobFile(
int64_t database_id,
@@ -652,7 +652,7 @@ class CONTENT_EXPORT IndexedDBBackingStore
int64_t database_id,
int64_t object_store_id,
int64_t index_id,
- const IndexedDBKey& key,
+ const blink::IndexedDBKey& key,
std::string* found_encoded_primary_key,
bool* found);
diff --git a/chromium/content/browser/indexed_db/indexed_db_backing_store_unittest.cc b/chromium/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
index eaa915e6d42..6eb906e0216 100644
--- a/chromium/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
@@ -11,6 +11,7 @@
#include "base/callback.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/guid.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/sequenced_task_runner.h"
@@ -28,14 +29,22 @@
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_utils.h"
#include "net/url_request/url_request_test_util.h"
+#include "storage/browser/blob/blob_data_builder.h"
#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/blob/blob_storage_context.h"
#include "storage/browser/quota/special_storage_policy.h"
#include "storage/browser/test/mock_quota_manager_proxy.h"
#include "storage/browser/test/mock_special_storage_policy.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_types.h"
+#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
using base::ASCIIToUTF16;
+using blink::IndexedDBDatabaseMetadata;
+using blink::IndexedDBIndexMetadata;
+using blink::IndexedDBKey;
+using blink::IndexedDBKeyPath;
+using blink::IndexedDBKeyRange;
+using blink::IndexedDBObjectStoreMetadata;
using url::Origin;
namespace content {
@@ -330,13 +339,15 @@ class IndexedDBBackingStoreTestWithBlobs : public IndexedDBBackingStoreTest {
void SetUp() override {
IndexedDBBackingStoreTest::SetUp();
+ blob_context_ = std::make_unique<storage::BlobStorageContext>();
+
// useful keys and values during tests
blob_info_.push_back(
- IndexedDBBlobInfo("uuid 3", base::UTF8ToUTF16("blob type"), 1));
+ IndexedDBBlobInfo(CreateBlob(), base::UTF8ToUTF16("blob type"), 1));
blob_info_.push_back(IndexedDBBlobInfo(
- "uuid 4", base::FilePath(FILE_PATH_LITERAL("path/to/file")),
+ CreateBlob(), base::FilePath(FILE_PATH_LITERAL("path/to/file")),
base::UTF8ToUTF16("file name"), base::UTF8ToUTF16("file type")));
- blob_info_.push_back(IndexedDBBlobInfo("uuid 5", base::FilePath(),
+ blob_info_.push_back(IndexedDBBlobInfo(CreateBlob(), base::FilePath(),
base::UTF8ToUTF16("file name"),
base::UTF8ToUTF16("file type")));
value3_ = IndexedDBValue("value3", blob_info_);
@@ -344,6 +355,11 @@ class IndexedDBBackingStoreTestWithBlobs : public IndexedDBBackingStoreTest {
key3_ = IndexedDBKey(ASCIIToUTF16("key3"));
}
+ std::unique_ptr<storage::BlobDataHandle> CreateBlob() {
+ return blob_context_->AddFinishedBlob(
+ std::make_unique<storage::BlobDataBuilder>(base::GenerateGUID()));
+ }
+
// This just checks the data that survive getting stored and recalled, e.g.
// the file path and UUID will change and thus aren't verified.
bool CheckBlobInfoMatches(const std::vector<IndexedDBBlobInfo>& reads) const {
@@ -403,7 +419,7 @@ class IndexedDBBackingStoreTestWithBlobs : public IndexedDBBackingStoreTest {
if (desc.file_path() != info.file_path())
return false;
} else {
- if (desc.url() != GURL("blob:uuid/" + info.uuid()))
+ if (desc.blob()->uuid() != info.blob_handle()->uuid())
return false;
}
}
@@ -428,6 +444,8 @@ class IndexedDBBackingStoreTestWithBlobs : public IndexedDBBackingStoreTest {
IndexedDBValue value3_;
private:
+ std::unique_ptr<storage::BlobStorageContext> blob_context_;
+
// Blob details referenced by |value3_|. The various CheckBlob*() methods
// can be used to verify the state as a test progresses.
std::vector<IndexedDBBlobInfo> blob_info_;
@@ -470,10 +488,9 @@ TEST_F(IndexedDBBackingStoreTest, PutGetConsistency) {
{
IndexedDBBackingStore::Transaction transaction1(backing_store);
transaction1.Begin();
- std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
IndexedDBBackingStore::RecordIdentifier record;
leveldb::Status s = backing_store->PutRecord(
- &transaction1, 1, 1, key, &value, &handles, &record);
+ &transaction1, 1, 1, key, &value, &record);
EXPECT_TRUE(s.ok());
scoped_refptr<TestCallback> callback(
base::MakeRefCounted<TestCallback>());
@@ -521,12 +538,10 @@ TEST_F(IndexedDBBackingStoreTestWithBlobs, PutGetConsistencyWithBlobs) {
std::make_unique<IndexedDBBackingStore::Transaction>(
test->backing_store());
state->transaction1->Begin();
- std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
IndexedDBBackingStore::RecordIdentifier record;
EXPECT_TRUE(test->backing_store()
->PutRecord(state->transaction1.get(), 1, 1,
- test->key3_, &test->value3_, &handles,
- &record)
+ test->key3_, &test->value3_, &record)
.ok());
state->callback1 = base::MakeRefCounted<TestCallback>();
EXPECT_TRUE(
@@ -599,7 +614,7 @@ TEST_F(IndexedDBBackingStoreTestWithBlobs, PutGetConsistencyWithBlobs) {
RunAllTasksUntilIdle();
}
-TEST_F(IndexedDBBackingStoreTest, DeleteRange) {
+TEST_F(IndexedDBBackingStoreTestWithBlobs, DeleteRange) {
const std::vector<IndexedDBKey> keys = {
IndexedDBKey(ASCIIToUTF16("key0")), IndexedDBKey(ASCIIToUTF16("key1")),
IndexedDBKey(ASCIIToUTF16("key2")), IndexedDBKey(ASCIIToUTF16("key3"))};
@@ -620,8 +635,12 @@ TEST_F(IndexedDBBackingStoreTest, DeleteRange) {
scoped_refptr<TestCallback> callback1;
std::unique_ptr<IndexedDBBackingStore::Transaction> transaction2;
scoped_refptr<TestCallback> callback2;
+ std::vector<std::unique_ptr<storage::BlobDataHandle>> blobs;
} state;
+ for (size_t j = 0; j < 4; ++j)
+ state.blobs.push_back(CreateBlob());
+
idb_context_->TaskRunner()->PostTask(
FROM_HERE,
base::BindOnce(
@@ -633,19 +652,26 @@ TEST_F(IndexedDBBackingStoreTest, DeleteRange) {
backing_store->ClearRemovals();
std::vector<IndexedDBValue> values = {
- IndexedDBValue(
- "value0", {IndexedDBBlobInfo(
- "uuid 0", base::UTF8ToUTF16("type 0"), 1)}),
- IndexedDBValue(
- "value1", {IndexedDBBlobInfo(
- "uuid 1", base::UTF8ToUTF16("type 1"), 1)}),
- IndexedDBValue(
- "value2", {IndexedDBBlobInfo(
- "uuid 2", base::UTF8ToUTF16("type 2"), 1)}),
- IndexedDBValue(
- "value3",
- {IndexedDBBlobInfo("uuid 3", base::UTF8ToUTF16("type 3"),
- 1)})};
+ IndexedDBValue("value0",
+ {IndexedDBBlobInfo(
+ std::make_unique<storage::BlobDataHandle>(
+ *state->blobs[0]),
+ base::UTF8ToUTF16("type 0"), 1)}),
+ IndexedDBValue("value1",
+ {IndexedDBBlobInfo(
+ std::make_unique<storage::BlobDataHandle>(
+ *state->blobs[1]),
+ base::UTF8ToUTF16("type 1"), 1)}),
+ IndexedDBValue("value2",
+ {IndexedDBBlobInfo(
+ std::make_unique<storage::BlobDataHandle>(
+ *state->blobs[2]),
+ base::UTF8ToUTF16("type 2"), 1)}),
+ IndexedDBValue("value3",
+ {IndexedDBBlobInfo(
+ std::make_unique<storage::BlobDataHandle>(
+ *state->blobs[3]),
+ base::UTF8ToUTF16("type 3"), 1)})};
ASSERT_GE(keys.size(), values.size());
// Initiate transaction1 - write records.
@@ -653,14 +679,12 @@ TEST_F(IndexedDBBackingStoreTest, DeleteRange) {
std::make_unique<IndexedDBBackingStore::Transaction>(
backing_store);
state->transaction1->Begin();
- std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
IndexedDBBackingStore::RecordIdentifier record;
for (size_t i = 0; i < values.size(); ++i) {
EXPECT_TRUE(backing_store
->PutRecord(state->transaction1.get(),
database_id, object_store_id,
- keys[i], &values[i], &handles,
- &record)
+ keys[i], &values[i], &record)
.ok());
}
@@ -728,7 +752,7 @@ TEST_F(IndexedDBBackingStoreTest, DeleteRange) {
}
}
-TEST_F(IndexedDBBackingStoreTest, DeleteRangeEmptyRange) {
+TEST_F(IndexedDBBackingStoreTestWithBlobs, DeleteRangeEmptyRange) {
const std::vector<IndexedDBKey> keys = {
IndexedDBKey(ASCIIToUTF16("key0")), IndexedDBKey(ASCIIToUTF16("key1")),
IndexedDBKey(ASCIIToUTF16("key2")), IndexedDBKey(ASCIIToUTF16("key3")),
@@ -748,8 +772,12 @@ TEST_F(IndexedDBBackingStoreTest, DeleteRangeEmptyRange) {
scoped_refptr<TestCallback> callback1;
std::unique_ptr<IndexedDBBackingStore::Transaction> transaction2;
scoped_refptr<TestCallback> callback2;
+ std::vector<std::unique_ptr<storage::BlobDataHandle>> blobs;
} state;
+ for (size_t j = 0; j < 4; ++j)
+ state.blobs.push_back(CreateBlob());
+
idb_context_->TaskRunner()->PostTask(
FROM_HERE,
base::BindOnce(
@@ -761,19 +789,26 @@ TEST_F(IndexedDBBackingStoreTest, DeleteRangeEmptyRange) {
backing_store->ClearRemovals();
std::vector<IndexedDBValue> values = {
- IndexedDBValue(
- "value0", {IndexedDBBlobInfo(
- "uuid 0", base::UTF8ToUTF16("type 0"), 1)}),
- IndexedDBValue(
- "value1", {IndexedDBBlobInfo(
- "uuid 1", base::UTF8ToUTF16("type 1"), 1)}),
- IndexedDBValue(
- "value2", {IndexedDBBlobInfo(
- "uuid 2", base::UTF8ToUTF16("type 2"), 1)}),
- IndexedDBValue(
- "value3",
- {IndexedDBBlobInfo("uuid 3", base::UTF8ToUTF16("type 3"),
- 1)})};
+ IndexedDBValue("value0",
+ {IndexedDBBlobInfo(
+ std::make_unique<storage::BlobDataHandle>(
+ *state->blobs[0]),
+ base::UTF8ToUTF16("type 0"), 1)}),
+ IndexedDBValue("value1",
+ {IndexedDBBlobInfo(
+ std::make_unique<storage::BlobDataHandle>(
+ *state->blobs[1]),
+ base::UTF8ToUTF16("type 1"), 1)}),
+ IndexedDBValue("value2",
+ {IndexedDBBlobInfo(
+ std::make_unique<storage::BlobDataHandle>(
+ *state->blobs[2]),
+ base::UTF8ToUTF16("type 2"), 1)}),
+ IndexedDBValue("value3",
+ {IndexedDBBlobInfo(
+ std::make_unique<storage::BlobDataHandle>(
+ *state->blobs[3]),
+ base::UTF8ToUTF16("type 3"), 1)})};
ASSERT_GE(keys.size(), values.size());
// Initiate transaction1 - write records.
@@ -782,14 +817,12 @@ TEST_F(IndexedDBBackingStoreTest, DeleteRangeEmptyRange) {
backing_store);
state->transaction1->Begin();
- std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
IndexedDBBackingStore::RecordIdentifier record;
for (size_t i = 0; i < values.size(); ++i) {
EXPECT_TRUE(backing_store
->PutRecord(state->transaction1.get(),
database_id, object_store_id,
- keys[i], &values[i], &handles,
- &record)
+ keys[i], &values[i], &record)
.ok());
}
// Start committing transaction1.
@@ -869,12 +902,10 @@ TEST_F(IndexedDBBackingStoreTestWithBlobs, BlobJournalInterleavedTransactions) {
std::make_unique<IndexedDBBackingStore::Transaction>(
test->backing_store());
state->transaction1->Begin();
- std::vector<std::unique_ptr<storage::BlobDataHandle>> handles1;
IndexedDBBackingStore::RecordIdentifier record1;
EXPECT_TRUE(test->backing_store()
->PutRecord(state->transaction1.get(), 1, 1,
- test->key3_, &test->value3_, &handles1,
- &record1)
+ test->key3_, &test->value3_, &record1)
.ok());
state->callback1 = base::MakeRefCounted<TestCallback>();
EXPECT_TRUE(
@@ -898,12 +929,10 @@ TEST_F(IndexedDBBackingStoreTestWithBlobs, BlobJournalInterleavedTransactions) {
std::make_unique<IndexedDBBackingStore::Transaction>(
test->backing_store());
state->transaction2->Begin();
- std::vector<std::unique_ptr<storage::BlobDataHandle>> handles2;
IndexedDBBackingStore::RecordIdentifier record2;
EXPECT_TRUE(test->backing_store()
->PutRecord(state->transaction2.get(), 1, 1,
- test->key1_, &test->value1_, &handles2,
- &record2)
+ test->key1_, &test->value1_, &record2)
.ok());
state->callback2 = base::MakeRefCounted<TestCallback>();
EXPECT_TRUE(
@@ -953,12 +982,10 @@ TEST_F(IndexedDBBackingStoreTestWithBlobs, LiveBlobJournal) {
std::make_unique<IndexedDBBackingStore::Transaction>(
test->backing_store());
state->transaction1->Begin();
- std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
IndexedDBBackingStore::RecordIdentifier record;
EXPECT_TRUE(test->backing_store()
->PutRecord(state->transaction1.get(), 1, 1,
- test->key3_, &test->value3_, &handles,
- &record)
+ test->key3_, &test->value3_, &record)
.ok());
state->callback1 = base::MakeRefCounted<TestCallback>();
EXPECT_TRUE(
@@ -1081,11 +1108,10 @@ TEST_F(IndexedDBBackingStoreTest, HighIds) {
{
IndexedDBBackingStore::Transaction transaction1(backing_store);
transaction1.Begin();
- std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
IndexedDBBackingStore::RecordIdentifier record;
leveldb::Status s = backing_store->PutRecord(
&transaction1, high_database_id, high_object_store_id, key1,
- &value1, &handles, &record);
+ &value1, &record);
EXPECT_TRUE(s.ok());
s = backing_store->PutIndexDataForRecord(
@@ -1158,21 +1184,19 @@ TEST_F(IndexedDBBackingStoreTest, InvalidIds) {
IndexedDBBackingStore::Transaction transaction1(backing_store);
transaction1.Begin();
- std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
IndexedDBBackingStore::RecordIdentifier record;
leveldb::Status s = backing_store->PutRecord(
&transaction1, database_id, KeyPrefix::kInvalidId, key, &value,
- &handles, &record);
+ &record);
EXPECT_FALSE(s.ok());
s = backing_store->PutRecord(&transaction1, database_id, 0, key,
- &value, &handles, &record);
+ &value, &record);
EXPECT_FALSE(s.ok());
s = backing_store->PutRecord(&transaction1, KeyPrefix::kInvalidId,
- object_store_id, key, &value, &handles,
- &record);
+ object_store_id, key, &value, &record);
EXPECT_FALSE(s.ok());
s = backing_store->PutRecord(&transaction1, 0, object_store_id, key,
- &value, &handles, &record);
+ &value, &record);
EXPECT_FALSE(s.ok());
s = backing_store->GetRecord(&transaction1, database_id,
@@ -1503,11 +1527,10 @@ TEST_F(IndexedDBBackingStoreTest, SchemaUpgradeWithoutBlobsSurvives) {
// Save a value.
IndexedDBBackingStore::Transaction transaction1(backing_store);
transaction1.Begin();
- std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
IndexedDBBackingStore::RecordIdentifier record;
leveldb::Status s = backing_store->PutRecord(
&transaction1, state->database_id, state->object_store_id, key,
- &value, &handles, &record);
+ &value, &record);
EXPECT_TRUE(s.ok());
scoped_refptr<TestCallback> callback(
base::MakeRefCounted<TestCallback>());
@@ -1648,13 +1671,12 @@ TEST_F(IndexedDBBackingStoreTestWithBlobs, SchemaUpgradeWithBlobsCorrupt) {
std::make_unique<IndexedDBBackingStore::Transaction>(
test->backing_store());
state->transaction1->Begin();
- std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
IndexedDBBackingStore::RecordIdentifier record;
EXPECT_TRUE(test->backing_store()
->PutRecord(state->transaction1.get(),
state->database_id,
state->object_store_id, test->key3_,
- &test->value3_, &handles, &record)
+ &test->value3_, &record)
.ok());
state->callback1 = base::MakeRefCounted<TestCallback>();
EXPECT_TRUE(
diff --git a/chromium/content/browser/indexed_db/indexed_db_blob_info.cc b/chromium/content/browser/indexed_db/indexed_db_blob_info.cc
index a2308c48f46..0e40f9c65fd 100644
--- a/chromium/content/browser/indexed_db/indexed_db_blob_info.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_blob_info.cc
@@ -14,11 +14,12 @@ IndexedDBBlobInfo::IndexedDBBlobInfo()
: is_file_(false), size_(-1), key_(DatabaseMetaDataKey::kInvalidBlobKey) {
}
-IndexedDBBlobInfo::IndexedDBBlobInfo(const std::string& uuid,
- const base::string16& type,
- int64_t size)
+IndexedDBBlobInfo::IndexedDBBlobInfo(
+ std::unique_ptr<storage::BlobDataHandle> blob_handle,
+ const base::string16& type,
+ int64_t size)
: is_file_(false),
- uuid_(uuid),
+ blob_handle_(*blob_handle),
type_(type),
size_(size),
key_(DatabaseMetaDataKey::kInvalidBlobKey) {}
@@ -28,18 +29,18 @@ IndexedDBBlobInfo::IndexedDBBlobInfo(const base::string16& type,
int64_t key)
: is_file_(false), type_(type), size_(size), key_(key) {}
-IndexedDBBlobInfo::IndexedDBBlobInfo(const std::string& uuid,
- const base::FilePath& file_path,
- const base::string16& file_name,
- const base::string16& type)
+IndexedDBBlobInfo::IndexedDBBlobInfo(
+ std::unique_ptr<storage::BlobDataHandle> blob_handle,
+ const base::FilePath& file_path,
+ const base::string16& file_name,
+ const base::string16& type)
: is_file_(true),
- uuid_(uuid),
+ blob_handle_(*blob_handle),
type_(type),
size_(-1),
file_name_(file_name),
file_path_(file_path),
- key_(DatabaseMetaDataKey::kInvalidBlobKey) {
-}
+ key_(DatabaseMetaDataKey::kInvalidBlobKey) {}
IndexedDBBlobInfo::IndexedDBBlobInfo(int64_t key,
const base::string16& type,
@@ -62,12 +63,6 @@ void IndexedDBBlobInfo::set_size(int64_t size) {
size_ = size;
}
-void IndexedDBBlobInfo::set_uuid(const std::string& uuid) {
- DCHECK(uuid_.empty());
- uuid_ = uuid;
- DCHECK(!uuid_.empty());
-}
-
void IndexedDBBlobInfo::set_file_path(const base::FilePath& file_path) {
DCHECK(file_path_.empty());
file_path_ = file_path;
diff --git a/chromium/content/browser/indexed_db/indexed_db_blob_info.h b/chromium/content/browser/indexed_db/indexed_db_blob_info.h
index 8b11194307a..2e36c081e48 100644
--- a/chromium/content/browser/indexed_db/indexed_db_blob_info.h
+++ b/chromium/content/browser/indexed_db/indexed_db_blob_info.h
@@ -11,8 +11,10 @@
#include "base/callback.h"
#include "base/files/file_path.h"
+#include "base/optional.h"
#include "base/time/time.h"
#include "content/common/content_export.h"
+#include "storage/browser/blob/blob_data_handle.h"
namespace content {
@@ -22,12 +24,12 @@ class CONTENT_EXPORT IndexedDBBlobInfo {
typedef base::RepeatingCallback<void(const base::FilePath&)> ReleaseCallback;
IndexedDBBlobInfo();
// These two are used for Blobs.
- IndexedDBBlobInfo(const std::string& uuid,
+ IndexedDBBlobInfo(std::unique_ptr<storage::BlobDataHandle> blob_handle,
const base::string16& type,
int64_t size);
IndexedDBBlobInfo(const base::string16& type, int64_t size, int64_t key);
// These two are used for Files.
- IndexedDBBlobInfo(const std::string& uuid,
+ IndexedDBBlobInfo(std::unique_ptr<storage::BlobDataHandle> blob_handle,
const base::FilePath& file_path,
const base::string16& file_name,
const base::string16& type);
@@ -40,7 +42,9 @@ class CONTENT_EXPORT IndexedDBBlobInfo {
IndexedDBBlobInfo& operator=(const IndexedDBBlobInfo& other);
bool is_file() const { return is_file_; }
- const std::string& uuid() const { return uuid_; }
+ const storage::BlobDataHandle* blob_handle() const {
+ return blob_handle_.has_value() ? &blob_handle_.value() : nullptr;
+ }
const base::string16& type() const { return type_; }
int64_t size() const { return size_; }
const base::string16& file_name() const { return file_name_; }
@@ -53,7 +57,6 @@ class CONTENT_EXPORT IndexedDBBlobInfo {
const ReleaseCallback& release_callback() const { return release_callback_; }
void set_size(int64_t size);
- void set_uuid(const std::string& uuid);
void set_file_path(const base::FilePath& file_path);
void set_last_modified(const base::Time& time);
void set_key(int64_t key);
@@ -62,7 +65,8 @@ class CONTENT_EXPORT IndexedDBBlobInfo {
private:
bool is_file_;
- std::string uuid_; // Always for Blob; sometimes for File.
+ base::Optional<storage::BlobDataHandle>
+ blob_handle_; // Always for Blob; sometimes for File.
base::string16 type_; // Mime type.
int64_t size_; // -1 if unknown for File.
base::string16 file_name_; // Only for File.
diff --git a/chromium/content/browser/indexed_db/indexed_db_browsertest.cc b/chromium/content/browser/indexed_db/indexed_db_browsertest.cc
index 860e36aee5b..e4f3274ff39 100644
--- a/chromium/content/browser/indexed_db/indexed_db_browsertest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_browsertest.cc
@@ -420,7 +420,7 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, LevelDBLogFileTest) {
base::FilePath log_file_path =
GetContext()->data_path().Append(leveldb_dir).Append(log_file);
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_test_verification;
+ base::ScopedAllowBlockingForTesting allow_blocking;
int64_t size;
EXPECT_TRUE(base::GetFileSize(log_file_path, &size));
EXPECT_GT(size, 0);
diff --git a/chromium/content/browser/indexed_db/indexed_db_callbacks.cc b/chromium/content/browser/indexed_db/indexed_db_callbacks.cc
index 8e16c5dbeab..55fbe83dc93 100644
--- a/chromium/content/browser/indexed_db/indexed_db_callbacks.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_callbacks.cc
@@ -17,7 +17,6 @@
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/time/time.h"
#include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/fileapi/fileapi_message_filter.h"
#include "content/browser/indexed_db/cursor_impl.h"
#include "content/browser/indexed_db/database_impl.h"
#include "content/browser/indexed_db/indexed_db_connection.h"
@@ -28,8 +27,6 @@
#include "content/browser/indexed_db/indexed_db_tracing.h"
#include "content/browser/indexed_db/indexed_db_transaction.h"
#include "content/browser/indexed_db/indexed_db_value.h"
-#include "content/common/indexed_db/indexed_db_constants.h"
-#include "content/common/indexed_db/indexed_db_metadata.h"
#include "content/public/common/content_features.h"
#include "mojo/public/cpp/bindings/strong_associated_binding.h"
#include "storage/browser/blob/blob_data_builder.h"
@@ -37,8 +34,11 @@
#include "storage/browser/blob/blob_storage_context.h"
#include "storage/browser/blob/shareable_file_reference.h"
#include "storage/browser/quota/quota_manager.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_metadata.h"
-using indexed_db::mojom::CallbacksAssociatedPtrInfo;
+using blink::IndexedDBDatabaseMetadata;
+using blink::IndexedDBKey;
+using blink::mojom::IDBCallbacksAssociatedPtrInfo;
using std::swap;
using storage::ShareableFileReference;
@@ -93,17 +93,17 @@ class SafeIOThreadCursorWrapper {
void ConvertBlobInfo(
const std::vector<IndexedDBBlobInfo>& blob_info,
- std::vector<::indexed_db::mojom::BlobInfoPtr>* blob_or_file_info) {
+ std::vector<blink::mojom::IDBBlobInfoPtr>* blob_or_file_info) {
blob_or_file_info->reserve(blob_info.size());
for (const auto& iter : blob_info) {
if (!iter.mark_used_callback().is_null())
iter.mark_used_callback().Run();
- auto info = ::indexed_db::mojom::BlobInfo::New();
+ auto info = blink::mojom::IDBBlobInfo::New();
info->mime_type = iter.type();
info->size = iter.size();
if (iter.is_file()) {
- info->file = ::indexed_db::mojom::FileInfo::New();
+ info->file = blink::mojom::IDBFileInfo::New();
info->file->name = iter.file_name();
info->file->path = iter.file_path();
info->file->last_modified = iter.last_modified();
@@ -113,10 +113,10 @@ void ConvertBlobInfo(
}
// Destructively converts an IndexedDBReturnValue to a Mojo ReturnValue.
-::indexed_db::mojom::ReturnValuePtr ConvertReturnValue(
+blink::mojom::IDBReturnValuePtr ConvertReturnValue(
IndexedDBReturnValue* value) {
- auto mojo_value = ::indexed_db::mojom::ReturnValue::New();
- mojo_value->value = ::indexed_db::mojom::Value::New();
+ auto mojo_value = blink::mojom::IDBReturnValue::New();
+ mojo_value->value = blink::mojom::IDBValue::New();
if (value->primary_key.IsValid()) {
mojo_value->primary_key = value->primary_key;
mojo_value->key_path = value->key_path;
@@ -132,7 +132,7 @@ void ConvertBlobInfo(
// Expected to be created and called from IO thread.
class IndexedDBCallbacks::IOThreadHelper {
public:
- IOThreadHelper(CallbacksAssociatedPtrInfo callbacks_info,
+ IOThreadHelper(IDBCallbacksAssociatedPtrInfo callbacks_info,
base::WeakPtr<IndexedDBDispatcherHost> dispatcher_host,
url::Origin origin,
scoped_refptr<base::SequencedTaskRunner> idb_runner);
@@ -145,28 +145,28 @@ class IndexedDBCallbacks::IOThreadHelper {
int64_t old_version,
blink::WebIDBDataLoss data_loss,
const std::string& data_loss_message,
- const content::IndexedDBDatabaseMetadata& metadata);
+ const IndexedDBDatabaseMetadata& metadata);
void SendSuccessDatabase(SafeIOThreadConnectionWrapper connection,
- const content::IndexedDBDatabaseMetadata& metadata);
+ const IndexedDBDatabaseMetadata& metadata);
void SendSuccessCursor(SafeIOThreadCursorWrapper cursor,
const IndexedDBKey& key,
const IndexedDBKey& primary_key,
- ::indexed_db::mojom::ValuePtr value,
+ blink::mojom::IDBValuePtr value,
const std::vector<IndexedDBBlobInfo>& blob_info);
- void SendSuccessValue(::indexed_db::mojom::ReturnValuePtr value,
+ void SendSuccessValue(blink::mojom::IDBReturnValuePtr value,
const std::vector<IndexedDBBlobInfo>& blob_info);
void SendSuccessCursorContinue(
const IndexedDBKey& key,
const IndexedDBKey& primary_key,
- ::indexed_db::mojom::ValuePtr value,
+ blink::mojom::IDBValuePtr value,
const std::vector<IndexedDBBlobInfo>& blob_info);
void SendSuccessCursorPrefetch(
const std::vector<IndexedDBKey>& keys,
const std::vector<IndexedDBKey>& primary_keys,
- std::vector<::indexed_db::mojom::ValuePtr> mojo_values,
+ std::vector<blink::mojom::IDBValuePtr> mojo_values,
const std::vector<IndexedDBValue>& values);
void SendSuccessArray(
- std::vector<::indexed_db::mojom::ReturnValuePtr> mojo_values,
+ std::vector<blink::mojom::IDBReturnValuePtr> mojo_values,
const std::vector<IndexedDBReturnValue>& values);
void SendSuccessKey(const IndexedDBKey& value);
void SendSuccessInteger(int64_t value);
@@ -176,12 +176,12 @@ class IndexedDBCallbacks::IOThreadHelper {
const IndexedDBBlobInfo& blob_info);
bool CreateAllBlobs(
const std::vector<IndexedDBBlobInfo>& blob_info,
- std::vector<::indexed_db::mojom::BlobInfoPtr>* blob_or_file_info);
+ std::vector<blink::mojom::IDBBlobInfoPtr>* blob_or_file_info);
void OnConnectionError();
private:
base::WeakPtr<IndexedDBDispatcherHost> dispatcher_host_;
- ::indexed_db::mojom::CallbacksAssociatedPtr callbacks_;
+ blink::mojom::IDBCallbacksAssociatedPtr callbacks_;
url::Origin origin_;
scoped_refptr<base::SequencedTaskRunner> idb_runner_;
@@ -189,9 +189,9 @@ class IndexedDBCallbacks::IOThreadHelper {
};
// static
-::indexed_db::mojom::ValuePtr IndexedDBCallbacks::ConvertAndEraseValue(
+blink::mojom::IDBValuePtr IndexedDBCallbacks::ConvertAndEraseValue(
IndexedDBValue* value) {
- auto mojo_value = ::indexed_db::mojom::Value::New();
+ auto mojo_value = blink::mojom::IDBValue::New();
if (!value->empty())
swap(mojo_value->bits, value->bits);
ConvertBlobInfo(value->blob_info, &mojo_value->blob_or_file_info);
@@ -201,7 +201,7 @@ class IndexedDBCallbacks::IOThreadHelper {
IndexedDBCallbacks::IndexedDBCallbacks(
base::WeakPtr<IndexedDBDispatcherHost> dispatcher_host,
const url::Origin& origin,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks_info,
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info,
scoped_refptr<base::SequencedTaskRunner> idb_runner)
: data_loss_(blink::kWebIDBDataLossNone),
io_helper_(new IOThreadHelper(std::move(callbacks_info),
@@ -341,7 +341,7 @@ void IndexedDBCallbacks::OnSuccess(std::unique_ptr<IndexedDBCursor> cursor,
DCHECK_EQ(blink::kWebIDBDataLossNone, data_loss_);
- ::indexed_db::mojom::ValuePtr mojo_value;
+ blink::mojom::IDBValuePtr mojo_value;
std::vector<IndexedDBBlobInfo> blob_info;
if (value) {
mojo_value = ConvertAndEraseValue(value);
@@ -368,7 +368,7 @@ void IndexedDBCallbacks::OnSuccess(const IndexedDBKey& key,
DCHECK_EQ(blink::kWebIDBDataLossNone, data_loss_);
- ::indexed_db::mojom::ValuePtr mojo_value;
+ blink::mojom::IDBValuePtr mojo_value;
std::vector<IndexedDBBlobInfo> blob_info;
if (value) {
mojo_value = ConvertAndEraseValue(value);
@@ -395,7 +395,7 @@ void IndexedDBCallbacks::OnSuccessWithPrefetch(
DCHECK_EQ(blink::kWebIDBDataLossNone, data_loss_);
- std::vector<::indexed_db::mojom::ValuePtr> mojo_values;
+ std::vector<blink::mojom::IDBValuePtr> mojo_values;
mojo_values.reserve(values->size());
for (size_t i = 0; i < values->size(); ++i)
mojo_values.push_back(ConvertAndEraseValue(&(*values)[i]));
@@ -414,7 +414,7 @@ void IndexedDBCallbacks::OnSuccess(IndexedDBReturnValue* value) {
DCHECK_EQ(blink::kWebIDBDataLossNone, data_loss_);
- ::indexed_db::mojom::ReturnValuePtr mojo_value;
+ blink::mojom::IDBReturnValuePtr mojo_value;
std::vector<IndexedDBBlobInfo> blob_info;
if (value) {
mojo_value = ConvertReturnValue(value);
@@ -437,7 +437,7 @@ void IndexedDBCallbacks::OnSuccessArray(
DCHECK_EQ(blink::kWebIDBDataLossNone, data_loss_);
- std::vector<::indexed_db::mojom::ReturnValuePtr> mojo_values;
+ std::vector<blink::mojom::IDBReturnValuePtr> mojo_values;
mojo_values.reserve(values->size());
for (size_t i = 0; i < values->size(); ++i)
mojo_values.push_back(ConvertReturnValue(&(*values)[i]));
@@ -493,7 +493,7 @@ void IndexedDBCallbacks::SetConnectionOpenStartTime(
}
IndexedDBCallbacks::IOThreadHelper::IOThreadHelper(
- CallbacksAssociatedPtrInfo callbacks_info,
+ IDBCallbacksAssociatedPtrInfo callbacks_info,
base::WeakPtr<IndexedDBDispatcherHost> dispatcher_host,
url::Origin origin,
scoped_refptr<base::SequencedTaskRunner> idb_runner)
@@ -551,7 +551,7 @@ void IndexedDBCallbacks::IOThreadHelper::SendUpgradeNeeded(
int64_t old_version,
blink::WebIDBDataLoss data_loss,
const std::string& data_loss_message,
- const content::IndexedDBDatabaseMetadata& metadata) {
+ const IndexedDBDatabaseMetadata& metadata) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!callbacks_)
return;
@@ -564,7 +564,7 @@ void IndexedDBCallbacks::IOThreadHelper::SendUpgradeNeeded(
std::move(connection_wrapper.connection_), origin_,
dispatcher_host_.get(), idb_runner_);
- ::indexed_db::mojom::DatabaseAssociatedPtrInfo ptr_info;
+ blink::mojom::IDBDatabaseAssociatedPtrInfo ptr_info;
auto request = mojo::MakeRequest(&ptr_info);
dispatcher_host_->AddDatabaseBinding(std::move(database), std::move(request));
@@ -574,7 +574,7 @@ void IndexedDBCallbacks::IOThreadHelper::SendUpgradeNeeded(
void IndexedDBCallbacks::IOThreadHelper::SendSuccessDatabase(
SafeIOThreadConnectionWrapper connection_wrapper,
- const content::IndexedDBDatabaseMetadata& metadata) {
+ const IndexedDBDatabaseMetadata& metadata) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!callbacks_)
return;
@@ -582,7 +582,7 @@ void IndexedDBCallbacks::IOThreadHelper::SendSuccessDatabase(
OnConnectionError();
return;
}
- ::indexed_db::mojom::DatabaseAssociatedPtrInfo ptr_info;
+ blink::mojom::IDBDatabaseAssociatedPtrInfo ptr_info;
if (connection_wrapper.connection_) {
auto database = std::make_unique<DatabaseImpl>(
std::move(connection_wrapper.connection_), origin_,
@@ -599,7 +599,7 @@ void IndexedDBCallbacks::IOThreadHelper::SendSuccessCursor(
SafeIOThreadCursorWrapper cursor,
const IndexedDBKey& key,
const IndexedDBKey& primary_key,
- ::indexed_db::mojom::ValuePtr value,
+ blink::mojom::IDBValuePtr value,
const std::vector<IndexedDBBlobInfo>& blob_info) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!callbacks_)
@@ -614,7 +614,7 @@ void IndexedDBCallbacks::IOThreadHelper::SendSuccessCursor(
if (value && !CreateAllBlobs(blob_info, &value->blob_or_file_info))
return;
- ::indexed_db::mojom::CursorAssociatedPtrInfo ptr_info;
+ blink::mojom::IDBCursorAssociatedPtrInfo ptr_info;
auto request = mojo::MakeRequest(&ptr_info);
dispatcher_host_->AddCursorBinding(std::move(cursor_impl),
std::move(request));
@@ -623,7 +623,7 @@ void IndexedDBCallbacks::IOThreadHelper::SendSuccessCursor(
}
void IndexedDBCallbacks::IOThreadHelper::SendSuccessValue(
- ::indexed_db::mojom::ReturnValuePtr value,
+ blink::mojom::IDBReturnValuePtr value,
const std::vector<IndexedDBBlobInfo>& blob_info) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!callbacks_)
@@ -638,7 +638,7 @@ void IndexedDBCallbacks::IOThreadHelper::SendSuccessValue(
}
void IndexedDBCallbacks::IOThreadHelper::SendSuccessArray(
- std::vector<::indexed_db::mojom::ReturnValuePtr> mojo_values,
+ std::vector<blink::mojom::IDBReturnValuePtr> mojo_values,
const std::vector<IndexedDBReturnValue>& values) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_EQ(mojo_values.size(), values.size());
@@ -661,7 +661,7 @@ void IndexedDBCallbacks::IOThreadHelper::SendSuccessArray(
void IndexedDBCallbacks::IOThreadHelper::SendSuccessCursorContinue(
const IndexedDBKey& key,
const IndexedDBKey& primary_key,
- ::indexed_db::mojom::ValuePtr value,
+ blink::mojom::IDBValuePtr value,
const std::vector<IndexedDBBlobInfo>& blob_info) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!callbacks_)
@@ -678,7 +678,7 @@ void IndexedDBCallbacks::IOThreadHelper::SendSuccessCursorContinue(
void IndexedDBCallbacks::IOThreadHelper::SendSuccessCursorPrefetch(
const std::vector<IndexedDBKey>& keys,
const std::vector<IndexedDBKey>& primary_keys,
- std::vector<::indexed_db::mojom::ValuePtr> mojo_values,
+ std::vector<blink::mojom::IDBValuePtr> mojo_values,
const std::vector<IndexedDBValue>& values) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_EQ(mojo_values.size(), values.size());
@@ -738,10 +738,9 @@ std::unique_ptr<storage::BlobDataHandle>
IndexedDBCallbacks::IOThreadHelper::CreateBlobData(
const IndexedDBBlobInfo& blob_info) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!blob_info.uuid().empty()) {
+ if (blob_info.blob_handle()) {
// We're sending back a live blob, not a reference into our backing store.
- return dispatcher_host_->blob_storage_context()->GetBlobDataFromUUID(
- blob_info.uuid());
+ return std::make_unique<storage::BlobDataHandle>(*blob_info.blob_handle());
}
scoped_refptr<ShareableFileReference> shareable_file =
ShareableFileReference::Get(blob_info.file_path());
@@ -764,7 +763,7 @@ IndexedDBCallbacks::IOThreadHelper::CreateBlobData(
bool IndexedDBCallbacks::IOThreadHelper::CreateAllBlobs(
const std::vector<IndexedDBBlobInfo>& blob_info,
- std::vector<::indexed_db::mojom::BlobInfoPtr>* blob_or_file_info) {
+ std::vector<blink::mojom::IDBBlobInfoPtr>* blob_or_file_info) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!dispatcher_host_) {
OnConnectionError();
diff --git a/chromium/content/browser/indexed_db/indexed_db_callbacks.h b/chromium/content/browser/indexed_db/indexed_db_callbacks.h
index f654d0e144c..daada34ef53 100644
--- a/chromium/content/browser/indexed_db/indexed_db_callbacks.h
+++ b/chromium/content/browser/indexed_db/indexed_db_callbacks.h
@@ -18,22 +18,24 @@
#include "base/strings/string16.h"
#include "content/browser/indexed_db/indexed_db_database_error.h"
#include "content/browser/indexed_db/indexed_db_dispatcher_host.h"
-#include "content/common/indexed_db/indexed_db.mojom.h"
-#include "content/common/indexed_db/indexed_db_key.h"
-#include "content/common/indexed_db/indexed_db_key_path.h"
#include "content/public/browser/browser_thread.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
#include "url/origin.h"
namespace base {
class SequencedTaskRunner;
}
+namespace blink {
+struct IndexedDBDatabaseMetadata;
+}
+
namespace content {
class IndexedDBConnection;
class IndexedDBCursor;
class IndexedDBDatabase;
struct IndexedDBDataLossInfo;
-struct IndexedDBDatabaseMetadata;
struct IndexedDBReturnValue;
struct IndexedDBValue;
@@ -42,14 +44,12 @@ class CONTENT_EXPORT IndexedDBCallbacks
: public base::RefCounted<IndexedDBCallbacks> {
public:
// Destructively converts an IndexedDBValue to a Mojo Value.
- static ::indexed_db::mojom::ValuePtr ConvertAndEraseValue(
- IndexedDBValue* value);
+ static blink::mojom::IDBValuePtr ConvertAndEraseValue(IndexedDBValue* value);
- IndexedDBCallbacks(
- base::WeakPtr<IndexedDBDispatcherHost> dispatcher_host,
- const url::Origin& origin,
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks_info,
- scoped_refptr<base::SequencedTaskRunner> idb_runner);
+ IndexedDBCallbacks(base::WeakPtr<IndexedDBDispatcherHost> dispatcher_host,
+ const url::Origin& origin,
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info,
+ scoped_refptr<base::SequencedTaskRunner> idb_runner);
virtual void OnError(const IndexedDBDatabaseError& error);
@@ -60,29 +60,28 @@ class CONTENT_EXPORT IndexedDBCallbacks
virtual void OnBlocked(int64_t existing_version);
// IndexedDBFactory::Open
- virtual void OnUpgradeNeeded(
- int64_t old_version,
- std::unique_ptr<IndexedDBConnection> connection,
- const content::IndexedDBDatabaseMetadata& metadata,
- const IndexedDBDataLossInfo& data_loss_info);
+ virtual void OnUpgradeNeeded(int64_t old_version,
+ std::unique_ptr<IndexedDBConnection> connection,
+ const blink::IndexedDBDatabaseMetadata& metadata,
+ const IndexedDBDataLossInfo& data_loss_info);
virtual void OnSuccess(std::unique_ptr<IndexedDBConnection> connection,
- const content::IndexedDBDatabaseMetadata& metadata);
+ const blink::IndexedDBDatabaseMetadata& metadata);
// IndexedDBDatabase::OpenCursor
virtual void OnSuccess(std::unique_ptr<IndexedDBCursor> cursor,
- const IndexedDBKey& key,
- const IndexedDBKey& primary_key,
+ const blink::IndexedDBKey& key,
+ const blink::IndexedDBKey& primary_key,
IndexedDBValue* value);
// IndexedDBCursor::Continue / Advance
- virtual void OnSuccess(const IndexedDBKey& key,
- const IndexedDBKey& primary_key,
+ virtual void OnSuccess(const blink::IndexedDBKey& key,
+ const blink::IndexedDBKey& primary_key,
IndexedDBValue* value);
// IndexedDBCursor::PrefetchContinue
virtual void OnSuccessWithPrefetch(
- const std::vector<IndexedDBKey>& keys,
- const std::vector<IndexedDBKey>& primary_keys,
+ const std::vector<blink::IndexedDBKey>& keys,
+ const std::vector<blink::IndexedDBKey>& primary_keys,
std::vector<IndexedDBValue>* values);
// IndexedDBDatabase::Get
@@ -93,7 +92,7 @@ class CONTENT_EXPORT IndexedDBCallbacks
virtual void OnSuccessArray(std::vector<IndexedDBReturnValue>* values);
// IndexedDBDatabase::Put / IndexedDBCursor::Update
- virtual void OnSuccess(const IndexedDBKey& key);
+ virtual void OnSuccess(const blink::IndexedDBKey& key);
// IndexedDBDatabase::Count
// IndexedDBFactory::DeleteDatabase
diff --git a/chromium/content/browser/indexed_db/indexed_db_class_factory.h b/chromium/content/browser/indexed_db/indexed_db_class_factory.h
index 21fc4381b64..a33b2f14049 100644
--- a/chromium/content/browser/indexed_db/indexed_db_class_factory.h
+++ b/chromium/content/browser/indexed_db/indexed_db_class_factory.h
@@ -15,7 +15,7 @@
#include "content/browser/indexed_db/indexed_db_backing_store.h"
#include "content/browser/indexed_db/indexed_db_database.h"
#include "content/common/content_export.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_types.h"
+#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
namespace leveldb {
class Iterator;
diff --git a/chromium/content/browser/indexed_db/indexed_db_context_impl.cc b/chromium/content/browser/indexed_db/indexed_db_context_impl.cc
index d582605c949..2bd6e7fc36e 100644
--- a/chromium/content/browser/indexed_db/indexed_db_context_impl.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_context_impl.cc
@@ -16,7 +16,7 @@
#include "base/sequenced_task_runner.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
@@ -405,6 +405,17 @@ void IndexedDBContextImpl::ForceClose(const Origin origin,
DCHECK_EQ(0UL, GetConnectionCount(origin));
}
+void IndexedDBContextImpl::ForceSchemaDowngrade(const Origin& origin) {
+ DCHECK(TaskRunner()->RunsTasksInCurrentSequence());
+
+ if (data_path_.empty() || !HasOrigin(origin))
+ return;
+
+ if (factory_.get())
+ factory_->ForceSchemaDowngrade(origin);
+ DCHECK_EQ(0UL, GetConnectionCount(origin));
+}
+
size_t IndexedDBContextImpl::GetConnectionCount(const Origin& origin) {
DCHECK(TaskRunner()->RunsTasksInCurrentSequence());
if (!HasOrigin(origin))
diff --git a/chromium/content/browser/indexed_db/indexed_db_context_impl.h b/chromium/content/browser/indexed_db/indexed_db_context_impl.h
index 12eecbed9f0..856f9e3e482 100644
--- a/chromium/content/browser/indexed_db/indexed_db_context_impl.h
+++ b/chromium/content/browser/indexed_db/indexed_db_context_impl.h
@@ -47,6 +47,7 @@ class CONTENT_EXPORT IndexedDBContextImpl : public IndexedDBContext {
FORCE_CLOSE_BACKING_STORE_FAILURE,
FORCE_CLOSE_INTERNALS_PAGE,
FORCE_CLOSE_COPY_ORIGIN,
+ FORCE_SCHEMA_DOWNGRADE_INTERNALS_PAGE,
// Append new values here and update IDBContextForcedCloseReason in
// enums.xml.
FORCE_CLOSE_REASON_MAX
@@ -122,6 +123,7 @@ class CONTENT_EXPORT IndexedDBContextImpl : public IndexedDBContext {
// ForceClose takes a value rather than a reference since it may release the
// owning object.
void ForceClose(const url::Origin origin, ForceCloseReason reason);
+ void ForceSchemaDowngrade(const url::Origin& origin);
// GetStoragePaths returns all paths owned by this database, in arbitrary
// order.
std::vector<base::FilePath> GetStoragePaths(const url::Origin& origin) const;
@@ -191,7 +193,7 @@ class CONTENT_EXPORT IndexedDBContextImpl : public IndexedDBContext {
scoped_refptr<base::SequencedTaskRunner> task_runner_;
std::unique_ptr<std::set<url::Origin>> origin_set_;
std::map<url::Origin, int64_t> origin_size_map_;
- base::ObserverList<Observer> observers_;
+ base::ObserverList<Observer>::Unchecked observers_;
DISALLOW_COPY_AND_ASSIGN(IndexedDBContextImpl);
};
diff --git a/chromium/content/browser/indexed_db/indexed_db_cursor.cc b/chromium/content/browser/indexed_db/indexed_db_cursor.cc
index bd12dd62086..6a940b17897 100644
--- a/chromium/content/browser/indexed_db/indexed_db_cursor.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_cursor.cc
@@ -17,6 +17,8 @@
#include "content/browser/indexed_db/indexed_db_value.h"
#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_exception.h"
+using blink::IndexedDBKey;
+
namespace content {
namespace {
// This should never be script visible: the cursor should either be closed when
diff --git a/chromium/content/browser/indexed_db/indexed_db_cursor.h b/chromium/content/browser/indexed_db/indexed_db_cursor.h
index d0cc7e74e37..60aad023c62 100644
--- a/chromium/content/browser/indexed_db/indexed_db_cursor.h
+++ b/chromium/content/browser/indexed_db/indexed_db_cursor.h
@@ -16,8 +16,7 @@
#include "content/browser/indexed_db/indexed_db_backing_store.h"
#include "content/browser/indexed_db/indexed_db_database.h"
#include "content/browser/indexed_db/indexed_db_transaction.h"
-#include "content/common/indexed_db/indexed_db_key_range.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_types.h"
+#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
namespace content {
@@ -30,15 +29,17 @@ class CONTENT_EXPORT IndexedDBCursor {
~IndexedDBCursor();
void Advance(uint32_t count, scoped_refptr<IndexedDBCallbacks> callbacks);
- void Continue(std::unique_ptr<IndexedDBKey> key,
- std::unique_ptr<IndexedDBKey> primary_key,
+ void Continue(std::unique_ptr<blink::IndexedDBKey> key,
+ std::unique_ptr<blink::IndexedDBKey> primary_key,
scoped_refptr<IndexedDBCallbacks> callbacks);
void PrefetchContinue(int number_to_fetch,
scoped_refptr<IndexedDBCallbacks> callbacks);
leveldb::Status PrefetchReset(int used_prefetches, int unused_prefetches);
- const IndexedDBKey& key() const { return cursor_->key(); }
- const IndexedDBKey& primary_key() const { return cursor_->primary_key(); }
+ const blink::IndexedDBKey& key() const { return cursor_->key(); }
+ const blink::IndexedDBKey& primary_key() const {
+ return cursor_->primary_key();
+ }
IndexedDBValue* Value() const {
return (cursor_type_ == indexed_db::CURSOR_KEY_ONLY) ? NULL
: cursor_->value();
@@ -47,8 +48,8 @@ class CONTENT_EXPORT IndexedDBCursor {
void Close();
leveldb::Status CursorIterationOperation(
- std::unique_ptr<IndexedDBKey> key,
- std::unique_ptr<IndexedDBKey> primary_key,
+ std::unique_ptr<blink::IndexedDBKey> key,
+ std::unique_ptr<blink::IndexedDBKey> primary_key,
scoped_refptr<IndexedDBCallbacks> callbacks,
IndexedDBTransaction* transaction);
leveldb::Status CursorAdvanceOperation(
diff --git a/chromium/content/browser/indexed_db/indexed_db_data_loss_info.h b/chromium/content/browser/indexed_db/indexed_db_data_loss_info.h
index 8c36dd38666..318f04e78e2 100644
--- a/chromium/content/browser/indexed_db/indexed_db_data_loss_info.h
+++ b/chromium/content/browser/indexed_db/indexed_db_data_loss_info.h
@@ -7,7 +7,7 @@
#include <string>
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_types.h"
+#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
namespace content {
diff --git a/chromium/content/browser/indexed_db/indexed_db_database.cc b/chromium/content/browser/indexed_db/indexed_db_database.cc
index 3baba4f2ed7..62b40f652fb 100644
--- a/chromium/content/browser/indexed_db/indexed_db_database.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_database.cc
@@ -31,17 +31,25 @@
#include "content/browser/indexed_db/indexed_db_tracing.h"
#include "content/browser/indexed_db/indexed_db_transaction.h"
#include "content/browser/indexed_db/indexed_db_value.h"
-#include "content/common/indexed_db/indexed_db_constants.h"
-#include "content/common/indexed_db/indexed_db_key_path.h"
-#include "content/common/indexed_db/indexed_db_key_range.h"
#include "content/public/common/content_switches.h"
+#include "ipc/ipc_channel.h"
#include "storage/browser/blob/blob_data_handle.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key_path.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key_range.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_metadata.h"
#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_exception.h"
#include "third_party/leveldatabase/env_chromium.h"
#include "url/origin.h"
using base::ASCIIToUTF16;
using base::Int64ToString16;
+using blink::IndexedDBDatabaseMetadata;
+using blink::IndexedDBIndexKeys;
+using blink::IndexedDBIndexMetadata;
+using blink::IndexedDBKey;
+using blink::IndexedDBKeyPath;
+using blink::IndexedDBKeyRange;
+using blink::IndexedDBObjectStoreMetadata;
using blink::kWebIDBKeyTypeNumber;
using leveldb::Status;
@@ -469,8 +477,18 @@ IndexedDBDatabase::~IndexedDBDatabase() {
DCHECK(pending_requests_.empty());
}
-size_t IndexedDBDatabase::GetMaxMessageSizeInBytes() const {
- return kMaxIDBMessageSizeInBytes;
+// kIDBMaxMessageSize is defined based on the original
+// IPC::Channel::kMaximumMessageSize value. We use kIDBMaxMessageSize to limit
+// the size of arguments we pass into our Mojo calls. We want to ensure this
+// value is always no bigger than the current kMaximumMessageSize value which
+// also ensures it is always no bigger than the current Mojo message size limit.
+static_assert(
+ blink::mojom::kIDBMaxMessageSize <= IPC::Channel::kMaximumMessageSize,
+ "kIDBMaxMessageSize is bigger than IPC::Channel::kMaximumMessageSize");
+
+size_t IndexedDBDatabase::GetUsableMessageSizeInBytes() const {
+ return blink::mojom::kIDBMaxMessageSize -
+ blink::mojom::kIDBMaxMessageOverhead;
}
std::unique_ptr<IndexedDBConnection> IndexedDBDatabase::CreateConnection(
@@ -816,7 +834,7 @@ void IndexedDBDatabase::FilterObservation(IndexedDBTransaction* transaction,
!observer->IsRecordingObjectStore(object_store_id))
continue;
if (!recorded) {
- auto observation = ::indexed_db::mojom::Observation::New();
+ auto observation = blink::mojom::IDBObservation::New();
observation->object_store_id = object_store_id;
observation->type = type;
if (type != blink::kWebIDBClear)
@@ -824,14 +842,14 @@ void IndexedDBDatabase::FilterObservation(IndexedDBTransaction* transaction,
transaction->AddObservation(connection->id(), std::move(observation));
recorded = true;
}
- ::indexed_db::mojom::ObserverChangesPtr& changes =
+ blink::mojom::IDBObserverChangesPtr& changes =
*transaction->GetPendingChangesForConnection(connection->id());
changes->observation_index_map[observer->id()].push_back(
changes->observations.size() - 1);
if (observer->include_transaction() &&
!base::ContainsKey(changes->transaction_map, observer->id())) {
- auto mojo_transaction = ::indexed_db::mojom::ObserverTransaction::New();
+ auto mojo_transaction = blink::mojom::IDBObserverTransaction::New();
mojo_transaction->id = connection->NewObserverTransactionId();
mojo_transaction->scope.insert(mojo_transaction->scope.end(),
observer->object_store_ids().begin(),
@@ -851,14 +869,14 @@ void IndexedDBDatabase::FilterObservation(IndexedDBTransaction* transaction,
}
void IndexedDBDatabase::SendObservations(
- std::map<int32_t, ::indexed_db::mojom::ObserverChangesPtr> changes_map) {
+ std::map<int32_t, blink::mojom::IDBObserverChangesPtr> changes_map) {
for (auto* conn : connections_) {
auto it = changes_map.find(conn->id());
if (it == changes_map.end())
continue;
// Start all of the transactions.
- ::indexed_db::mojom::ObserverChangesPtr& changes = it->second;
+ blink::mojom::IDBObserverChangesPtr& changes = it->second;
for (const auto& transaction_pair : changes->transaction_map) {
std::set<int64_t> scope(transaction_pair.second->scope.begin(),
transaction_pair.second->scope.end());
@@ -1047,6 +1065,11 @@ Status IndexedDBDatabase::GetOperation(
return s;
}
+static_assert(sizeof(size_t) >= sizeof(int32_t),
+ "Size of size_t is less than size of int32");
+static_assert(blink::mojom::kIDBMaxMessageOverhead <= INT32_MAX,
+ "kIDBMaxMessageOverhead is more than INT32_MAX");
+
Status IndexedDBDatabase::GetAllOperation(
int64_t object_store_id,
int64_t index_id,
@@ -1114,7 +1137,7 @@ Status IndexedDBDatabase::GetAllOperation(
bool generated_key = object_store_metadata.auto_increment &&
!object_store_metadata.key_path.IsNull();
- size_t response_size = kMaxIDBMessageOverhead;
+ size_t response_size = blink::mojom::kIDBMaxMessageOverhead;
int64_t num_found_items = 0;
while (num_found_items++ < max_count) {
bool cursor_valid;
@@ -1148,7 +1171,7 @@ Status IndexedDBDatabase::GetAllOperation(
response_size += return_key.size_estimate();
else
response_size += return_value.SizeEstimate();
- if (response_size > GetMaxMessageSizeInBytes()) {
+ if (response_size > GetUsableMessageSizeInBytes()) {
callbacks->OnError(
IndexedDBDatabaseError(blink::kWebIDBDatabaseExceptionUnknownError,
"Maximum IPC message size exceeded."));
@@ -1216,7 +1239,6 @@ struct IndexedDBDatabase::PutOperationParams {
PutOperationParams() {}
int64_t object_store_id;
IndexedDBValue value;
- std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
std::unique_ptr<IndexedDBKey> key;
blink::WebIDBPutMode put_mode;
scoped_refptr<IndexedDBCallbacks> callbacks;
@@ -1230,7 +1252,6 @@ void IndexedDBDatabase::Put(
IndexedDBTransaction* transaction,
int64_t object_store_id,
IndexedDBValue* value,
- std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles,
std::unique_ptr<IndexedDBKey> key,
blink::WebIDBPutMode put_mode,
scoped_refptr<IndexedDBCallbacks> callbacks,
@@ -1248,7 +1269,6 @@ void IndexedDBDatabase::Put(
std::make_unique<PutOperationParams>());
params->object_store_id = object_store_id;
params->value.swap(*value);
- params->handles.swap(*handles);
params->key = std::move(key);
params->put_mode = put_mode;
params->callbacks = callbacks;
@@ -1336,7 +1356,7 @@ Status IndexedDBDatabase::PutOperation(
// transaction in case of error.
s = backing_store_->PutRecord(transaction->BackingStoreTransaction(), id(),
params->object_store_id, *key, &params->value,
- &params->handles, &record_identifier);
+ &record_identifier);
if (!s.ok())
return s;
diff --git a/chromium/content/browser/indexed_db/indexed_db_database.h b/chromium/content/browser/indexed_db/indexed_db_database.h
index 0fc4f636c2b..4ca1676c41a 100644
--- a/chromium/content/browser/indexed_db/indexed_db_database.h
+++ b/chromium/content/browser/indexed_db/indexed_db_database.h
@@ -28,8 +28,16 @@
#include "content/browser/indexed_db/indexed_db_transaction_coordinator.h"
#include "content/browser/indexed_db/list_set.h"
#include "content/common/content_export.h"
-#include "content/common/indexed_db/indexed_db_metadata.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_types.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
+#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
+
+namespace blink {
+class IndexedDBKeyPath;
+class IndexedDBKeyRange;
+struct IndexedDBDatabaseMetadata;
+struct IndexedDBIndexMetadata;
+struct IndexedDBObjectStoreMetadata;
+} // namespace blink
namespace url {
class Origin;
@@ -40,9 +48,6 @@ namespace content {
class IndexedDBConnection;
class IndexedDBDatabaseCallbacks;
class IndexedDBFactory;
-class IndexedDBKey;
-class IndexedDBKeyPath;
-class IndexedDBKeyRange;
class IndexedDBMetadataCoding;
class IndexedDBTransaction;
struct IndexedDBValue;
@@ -70,23 +75,25 @@ class CONTENT_EXPORT IndexedDBDatabase
const base::string16& name() const { return metadata_.name; }
const url::Origin& origin() const { return identifier_.first; }
- void AddObjectStore(IndexedDBObjectStoreMetadata metadata,
+ void AddObjectStore(blink::IndexedDBObjectStoreMetadata metadata,
int64_t new_max_object_store_id);
- IndexedDBObjectStoreMetadata RemoveObjectStore(int64_t object_store_id);
+ blink::IndexedDBObjectStoreMetadata RemoveObjectStore(
+ int64_t object_store_id);
void AddIndex(int64_t object_store_id,
- IndexedDBIndexMetadata metadata,
+ blink::IndexedDBIndexMetadata metadata,
int64_t new_max_index_id);
- IndexedDBIndexMetadata RemoveIndex(int64_t object_store_id, int64_t index_id);
+ blink::IndexedDBIndexMetadata RemoveIndex(int64_t object_store_id,
+ int64_t index_id);
void OpenConnection(std::unique_ptr<IndexedDBPendingConnection> connection);
void DeleteDatabase(scoped_refptr<IndexedDBCallbacks> callbacks,
bool force_close);
- const IndexedDBDatabaseMetadata& metadata() const { return metadata_; }
+ const blink::IndexedDBDatabaseMetadata& metadata() const { return metadata_; }
void CreateObjectStore(IndexedDBTransaction* transaction,
int64_t object_store_id,
const base::string16& name,
- const IndexedDBKeyPath& key_path,
+ const blink::IndexedDBKeyPath& key_path,
bool auto_increment);
void DeleteObjectStore(IndexedDBTransaction* transaction,
int64_t object_store_id);
@@ -115,7 +122,7 @@ class CONTENT_EXPORT IndexedDBDatabase
int64_t object_store_id,
int64_t index_id,
const base::string16& name,
- const IndexedDBKeyPath& key_path,
+ const blink::IndexedDBKeyPath& key_path,
bool unique,
bool multi_entry);
void DeleteIndex(IndexedDBTransaction* transaction,
@@ -146,43 +153,42 @@ class CONTENT_EXPORT IndexedDBDatabase
void FilterObservation(IndexedDBTransaction*,
int64_t object_store_id,
blink::WebIDBOperationType type,
- const IndexedDBKeyRange& key_range,
+ const blink::IndexedDBKeyRange& key_range,
const IndexedDBValue* value);
void SendObservations(
- std::map<int32_t, ::indexed_db::mojom::ObserverChangesPtr> change_map);
+ std::map<int32_t, blink::mojom::IDBObserverChangesPtr> change_map);
void Get(IndexedDBTransaction* transaction,
int64_t object_store_id,
int64_t index_id,
- std::unique_ptr<IndexedDBKeyRange> key_range,
+ std::unique_ptr<blink::IndexedDBKeyRange> key_range,
bool key_only,
scoped_refptr<IndexedDBCallbacks> callbacks);
void GetAll(IndexedDBTransaction* transaction,
int64_t object_store_id,
int64_t index_id,
- std::unique_ptr<IndexedDBKeyRange> key_range,
+ std::unique_ptr<blink::IndexedDBKeyRange> key_range,
bool key_only,
int64_t max_count,
scoped_refptr<IndexedDBCallbacks> callbacks);
void Put(IndexedDBTransaction* transaction,
int64_t object_store_id,
IndexedDBValue* value,
- std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles,
- std::unique_ptr<IndexedDBKey> key,
+ std::unique_ptr<blink::IndexedDBKey> key,
blink::WebIDBPutMode mode,
scoped_refptr<IndexedDBCallbacks> callbacks,
- const std::vector<IndexedDBIndexKeys>& index_keys);
+ const std::vector<blink::IndexedDBIndexKeys>& index_keys);
void SetIndexKeys(IndexedDBTransaction* transaction,
int64_t object_store_id,
- std::unique_ptr<IndexedDBKey> primary_key,
- const std::vector<IndexedDBIndexKeys>& index_keys);
+ std::unique_ptr<blink::IndexedDBKey> primary_key,
+ const std::vector<blink::IndexedDBIndexKeys>& index_keys);
void SetIndexesReady(IndexedDBTransaction* transaction,
int64_t object_store_id,
const std::vector<int64_t>& index_ids);
void OpenCursor(IndexedDBTransaction* transaction,
int64_t object_store_id,
int64_t index_id,
- std::unique_ptr<IndexedDBKeyRange> key_range,
+ std::unique_ptr<blink::IndexedDBKeyRange> key_range,
blink::WebIDBCursorDirection,
bool key_only,
blink::WebIDBTaskType task_type,
@@ -190,11 +196,11 @@ class CONTENT_EXPORT IndexedDBDatabase
void Count(IndexedDBTransaction* transaction,
int64_t object_store_id,
int64_t index_id,
- std::unique_ptr<IndexedDBKeyRange> key_range,
+ std::unique_ptr<blink::IndexedDBKeyRange> key_range,
scoped_refptr<IndexedDBCallbacks> callbacks);
void DeleteRange(IndexedDBTransaction* transaction,
int64_t object_store_id,
- std::unique_ptr<IndexedDBKeyRange> key_range,
+ std::unique_ptr<blink::IndexedDBKeyRange> key_range,
scoped_refptr<IndexedDBCallbacks> callbacks);
void Clear(IndexedDBTransaction* transaction,
int64_t object_store_id,
@@ -215,7 +221,7 @@ class CONTENT_EXPORT IndexedDBDatabase
leveldb::Status DeleteObjectStoreOperation(int64_t object_store_id,
IndexedDBTransaction* transaction);
void DeleteObjectStoreAbortOperation(
- IndexedDBObjectStoreMetadata object_store_metadata);
+ blink::IndexedDBObjectStoreMetadata object_store_metadata);
void RenameObjectStoreAbortOperation(int64_t object_store_id,
base::string16 old_name);
leveldb::Status VersionChangeOperation(
@@ -228,23 +234,25 @@ class CONTENT_EXPORT IndexedDBDatabase
IndexedDBTransaction* transaction);
void CreateIndexAbortOperation(int64_t object_store_id, int64_t index_id);
void DeleteIndexAbortOperation(int64_t object_store_id,
- IndexedDBIndexMetadata index_metadata);
+ blink::IndexedDBIndexMetadata index_metadata);
void RenameIndexAbortOperation(int64_t object_store_id,
int64_t index_id,
base::string16 old_name);
- leveldb::Status GetOperation(int64_t object_store_id,
- int64_t index_id,
- std::unique_ptr<IndexedDBKeyRange> key_range,
- indexed_db::CursorType cursor_type,
- scoped_refptr<IndexedDBCallbacks> callbacks,
- IndexedDBTransaction* transaction);
- leveldb::Status GetAllOperation(int64_t object_store_id,
- int64_t index_id,
- std::unique_ptr<IndexedDBKeyRange> key_range,
- indexed_db::CursorType cursor_type,
- int64_t max_count,
- scoped_refptr<IndexedDBCallbacks> callbacks,
- IndexedDBTransaction* transaction);
+ leveldb::Status GetOperation(
+ int64_t object_store_id,
+ int64_t index_id,
+ std::unique_ptr<blink::IndexedDBKeyRange> key_range,
+ indexed_db::CursorType cursor_type,
+ scoped_refptr<IndexedDBCallbacks> callbacks,
+ IndexedDBTransaction* transaction);
+ leveldb::Status GetAllOperation(
+ int64_t object_store_id,
+ int64_t index_id,
+ std::unique_ptr<blink::IndexedDBKeyRange> key_range,
+ indexed_db::CursorType cursor_type,
+ int64_t max_count,
+ scoped_refptr<IndexedDBCallbacks> callbacks,
+ IndexedDBTransaction* transaction);
struct PutOperationParams;
leveldb::Status PutOperation(std::unique_ptr<PutOperationParams> params,
IndexedDBTransaction* transaction);
@@ -254,14 +262,15 @@ class CONTENT_EXPORT IndexedDBDatabase
leveldb::Status OpenCursorOperation(
std::unique_ptr<OpenCursorOperationParams> params,
IndexedDBTransaction* transaction);
- leveldb::Status CountOperation(int64_t object_store_id,
- int64_t index_id,
- std::unique_ptr<IndexedDBKeyRange> key_range,
- scoped_refptr<IndexedDBCallbacks> callbacks,
- IndexedDBTransaction* transaction);
+ leveldb::Status CountOperation(
+ int64_t object_store_id,
+ int64_t index_id,
+ std::unique_ptr<blink::IndexedDBKeyRange> key_range,
+ scoped_refptr<IndexedDBCallbacks> callbacks,
+ IndexedDBTransaction* transaction);
leveldb::Status DeleteRangeOperation(
int64_t object_store_id,
- std::unique_ptr<IndexedDBKeyRange> key_range,
+ std::unique_ptr<blink::IndexedDBKeyRange> key_range,
scoped_refptr<IndexedDBCallbacks> callbacks,
IndexedDBTransaction* transaction);
leveldb::Status ClearOperation(int64_t object_store_id,
@@ -287,7 +296,7 @@ class CONTENT_EXPORT IndexedDBDatabase
virtual ~IndexedDBDatabase();
// May be overridden in tests.
- virtual size_t GetMaxMessageSizeInBytes() const;
+ virtual size_t GetUsableMessageSizeInBytes() const;
private:
friend class base::RefCounted<IndexedDBDatabase>;
@@ -328,7 +337,7 @@ class CONTENT_EXPORT IndexedDBDatabase
int64_t index_id) const;
scoped_refptr<IndexedDBBackingStore> backing_store_;
- IndexedDBDatabaseMetadata metadata_;
+ blink::IndexedDBDatabaseMetadata metadata_;
const Identifier identifier_;
scoped_refptr<IndexedDBFactory> factory_;
diff --git a/chromium/content/browser/indexed_db/indexed_db_database_callbacks.cc b/chromium/content/browser/indexed_db/indexed_db_database_callbacks.cc
index 0dcddfd12fc..2da4f50e3b4 100644
--- a/chromium/content/browser/indexed_db/indexed_db_database_callbacks.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_database_callbacks.cc
@@ -9,31 +9,31 @@
#include "content/browser/indexed_db/indexed_db_dispatcher_host.h"
#include "content/browser/indexed_db/indexed_db_transaction.h"
-using ::indexed_db::mojom::DatabaseCallbacksAssociatedPtrInfo;
+using blink::mojom::IDBDatabaseCallbacksAssociatedPtrInfo;
namespace content {
class IndexedDBDatabaseCallbacks::IOThreadHelper {
public:
- explicit IOThreadHelper(DatabaseCallbacksAssociatedPtrInfo callbacks_info);
+ explicit IOThreadHelper(IDBDatabaseCallbacksAssociatedPtrInfo callbacks_info);
~IOThreadHelper();
void SendForcedClose();
void SendVersionChange(int64_t old_version, int64_t new_version);
void SendAbort(int64_t transaction_id, const IndexedDBDatabaseError& error);
void SendComplete(int64_t transaction_id);
- void SendChanges(::indexed_db::mojom::ObserverChangesPtr changes);
+ void SendChanges(blink::mojom::IDBObserverChangesPtr changes);
void OnConnectionError();
private:
- ::indexed_db::mojom::DatabaseCallbacksAssociatedPtr callbacks_;
+ blink::mojom::IDBDatabaseCallbacksAssociatedPtr callbacks_;
DISALLOW_COPY_AND_ASSIGN(IOThreadHelper);
};
IndexedDBDatabaseCallbacks::IndexedDBDatabaseCallbacks(
scoped_refptr<IndexedDBContextImpl> context,
- DatabaseCallbacksAssociatedPtrInfo callbacks_info)
+ IDBDatabaseCallbacksAssociatedPtrInfo callbacks_info)
: indexed_db_context_(std::move(context)),
io_helper_(new IOThreadHelper(std::move(callbacks_info))) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -98,7 +98,7 @@ void IndexedDBDatabaseCallbacks::OnComplete(
}
void IndexedDBDatabaseCallbacks::OnDatabaseChange(
- ::indexed_db::mojom::ObserverChangesPtr changes) {
+ blink::mojom::IDBObserverChangesPtr changes) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(io_helper_);
BrowserThread::PostTask(
@@ -108,7 +108,7 @@ void IndexedDBDatabaseCallbacks::OnDatabaseChange(
}
IndexedDBDatabaseCallbacks::IOThreadHelper::IOThreadHelper(
- DatabaseCallbacksAssociatedPtrInfo callbacks_info) {
+ IDBDatabaseCallbacksAssociatedPtrInfo callbacks_info) {
if (!callbacks_info.is_valid())
return;
callbacks_.Bind(std::move(callbacks_info));
@@ -144,7 +144,7 @@ void IndexedDBDatabaseCallbacks::IOThreadHelper::SendComplete(
}
void IndexedDBDatabaseCallbacks::IOThreadHelper::SendChanges(
- ::indexed_db::mojom::ObserverChangesPtr changes) {
+ blink::mojom::IDBObserverChangesPtr changes) {
if (callbacks_)
callbacks_->Changes(std::move(changes));
}
diff --git a/chromium/content/browser/indexed_db/indexed_db_database_callbacks.h b/chromium/content/browser/indexed_db/indexed_db_database_callbacks.h
index 86160968999..282d7736f0d 100644
--- a/chromium/content/browser/indexed_db/indexed_db_database_callbacks.h
+++ b/chromium/content/browser/indexed_db/indexed_db_database_callbacks.h
@@ -11,8 +11,8 @@
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "content/common/content_export.h"
-#include "content/common/indexed_db/indexed_db.mojom.h"
#include "content/public/browser/browser_thread.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
namespace content {
class IndexedDBContextImpl;
@@ -25,7 +25,7 @@ class CONTENT_EXPORT IndexedDBDatabaseCallbacks
public:
IndexedDBDatabaseCallbacks(
scoped_refptr<IndexedDBContextImpl> context,
- ::indexed_db::mojom::DatabaseCallbacksAssociatedPtrInfo callbacks_info);
+ blink::mojom::IDBDatabaseCallbacksAssociatedPtrInfo callbacks_info);
virtual void OnForcedClose();
virtual void OnVersionChange(int64_t old_version, int64_t new_version);
@@ -33,8 +33,7 @@ class CONTENT_EXPORT IndexedDBDatabaseCallbacks
virtual void OnAbort(const IndexedDBTransaction& transaction,
const IndexedDBDatabaseError& error);
virtual void OnComplete(const IndexedDBTransaction& transaction);
- virtual void OnDatabaseChange(
- ::indexed_db::mojom::ObserverChangesPtr changes);
+ virtual void OnDatabaseChange(blink::mojom::IDBObserverChangesPtr changes);
protected:
virtual ~IndexedDBDatabaseCallbacks();
diff --git a/chromium/content/browser/indexed_db/indexed_db_database_unittest.cc b/chromium/content/browser/indexed_db/indexed_db_database_unittest.cc
index fd5e26400ab..7a8db895399 100644
--- a/chromium/content/browser/indexed_db/indexed_db_database_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_database_unittest.cc
@@ -32,6 +32,10 @@
#include "testing/gtest/include/gtest/gtest.h"
using base::ASCIIToUTF16;
+using blink::IndexedDBDatabaseMetadata;
+using blink::IndexedDBIndexKeys;
+using blink::IndexedDBKey;
+using blink::IndexedDBKeyPath;
namespace {
const int kFakeChildProcessId = 0;
@@ -451,12 +455,11 @@ TEST_F(IndexedDBDatabaseOperationTest, CreatePutDelete) {
// Put is asynchronous
IndexedDBValue value("value1", std::vector<IndexedDBBlobInfo>());
- std::vector<std::unique_ptr<storage::BlobDataHandle>> handles;
std::unique_ptr<IndexedDBKey> key(std::make_unique<IndexedDBKey>("key"));
std::vector<IndexedDBIndexKeys> index_keys;
scoped_refptr<MockIndexedDBCallbacks> request(
new MockIndexedDBCallbacks(false));
- db_->Put(transaction_, store_id, &value, &handles, std::move(key),
+ db_->Put(transaction_, store_id, &value, std::move(key),
blink::kWebIDBPutModeAddOnly, request, index_keys);
// Deletion is asynchronous.
diff --git a/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.cc b/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.cc
index 034a34e0465..e876744e8dc 100644
--- a/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.cc
@@ -32,19 +32,19 @@ bool IsValidOrigin(const url::Origin& origin) {
return !origin.unique();
}
-::indexed_db::mojom::Status GetIndexedDBStatus(leveldb::Status status) {
+blink::mojom::IDBStatus GetIndexedDBStatus(leveldb::Status status) {
if (status.ok())
- return ::indexed_db::mojom::Status::OK;
+ return blink::mojom::IDBStatus::OK;
else if (status.IsNotFound())
- return ::indexed_db::mojom::Status::NotFound;
+ return blink::mojom::IDBStatus::NotFound;
else if (status.IsCorruption())
- return ::indexed_db::mojom::Status::Corruption;
+ return blink::mojom::IDBStatus::Corruption;
else if (status.IsNotSupportedError())
- return ::indexed_db::mojom::Status::NotSupported;
+ return blink::mojom::IDBStatus::NotSupported;
else if (status.IsInvalidArgument())
- return ::indexed_db::mojom::Status::InvalidArgument;
+ return blink::mojom::IDBStatus::InvalidArgument;
else
- return ::indexed_db::mojom::Status::IOError;
+ return blink::mojom::IDBStatus::IOError;
}
void DoCallCompactionStatusCallback(
@@ -142,19 +142,19 @@ IndexedDBDispatcherHost::~IndexedDBDispatcherHost() {
}
void IndexedDBDispatcherHost::AddBinding(
- ::indexed_db::mojom::FactoryAssociatedRequest request) {
+ blink::mojom::IDBFactoryRequest request) {
bindings_.AddBinding(this, std::move(request));
}
void IndexedDBDispatcherHost::AddDatabaseBinding(
- std::unique_ptr<::indexed_db::mojom::Database> database,
- ::indexed_db::mojom::DatabaseAssociatedRequest request) {
+ std::unique_ptr<blink::mojom::IDBDatabase> database,
+ blink::mojom::IDBDatabaseAssociatedRequest request) {
database_bindings_.AddBinding(std::move(database), std::move(request));
}
void IndexedDBDispatcherHost::AddCursorBinding(
- std::unique_ptr<::indexed_db::mojom::Cursor> cursor,
- ::indexed_db::mojom::CursorAssociatedRequest request) {
+ std::unique_ptr<blink::mojom::IDBCursor> cursor,
+ blink::mojom::IDBCursorAssociatedRequest request) {
cursor_bindings_.AddBinding(std::move(cursor), std::move(request));
}
@@ -169,7 +169,7 @@ void IndexedDBDispatcherHost::RenderProcessExited(
}
void IndexedDBDispatcherHost::GetDatabaseNames(
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks_info,
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info,
const url::Origin& origin) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -187,9 +187,8 @@ void IndexedDBDispatcherHost::GetDatabaseNames(
}
void IndexedDBDispatcherHost::Open(
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks_info,
- ::indexed_db::mojom::DatabaseCallbacksAssociatedPtrInfo
- database_callbacks_info,
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info,
+ blink::mojom::IDBDatabaseCallbacksAssociatedPtrInfo database_callbacks_info,
const url::Origin& origin,
const base::string16& name,
int64_t version,
@@ -215,7 +214,7 @@ void IndexedDBDispatcherHost::Open(
}
void IndexedDBDispatcherHost::DeleteDatabase(
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks_info,
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info,
const url::Origin& origin,
const base::string16& name,
bool force_close) {
diff --git a/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.h b/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.h
index dc177044771..099b0315498 100644
--- a/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.h
+++ b/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.h
@@ -17,12 +17,12 @@
#include "base/memory/ref_counted.h"
#include "content/browser/blob_storage/chrome_blob_storage_context.h"
#include "content/common/content_export.h"
-#include "content/common/indexed_db/indexed_db.mojom.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host_observer.h"
#include "mojo/public/cpp/bindings/associated_binding_set.h"
#include "mojo/public/cpp/bindings/strong_associated_binding_set.h"
#include "net/url_request/url_request_context_getter.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
namespace base {
class SequencedTaskRunner;
@@ -39,7 +39,7 @@ class IndexedDBContextImpl;
// Constructed on UI thread, expects all other calls (including destruction) on
// IO thread.
class CONTENT_EXPORT IndexedDBDispatcherHost
- : public ::indexed_db::mojom::Factory,
+ : public blink::mojom::IDBFactory,
public RenderProcessHostObserver {
public:
// Only call the constructor from the UI thread.
@@ -49,14 +49,13 @@ class CONTENT_EXPORT IndexedDBDispatcherHost
scoped_refptr<IndexedDBContextImpl> indexed_db_context,
scoped_refptr<ChromeBlobStorageContext> blob_storage_context);
- void AddBinding(::indexed_db::mojom::FactoryAssociatedRequest request);
+ void AddBinding(blink::mojom::IDBFactoryRequest request);
- void AddDatabaseBinding(
- std::unique_ptr<::indexed_db::mojom::Database> database,
- ::indexed_db::mojom::DatabaseAssociatedRequest request);
+ void AddDatabaseBinding(std::unique_ptr<blink::mojom::IDBDatabase> database,
+ blink::mojom::IDBDatabaseAssociatedRequest request);
- void AddCursorBinding(std::unique_ptr<::indexed_db::mojom::Cursor> cursor,
- ::indexed_db::mojom::CursorAssociatedRequest request);
+ void AddCursorBinding(std::unique_ptr<blink::mojom::IDBCursor> cursor,
+ blink::mojom::IDBCursorAssociatedRequest request);
// A shortcut for accessing our context.
IndexedDBContextImpl* context() const { return indexed_db_context_.get(); }
@@ -84,19 +83,19 @@ class CONTENT_EXPORT IndexedDBDispatcherHost
~IndexedDBDispatcherHost() override;
- // indexed_db::mojom::Factory implementation:
+ // blink::mojom::IDBFactory implementation:
void GetDatabaseNames(
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks_info,
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info,
const url::Origin& origin) override;
- void Open(::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks_info,
- ::indexed_db::mojom::DatabaseCallbacksAssociatedPtrInfo
+ void Open(blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info,
+ blink::mojom::IDBDatabaseCallbacksAssociatedPtrInfo
database_callbacks_info,
const url::Origin& origin,
const base::string16& name,
int64_t version,
int64_t transaction_id) override;
void DeleteDatabase(
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo callbacks_info,
+ blink::mojom::IDBCallbacksAssociatedPtrInfo callbacks_info,
const url::Origin& origin,
const base::string16& name,
bool force_close) override;
@@ -117,13 +116,12 @@ class CONTENT_EXPORT IndexedDBDispatcherHost
// Used to set file permissions for blob storage.
const int ipc_process_id_;
- mojo::AssociatedBindingSet<::indexed_db::mojom::Factory> bindings_;
+ mojo::BindingSet<blink::mojom::IDBFactory> bindings_;
- mojo::StrongAssociatedBindingSet<::indexed_db::mojom::Database>
+ mojo::StrongAssociatedBindingSet<blink::mojom::IDBDatabase>
database_bindings_;
- mojo::StrongAssociatedBindingSet<::indexed_db::mojom::Cursor>
- cursor_bindings_;
+ mojo::StrongAssociatedBindingSet<blink::mojom::IDBCursor> cursor_bindings_;
IDBSequenceHelper* idb_helper_;
diff --git a/chromium/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc b/chromium/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
index ff718191b32..960febdf847 100644
--- a/chromium/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
@@ -20,7 +20,6 @@
#include "content/browser/indexed_db/indexed_db_pending_connection.h"
#include "content/browser/indexed_db/mock_mojo_indexed_db_callbacks.h"
#include "content/browser/indexed_db/mock_mojo_indexed_db_database_callbacks.h"
-#include "content/common/indexed_db/indexed_db.mojom.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_utils.h"
@@ -32,22 +31,24 @@
#include "storage/browser/test/mock_special_storage_policy.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_exception.h"
#include "url/origin.h"
-using indexed_db::mojom::Callbacks;
-using indexed_db::mojom::CallbacksAssociatedPtrInfo;
-using indexed_db::mojom::DatabaseAssociatedPtr;
-using indexed_db::mojom::DatabaseAssociatedPtrInfo;
-using indexed_db::mojom::DatabaseAssociatedRequest;
-using indexed_db::mojom::DatabaseCallbacks;
-using indexed_db::mojom::DatabaseCallbacksAssociatedPtrInfo;
-using indexed_db::mojom::Factory;
-using indexed_db::mojom::FactoryAssociatedPtr;
-using indexed_db::mojom::FactoryAssociatedRequest;
-using indexed_db::mojom::KeyPath;
-using indexed_db::mojom::Value;
-using indexed_db::mojom::ValuePtr;
+using blink::mojom::IDBValue;
+using blink::mojom::IDBValuePtr;
+using blink::IndexedDBDatabaseMetadata;
+using blink::IndexedDBIndexKeys;
+using blink::IndexedDBKey;
+using blink::mojom::IDBCallbacks;
+using blink::mojom::IDBCallbacksAssociatedPtrInfo;
+using blink::mojom::IDBDatabaseAssociatedPtr;
+using blink::mojom::IDBDatabaseAssociatedPtrInfo;
+using blink::mojom::IDBDatabaseAssociatedRequest;
+using blink::mojom::IDBDatabaseCallbacks;
+using blink::mojom::IDBDatabaseCallbacksAssociatedPtrInfo;
+using blink::mojom::IDBFactory;
+using blink::mojom::IDBFactoryPtr;
using mojo::StrongAssociatedBindingPtr;
using testing::_;
using testing::StrictMock;
@@ -103,7 +104,7 @@ struct TestDatabaseConnection {
new StrictMock<MockMojoIndexedDBDatabaseCallbacks>()){};
~TestDatabaseConnection() {}
- void Open(Factory* factory) {
+ void Open(IDBFactory* factory) {
factory->Open(open_callbacks->CreateInterfacePtrAndBind(),
connection_callbacks->CreateInterfacePtrAndBind(), origin,
db_name, version, upgrade_txn_id);
@@ -114,7 +115,7 @@ struct TestDatabaseConnection {
int64_t version;
int64_t upgrade_txn_id;
- DatabaseAssociatedPtr database;
+ IDBDatabaseAssociatedPtr database;
std::unique_ptr<MockMojoIndexedDBCallbacks> open_callbacks;
std::unique_ptr<MockMojoIndexedDBDatabaseCallbacks> connection_callbacks;
@@ -124,8 +125,8 @@ struct TestDatabaseConnection {
};
void StatusCallback(const base::Closure& callback,
- ::indexed_db::mojom::Status* status_out,
- ::indexed_db::mojom::Status status) {
+ blink::mojom::IDBStatus* status_out,
+ blink::mojom::IDBStatus status) {
*status_out = status;
callback.Run();
}
@@ -184,9 +185,7 @@ class IndexedDBDispatcherHostTest : public testing::Test {
}
void SetUp() override {
- FactoryAssociatedRequest request =
- ::mojo::MakeRequestAssociatedWithDedicatedPipe(&idb_mojo_factory_);
- host_->AddBinding(std::move(request));
+ host_->AddBinding(::mojo::MakeRequest(&idb_mojo_factory_));
}
protected:
@@ -199,7 +198,7 @@ class IndexedDBDispatcherHostTest : public testing::Test {
scoped_refptr<IndexedDBContextImpl> context_impl_;
std::unique_ptr<IndexedDBDispatcherHost, BrowserThread::DeleteOnIOThread>
host_;
- FactoryAssociatedPtr idb_mojo_factory_;
+ IDBFactoryPtr idb_mojo_factory_;
DISALLOW_COPY_AND_ASSIGN(IndexedDBDispatcherHostTest);
};
@@ -212,7 +211,7 @@ TEST_F(IndexedDBDispatcherHostTest, CloseConnectionBeforeUpgrade) {
base::UTF8ToUTF16(kDatabaseName),
kDBVersion, kTransactionId);
IndexedDBDatabaseMetadata metadata;
- DatabaseAssociatedPtrInfo database_info;
+ IDBDatabaseAssociatedPtrInfo database_info;
base::RunLoop loop;
EXPECT_CALL(
*connection.open_callbacks,
@@ -243,7 +242,7 @@ TEST_F(IndexedDBDispatcherHostTest, CloseAfterUpgrade) {
kDBVersion, kTransactionId);
IndexedDBDatabaseMetadata metadata;
- DatabaseAssociatedPtrInfo database_info;
+ IDBDatabaseAssociatedPtrInfo database_info;
{
base::RunLoop loop;
EXPECT_CALL(
@@ -282,7 +281,7 @@ TEST_F(IndexedDBDispatcherHostTest, CloseAfterUpgrade) {
ASSERT_TRUE(connection.database.is_bound());
connection.database->CreateObjectStore(kTransactionId, kObjectStoreId,
base::UTF8ToUTF16(kObjectStoreName),
- content::IndexedDBKeyPath(), false);
+ blink::IndexedDBKeyPath(), false);
connection.database->Commit(kTransactionId);
loop.Run();
}
@@ -298,7 +297,7 @@ TEST_F(IndexedDBDispatcherHostTest, OpenNewConnectionWhileUpgrading) {
TestDatabaseConnection connection1(url::Origin::Create(GURL(kOrigin)),
base::UTF8ToUTF16(kDatabaseName),
kDBVersion, kTransactionId);
- DatabaseAssociatedPtrInfo database_info1;
+ IDBDatabaseAssociatedPtrInfo database_info1;
{
base::RunLoop loop;
IndexedDBDatabaseMetadata metadata;
@@ -318,7 +317,7 @@ TEST_F(IndexedDBDispatcherHostTest, OpenNewConnectionWhileUpgrading) {
connection1.database.Bind(std::move(database_info1));
// Open connection 2, but expect that we won't be called back.
- DatabaseAssociatedPtrInfo database_info2;
+ IDBDatabaseAssociatedPtrInfo database_info2;
IndexedDBDatabaseMetadata metadata2;
TestDatabaseConnection connection2(url::Origin::Create(GURL(kOrigin)),
base::UTF8ToUTF16(kDatabaseName),
@@ -350,7 +349,7 @@ TEST_F(IndexedDBDispatcherHostTest, OpenNewConnectionWhileUpgrading) {
ASSERT_TRUE(connection1.database.is_bound());
connection1.database->CreateObjectStore(kTransactionId, kObjectStoreId,
base::UTF8ToUTF16(kObjectStoreName),
- content::IndexedDBKeyPath(), false);
+ blink::IndexedDBKeyPath(), false);
connection1.database->Commit(kTransactionId);
loop.Run();
}
@@ -372,7 +371,7 @@ TEST_F(IndexedDBDispatcherHostTest, PutWithInvalidBlob) {
kDBVersion, kTransactionId);
IndexedDBDatabaseMetadata metadata;
- DatabaseAssociatedPtrInfo database_info;
+ IDBDatabaseAssociatedPtrInfo database_info;
{
base::RunLoop loop;
EXPECT_CALL(
@@ -422,19 +421,19 @@ TEST_F(IndexedDBDispatcherHostTest, PutWithInvalidBlob) {
ASSERT_TRUE(connection.database.is_bound());
connection.database->CreateObjectStore(kTransactionId, kObjectStoreId,
base::UTF8ToUTF16(kObjectStoreName),
- content::IndexedDBKeyPath(), false);
+ blink::IndexedDBKeyPath(), false);
// Call Put with an invalid blob.
- std::vector<::indexed_db::mojom::BlobInfoPtr> blobs;
+ std::vector<blink::mojom::IDBBlobInfoPtr> blobs;
blink::mojom::BlobPtrInfo blob;
// Ignore the result of MakeRequest, to end up with an invalid blob.
mojo::MakeRequest(&blob);
- blobs.push_back(::indexed_db::mojom::BlobInfo::New(
+ blobs.push_back(blink::mojom::IDBBlobInfo::New(
std::move(blob), "fakeUUID", base::string16(), 100, nullptr));
connection.database->Put(kTransactionId, kObjectStoreId,
- Value::New("hello", std::move(blobs)),
- content::IndexedDBKey(base::UTF8ToUTF16("hello")),
+ IDBValue::New("hello", std::move(blobs)),
+ IndexedDBKey(base::UTF8ToUTF16("hello")),
blink::kWebIDBPutModeAddOnly,
- std::vector<content::IndexedDBIndexKeys>(),
+ std::vector<IndexedDBIndexKeys>(),
put_callbacks->CreateInterfacePtrAndBind());
connection.database->Commit(kTransactionId);
loop.Run();
@@ -450,7 +449,7 @@ TEST_F(IndexedDBDispatcherHostTest, CompactDatabaseWithConnection) {
base::UTF8ToUTF16(kDatabaseName),
kDBVersion, kTransactionId);
IndexedDBDatabaseMetadata metadata;
- DatabaseAssociatedPtrInfo database_info;
+ IDBDatabaseAssociatedPtrInfo database_info;
{
base::RunLoop loop;
EXPECT_CALL(
@@ -473,8 +472,7 @@ TEST_F(IndexedDBDispatcherHostTest, CompactDatabaseWithConnection) {
connection.database.Bind(std::move(database_info));
- ::indexed_db::mojom::Status callback_result =
- ::indexed_db::mojom::Status::IOError;
+ blink::mojom::IDBStatus callback_result = blink::mojom::IDBStatus::IOError;
{
::testing::InSequence dummy;
base::RunLoop loop;
@@ -497,7 +495,7 @@ TEST_F(IndexedDBDispatcherHostTest, CompactDatabaseWithConnection) {
loop.Run();
}
- EXPECT_EQ(::indexed_db::mojom::Status::OK, callback_result);
+ EXPECT_EQ(blink::mojom::IDBStatus::OK, callback_result);
}
TEST_F(IndexedDBDispatcherHostTest, CompactDatabaseWhileDoingTransaction) {
@@ -511,7 +509,7 @@ TEST_F(IndexedDBDispatcherHostTest, CompactDatabaseWhileDoingTransaction) {
base::UTF8ToUTF16(kDatabaseName),
kDBVersion, kTransactionId);
IndexedDBDatabaseMetadata metadata;
- DatabaseAssociatedPtrInfo database_info;
+ IDBDatabaseAssociatedPtrInfo database_info;
{
base::RunLoop loop;
EXPECT_CALL(
@@ -534,8 +532,7 @@ TEST_F(IndexedDBDispatcherHostTest, CompactDatabaseWhileDoingTransaction) {
connection.database.Bind(std::move(database_info));
- ::indexed_db::mojom::Status callback_result =
- ::indexed_db::mojom::Status::IOError;
+ blink::mojom::IDBStatus callback_result = blink::mojom::IDBStatus::IOError;
{
::testing::InSequence dummy;
base::RunLoop loop;
@@ -558,14 +555,14 @@ TEST_F(IndexedDBDispatcherHostTest, CompactDatabaseWhileDoingTransaction) {
ASSERT_TRUE(connection.database.is_bound());
connection.database->CreateObjectStore(kTransactionId, kObjectStoreId,
base::UTF8ToUTF16(kObjectStoreName),
- content::IndexedDBKeyPath(), false);
+ blink::IndexedDBKeyPath(), false);
idb_mojo_factory_->AbortTransactionsAndCompactDatabase(
origin, base::BindOnce(&StatusCallback, std::move(quit_closure),
&callback_result));
loop.Run();
}
- EXPECT_EQ(::indexed_db::mojom::Status::OK, callback_result);
+ EXPECT_EQ(blink::mojom::IDBStatus::OK, callback_result);
}
TEST_F(IndexedDBDispatcherHostTest, CompactDatabaseWhileUpgrading) {
@@ -577,7 +574,7 @@ TEST_F(IndexedDBDispatcherHostTest, CompactDatabaseWhileUpgrading) {
base::UTF8ToUTF16(kDatabaseName),
kDBVersion, kTransactionId);
IndexedDBDatabaseMetadata metadata;
- DatabaseAssociatedPtrInfo database_info;
+ IDBDatabaseAssociatedPtrInfo database_info;
{
base::RunLoop loop;
EXPECT_CALL(
@@ -600,8 +597,7 @@ TEST_F(IndexedDBDispatcherHostTest, CompactDatabaseWhileUpgrading) {
connection.database.Bind(std::move(database_info));
- ::indexed_db::mojom::Status callback_result =
- ::indexed_db::mojom::Status::IOError;
+ blink::mojom::IDBStatus callback_result = blink::mojom::IDBStatus::IOError;
{
::testing::InSequence dummy;
base::RunLoop loop;
@@ -628,7 +624,7 @@ TEST_F(IndexedDBDispatcherHostTest, CompactDatabaseWhileUpgrading) {
loop.Run();
}
- EXPECT_EQ(::indexed_db::mojom::Status::OK, callback_result);
+ EXPECT_EQ(blink::mojom::IDBStatus::OK, callback_result);
}
TEST_F(IndexedDBDispatcherHostTest,
@@ -641,7 +637,7 @@ TEST_F(IndexedDBDispatcherHostTest,
base::UTF8ToUTF16(kDatabaseName),
kDBVersion, kTransactionId);
IndexedDBDatabaseMetadata metadata;
- DatabaseAssociatedPtrInfo database_info;
+ IDBDatabaseAssociatedPtrInfo database_info;
{
base::RunLoop loop;
EXPECT_CALL(
@@ -664,8 +660,7 @@ TEST_F(IndexedDBDispatcherHostTest,
connection.database.Bind(std::move(database_info));
- ::indexed_db::mojom::Status callback_result =
- ::indexed_db::mojom::Status::IOError;
+ blink::mojom::IDBStatus callback_result = blink::mojom::IDBStatus::IOError;
{
::testing::InSequence dummy;
base::RunLoop loop;
@@ -691,7 +686,7 @@ TEST_F(IndexedDBDispatcherHostTest,
loop.Run();
}
- EXPECT_EQ(::indexed_db::mojom::Status::OK, callback_result);
+ EXPECT_EQ(blink::mojom::IDBStatus::OK, callback_result);
}
TEST_F(IndexedDBDispatcherHostTest, AbortTransactionsWhileDoingTransaction) {
@@ -705,7 +700,7 @@ TEST_F(IndexedDBDispatcherHostTest, AbortTransactionsWhileDoingTransaction) {
base::UTF8ToUTF16(kDatabaseName),
kDBVersion, kTransactionId);
IndexedDBDatabaseMetadata metadata;
- DatabaseAssociatedPtrInfo database_info;
+ IDBDatabaseAssociatedPtrInfo database_info;
{
base::RunLoop loop;
EXPECT_CALL(
@@ -728,8 +723,7 @@ TEST_F(IndexedDBDispatcherHostTest, AbortTransactionsWhileDoingTransaction) {
connection.database.Bind(std::move(database_info));
- ::indexed_db::mojom::Status callback_result =
- ::indexed_db::mojom::Status::IOError;
+ blink::mojom::IDBStatus callback_result = blink::mojom::IDBStatus::IOError;
{
::testing::InSequence dummy;
base::RunLoop loop;
@@ -752,14 +746,14 @@ TEST_F(IndexedDBDispatcherHostTest, AbortTransactionsWhileDoingTransaction) {
ASSERT_TRUE(connection.database.is_bound());
connection.database->CreateObjectStore(kTransactionId, kObjectStoreId,
base::UTF8ToUTF16(kObjectStoreName),
- content::IndexedDBKeyPath(), false);
+ blink::IndexedDBKeyPath(), false);
idb_mojo_factory_->AbortTransactionsForDatabase(
origin, base::BindOnce(&StatusCallback, std::move(quit_closure),
&callback_result));
loop.Run();
}
- EXPECT_EQ(::indexed_db::mojom::Status::OK, callback_result);
+ EXPECT_EQ(blink::mojom::IDBStatus::OK, callback_result);
}
TEST_F(IndexedDBDispatcherHostTest, AbortTransactionsWhileUpgrading) {
@@ -771,7 +765,7 @@ TEST_F(IndexedDBDispatcherHostTest, AbortTransactionsWhileUpgrading) {
base::UTF8ToUTF16(kDatabaseName),
kDBVersion, kTransactionId);
IndexedDBDatabaseMetadata metadata;
- DatabaseAssociatedPtrInfo database_info;
+ IDBDatabaseAssociatedPtrInfo database_info;
{
base::RunLoop loop;
EXPECT_CALL(
@@ -794,8 +788,7 @@ TEST_F(IndexedDBDispatcherHostTest, AbortTransactionsWhileUpgrading) {
connection.database.Bind(std::move(database_info));
- ::indexed_db::mojom::Status callback_result =
- ::indexed_db::mojom::Status::IOError;
+ blink::mojom::IDBStatus callback_result = blink::mojom::IDBStatus::IOError;
{
::testing::InSequence dummy;
base::RunLoop loop;
@@ -822,7 +815,7 @@ TEST_F(IndexedDBDispatcherHostTest, AbortTransactionsWhileUpgrading) {
loop.Run();
}
- EXPECT_EQ(::indexed_db::mojom::Status::OK, callback_result);
+ EXPECT_EQ(blink::mojom::IDBStatus::OK, callback_result);
}
// Flaky: crbug.com/772067
@@ -846,7 +839,7 @@ TEST_F(IndexedDBDispatcherHostTest, DISABLED_NotifyIndexedDBListChanged) {
base::UTF8ToUTF16(kDatabaseName),
kDBVersion1, kTransactionId1);
IndexedDBDatabaseMetadata metadata1;
- DatabaseAssociatedPtrInfo database_info1;
+ IDBDatabaseAssociatedPtrInfo database_info1;
EXPECT_EQ(0, observer.notify_list_changed_count);
{
base::RunLoop loop;
@@ -886,11 +879,10 @@ TEST_F(IndexedDBDispatcherHostTest, DISABLED_NotifyIndexedDBListChanged) {
ASSERT_TRUE(connection1.database.is_bound());
connection1.database->CreateObjectStore(kTransactionId1, kObjectStoreId,
base::UTF8ToUTF16(kObjectStoreName),
- content::IndexedDBKeyPath(), false);
+ blink::IndexedDBKeyPath(), false);
connection1.database->CreateIndex(kTransactionId1, kObjectStoreId, kIndexId,
base::UTF8ToUTF16(kIndexName),
- content::IndexedDBKeyPath(), false,
- false);
+ blink::IndexedDBKeyPath(), false, false);
connection1.database->Commit(kTransactionId1);
loop.Run();
}
@@ -902,7 +894,7 @@ TEST_F(IndexedDBDispatcherHostTest, DISABLED_NotifyIndexedDBListChanged) {
base::UTF8ToUTF16(kDatabaseName),
kDBVersion2, kTransactionId2);
IndexedDBDatabaseMetadata metadata2;
- DatabaseAssociatedPtrInfo database_info2;
+ IDBDatabaseAssociatedPtrInfo database_info2;
{
::testing::InSequence dummy;
base::RunLoop loop;
@@ -952,7 +944,7 @@ TEST_F(IndexedDBDispatcherHostTest, DISABLED_NotifyIndexedDBListChanged) {
base::UTF8ToUTF16(kDatabaseName),
kDBVersion3, kTransactionId3);
IndexedDBDatabaseMetadata metadata3;
- DatabaseAssociatedPtrInfo database_info3;
+ IDBDatabaseAssociatedPtrInfo database_info3;
{
::testing::InSequence dummy;
base::RunLoop loop;
@@ -1014,7 +1006,7 @@ TEST_F(IndexedDBDispatcherHostTest, NotifyIndexedDBContentChanged) {
base::UTF8ToUTF16(kDatabaseName),
kDBVersion1, kTransactionId1);
IndexedDBDatabaseMetadata metadata1;
- DatabaseAssociatedPtrInfo database_info1;
+ IDBDatabaseAssociatedPtrInfo database_info1;
EXPECT_EQ(0, observer.notify_list_changed_count);
EXPECT_EQ(0, observer.notify_content_changed_count);
{
@@ -1061,14 +1053,13 @@ TEST_F(IndexedDBDispatcherHostTest, NotifyIndexedDBContentChanged) {
ASSERT_TRUE(connection1.database.is_bound());
connection1.database->CreateObjectStore(kTransactionId1, kObjectStoreId,
base::UTF8ToUTF16(kObjectStoreName),
- content::IndexedDBKeyPath(), false);
+ blink::IndexedDBKeyPath(), false);
connection1.database->Put(
kTransactionId1, kObjectStoreId,
- ::indexed_db::mojom::Value::New(
- "value", std::vector<::indexed_db::mojom::BlobInfoPtr>()),
- content::IndexedDBKey(base::UTF8ToUTF16("key")),
- blink::kWebIDBPutModeAddOnly,
- std::vector<content::IndexedDBIndexKeys>(),
+ blink::mojom::IDBValue::New(
+ "value", std::vector<blink::mojom::IDBBlobInfoPtr>()),
+ IndexedDBKey(base::UTF8ToUTF16("key")), blink::kWebIDBPutModeAddOnly,
+ std::vector<IndexedDBIndexKeys>(),
put_callbacks->CreateInterfacePtrAndBind());
connection1.database->Commit(kTransactionId1);
loop.Run();
@@ -1082,7 +1073,7 @@ TEST_F(IndexedDBDispatcherHostTest, NotifyIndexedDBContentChanged) {
base::UTF8ToUTF16(kDatabaseName),
kDBVersion2, kTransactionId2);
IndexedDBDatabaseMetadata metadata2;
- DatabaseAssociatedPtrInfo database_info2;
+ IDBDatabaseAssociatedPtrInfo database_info2;
{
::testing::InSequence dummy;
base::RunLoop loop;
diff --git a/chromium/content/browser/indexed_db/indexed_db_factory.h b/chromium/content/browser/indexed_db/indexed_db_factory.h
index c4edb3f5d3f..d4e62a6a9f7 100644
--- a/chromium/content/browser/indexed_db/indexed_db_factory.h
+++ b/chromium/content/browser/indexed_db/indexed_db_factory.h
@@ -79,6 +79,7 @@ class CONTENT_EXPORT IndexedDBFactory
const url::Origin& origin) const = 0;
virtual void ForceClose(const url::Origin& origin) = 0;
+ virtual void ForceSchemaDowngrade(const url::Origin& origin) = 0;
// Called by the IndexedDBContext destructor so the factory can do cleanup.
virtual void ContextDestroyed() = 0;
diff --git a/chromium/content/browser/indexed_db/indexed_db_factory_impl.cc b/chromium/content/browser/indexed_db/indexed_db_factory_impl.cc
index cd079aedd08..404b2556081 100644
--- a/chromium/content/browser/indexed_db/indexed_db_factory_impl.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_factory_impl.cc
@@ -191,7 +191,8 @@ void IndexedDBFactoryImpl::ReleaseBackingStore(const Origin& origin,
DCHECK(!backing_store_map_[origin]->close_timer()->IsRunning());
backing_store_map_[origin]->close_timer()->Start(
FROM_HERE, base::TimeDelta::FromSeconds(kBackingStoreGracePeriodSeconds),
- base::Bind(&IndexedDBFactoryImpl::MaybeStartPreCloseTasks, this, origin));
+ base::BindOnce(&IndexedDBFactoryImpl::MaybeStartPreCloseTasks, this,
+ origin));
}
void IndexedDBFactoryImpl::MaybeStartPreCloseTasks(const Origin& origin) {
@@ -337,6 +338,17 @@ void IndexedDBFactoryImpl::ForceClose(const Origin& origin) {
ReleaseBackingStore(origin, true /* immediate */);
}
+void IndexedDBFactoryImpl::ForceSchemaDowngrade(const Origin& origin) {
+ OriginDBs range = GetOpenDatabasesForOrigin(origin);
+
+ while (range.first != range.second) {
+ IndexedDBDatabase* db = range.first->second;
+ ++range.first;
+ leveldb::Status s = db->backing_store()->RevertSchemaToV2();
+ DLOG_IF(ERROR, !s.ok()) << "Unable to force downgrade: " << s.ToString();
+ }
+}
+
void IndexedDBFactoryImpl::ContextDestroyed() {
// Timers on backing stores hold a reference to this factory. When the
// context (which nominally owns this factory) is destroyed during thread
diff --git a/chromium/content/browser/indexed_db/indexed_db_factory_impl.h b/chromium/content/browser/indexed_db/indexed_db_factory_impl.h
index 3935f9b319f..b78429e2e2c 100644
--- a/chromium/content/browser/indexed_db/indexed_db_factory_impl.h
+++ b/chromium/content/browser/indexed_db/indexed_db_factory_impl.h
@@ -87,6 +87,7 @@ class CONTENT_EXPORT IndexedDBFactoryImpl : public IndexedDBFactory {
OriginDBs GetOpenDatabasesForOrigin(const url::Origin& origin) const override;
void ForceClose(const url::Origin& origin) override;
+ void ForceSchemaDowngrade(const url::Origin& origin) override;
// Called by the IndexedDBContext destructor so the factory can do cleanup.
void ContextDestroyed() override;
diff --git a/chromium/content/browser/indexed_db/indexed_db_factory_unittest.cc b/chromium/content/browser/indexed_db/indexed_db_factory_unittest.cc
index 0031ef8024b..849666e7be5 100644
--- a/chromium/content/browser/indexed_db/indexed_db_factory_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_factory_unittest.cc
@@ -27,12 +27,13 @@
#include "content/public/test/test_utils.h"
#include "storage/browser/test/mock_quota_manager_proxy.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
#include "third_party/blink/public/platform/modules/indexeddb/web_idb_database_exception.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_types.h"
#include "url/gurl.h"
#include "url/origin.h"
using base::ASCIIToUTF16;
+using blink::IndexedDBDatabaseMetadata;
using url::Origin;
namespace content {
@@ -720,7 +721,7 @@ class UpgradeNeededCallbacks : public MockIndexedDBCallbacks {
void OnUpgradeNeeded(int64_t old_version,
std::unique_ptr<IndexedDBConnection> connection,
- const content::IndexedDBDatabaseMetadata& metadata,
+ const IndexedDBDatabaseMetadata& metadata,
const IndexedDBDataLossInfo& data_loss_info) override {
connection_ = std::move(connection);
}
@@ -854,7 +855,7 @@ class DataLossCallbacks final : public MockIndexedDBCallbacks {
}
void OnUpgradeNeeded(int64_t old_version,
std::unique_ptr<IndexedDBConnection> connection,
- const content::IndexedDBDatabaseMetadata& metadata,
+ const IndexedDBDatabaseMetadata& metadata,
const IndexedDBDataLossInfo& data_loss) final {
connection_ = std::move(connection);
data_loss_ = data_loss.status;
diff --git a/chromium/content/browser/indexed_db/indexed_db_fake_backing_store.cc b/chromium/content/browser/indexed_db/indexed_db_fake_backing_store.cc
index 46b713fb53a..7477de76328 100644
--- a/chromium/content/browser/indexed_db/indexed_db_fake_backing_store.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_fake_backing_store.cc
@@ -9,6 +9,12 @@
#include "net/url_request/url_request_context_getter.h"
namespace content {
+namespace {
+
+using blink::IndexedDBKey;
+using blink::IndexedDBKeyRange;
+
+} // namespace
IndexedDBFakeBackingStore::IndexedDBFakeBackingStore()
: IndexedDBBackingStore(nullptr /* indexed_db_factory */,
@@ -41,7 +47,6 @@ leveldb::Status IndexedDBFakeBackingStore::PutRecord(
int64_t object_store_id,
const IndexedDBKey& key,
IndexedDBValue* value,
- std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles,
RecordIdentifier* record) {
return leveldb::Status::OK();
}
diff --git a/chromium/content/browser/indexed_db/indexed_db_fake_backing_store.h b/chromium/content/browser/indexed_db/indexed_db_fake_backing_store.h
index 42ab318bfd9..3f8337cfd6f 100644
--- a/chromium/content/browser/indexed_db/indexed_db_fake_backing_store.h
+++ b/chromium/content/browser/indexed_db/indexed_db_fake_backing_store.h
@@ -12,11 +12,16 @@
#include "base/macros.h"
#include "content/browser/indexed_db/indexed_db_backing_store.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
namespace base {
class SequencedTaskRunner;
}
+namespace blink {
+class IndexedDBKeyRange;
+}
+
namespace content {
class IndexedDBFactory;
@@ -28,14 +33,12 @@ class IndexedDBFakeBackingStore : public IndexedDBBackingStore {
base::SequencedTaskRunner* task_runner);
leveldb::Status DeleteDatabase(const base::string16& name) override;
- leveldb::Status PutRecord(
- IndexedDBBackingStore::Transaction* transaction,
- int64_t database_id,
- int64_t object_store_id,
- const IndexedDBKey& key,
- IndexedDBValue* value,
- std::vector<std::unique_ptr<storage::BlobDataHandle>>* handles,
- RecordIdentifier* record) override;
+ leveldb::Status PutRecord(IndexedDBBackingStore::Transaction* transaction,
+ int64_t database_id,
+ int64_t object_store_id,
+ const blink::IndexedDBKey& key,
+ IndexedDBValue* value,
+ RecordIdentifier* record) override;
leveldb::Status ClearObjectStore(Transaction*,
int64_t database_id,
@@ -59,7 +62,7 @@ class IndexedDBFakeBackingStore : public IndexedDBBackingStore {
Transaction*,
int64_t database_id,
int64_t object_store_id,
- const IndexedDBKey&,
+ const blink::IndexedDBKey&,
RecordIdentifier* found_record_identifier,
bool* found) override;
@@ -71,37 +74,39 @@ class IndexedDBFakeBackingStore : public IndexedDBBackingStore {
int64_t database_id,
int64_t object_store_id,
int64_t index_id,
- const IndexedDBKey&,
+ const blink::IndexedDBKey&,
const RecordIdentifier&) override;
void ReportBlobUnused(int64_t database_id, int64_t blob_key) override;
std::unique_ptr<Cursor> OpenObjectStoreKeyCursor(
Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
- const IndexedDBKeyRange& key_range,
+ const blink::IndexedDBKeyRange& key_range,
blink::WebIDBCursorDirection,
leveldb::Status*) override;
std::unique_ptr<Cursor> OpenObjectStoreCursor(
Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
- const IndexedDBKeyRange& key_range,
+ const blink::IndexedDBKeyRange& key_range,
+ blink::WebIDBCursorDirection,
+ leveldb::Status*) override;
+ std::unique_ptr<Cursor> OpenIndexKeyCursor(
+ Transaction* transaction,
+ int64_t database_id,
+ int64_t object_store_id,
+ int64_t index_id,
+ const blink::IndexedDBKeyRange& key_range,
+ blink::WebIDBCursorDirection,
+ leveldb::Status*) override;
+ std::unique_ptr<Cursor> OpenIndexCursor(
+ Transaction* transaction,
+ int64_t database_id,
+ int64_t object_store_id,
+ int64_t index_id,
+ const blink::IndexedDBKeyRange& key_range,
blink::WebIDBCursorDirection,
leveldb::Status*) override;
- std::unique_ptr<Cursor> OpenIndexKeyCursor(Transaction* transaction,
- int64_t database_id,
- int64_t object_store_id,
- int64_t index_id,
- const IndexedDBKeyRange& key_range,
- blink::WebIDBCursorDirection,
- leveldb::Status*) override;
- std::unique_ptr<Cursor> OpenIndexCursor(Transaction* transaction,
- int64_t database_id,
- int64_t object_store_id,
- int64_t index_id,
- const IndexedDBKeyRange& key_range,
- blink::WebIDBCursorDirection,
- leveldb::Status*) override;
class FakeTransaction : public IndexedDBBackingStore::Transaction {
public:
diff --git a/chromium/content/browser/indexed_db/indexed_db_index_writer.cc b/chromium/content/browser/indexed_db/indexed_db_index_writer.cc
index f18444c36f8..597603919c5 100644
--- a/chromium/content/browser/indexed_db/indexed_db_index_writer.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_index_writer.cc
@@ -12,11 +12,13 @@
#include "content/browser/indexed_db/indexed_db_backing_store.h"
#include "content/browser/indexed_db/indexed_db_tracing.h"
#include "content/browser/indexed_db/indexed_db_transaction.h"
-#include "content/common/indexed_db/indexed_db_key.h"
-#include "content/common/indexed_db/indexed_db_key_path.h"
-#include "content/common/indexed_db/indexed_db_key_range.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_metadata.h"
using base::ASCIIToUTF16;
+using blink::IndexedDBIndexKeys;
+using blink::IndexedDBIndexMetadata;
+using blink::IndexedDBKey;
+using blink::IndexedDBObjectStoreMetadata;
namespace content {
diff --git a/chromium/content/browser/indexed_db/indexed_db_index_writer.h b/chromium/content/browser/indexed_db/indexed_db_index_writer.h
index bf9c4e88109..78bf722c92d 100644
--- a/chromium/content/browser/indexed_db/indexed_db_index_writer.h
+++ b/chromium/content/browser/indexed_db/indexed_db_index_writer.h
@@ -14,20 +14,22 @@
#include "base/macros.h"
#include "content/browser/indexed_db/indexed_db_backing_store.h"
#include "content/browser/indexed_db/indexed_db_database.h"
-#include "content/common/indexed_db/indexed_db_key_path.h"
-#include "content/common/indexed_db/indexed_db_metadata.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
+
+namespace blink {
+struct IndexedDBObjectStoreMetadata;
+}
namespace content {
class IndexedDBTransaction;
-struct IndexedDBObjectStoreMetadata;
class IndexWriter {
public:
- explicit IndexWriter(const IndexedDBIndexMetadata& index_metadata);
+ explicit IndexWriter(const blink::IndexedDBIndexMetadata& index_metadata);
- IndexWriter(const IndexedDBIndexMetadata& index_metadata,
- const IndexedDBIndexKeys& index_keys);
+ IndexWriter(const blink::IndexedDBIndexMetadata& index_metadata,
+ const blink::IndexedDBIndexKeys& index_keys);
bool VerifyIndexKeys(IndexedDBBackingStore* store,
IndexedDBBackingStore::Transaction* transaction,
@@ -35,7 +37,7 @@ class IndexWriter {
int64_t object_store_id,
int64_t index_id,
bool* can_add_keys,
- const IndexedDBKey& primary_key,
+ const blink::IndexedDBKey& primary_key,
base::string16* error_message) const WARN_UNUSED_RESULT;
void WriteIndexKeys(const IndexedDBBackingStore::RecordIdentifier& record,
@@ -52,12 +54,12 @@ class IndexWriter {
int64_t database_id,
int64_t object_store_id,
int64_t index_id,
- const IndexedDBKey& index_key,
- const IndexedDBKey& primary_key,
+ const blink::IndexedDBKey& index_key,
+ const blink::IndexedDBKey& primary_key,
bool* allowed) const WARN_UNUSED_RESULT;
- const IndexedDBIndexMetadata index_metadata_;
- IndexedDBIndexKeys index_keys_;
+ const blink::IndexedDBIndexMetadata index_metadata_;
+ blink::IndexedDBIndexKeys index_keys_;
DISALLOW_COPY_AND_ASSIGN(IndexWriter);
};
@@ -65,10 +67,10 @@ class IndexWriter {
bool MakeIndexWriters(IndexedDBTransaction* transaction,
IndexedDBBackingStore* store,
int64_t database_id,
- const IndexedDBObjectStoreMetadata& metadata,
- const IndexedDBKey& primary_key,
+ const blink::IndexedDBObjectStoreMetadata& metadata,
+ const blink::IndexedDBKey& primary_key,
bool key_was_generated,
- const std::vector<IndexedDBIndexKeys>& index_keys,
+ const std::vector<blink::IndexedDBIndexKeys>& index_keys,
std::vector<std::unique_ptr<IndexWriter>>* index_writers,
base::string16* error_message,
bool* completed) WARN_UNUSED_RESULT;
diff --git a/chromium/content/browser/indexed_db/indexed_db_internals_ui.cc b/chromium/content/browser/indexed_db/indexed_db_internals_ui.cc
index b548e8953e4..cd8bc3bdb43 100644
--- a/chromium/content/browser/indexed_db/indexed_db_internals_ui.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_internals_ui.cc
@@ -12,7 +12,7 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/threading/platform_thread.h"
#include "base/values.h"
#include "content/browser/indexed_db/indexed_db_context_impl.h"
@@ -62,6 +62,10 @@ IndexedDBInternalsUI::IndexedDBInternalsUI(WebUI* web_ui)
web_ui->RegisterMessageCallback(
"forceClose", base::BindRepeating(&IndexedDBInternalsUI::ForceCloseOrigin,
base::Unretained(this)));
+ web_ui->RegisterMessageCallback(
+ "forceSchemaDowngrade",
+ base::BindRepeating(&IndexedDBInternalsUI::ForceSchemaDowngradeOrigin,
+ base::Unretained(this)));
WebUIDataSource* source =
WebUIDataSource::Create(kChromeUIIndexedDBInternalsHost);
@@ -210,6 +214,23 @@ void IndexedDBInternalsUI::ForceCloseOrigin(const base::ListValue* args) {
base::Unretained(this), partition_path, context, origin));
}
+void IndexedDBInternalsUI::ForceSchemaDowngradeOrigin(
+ const base::ListValue* args) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ base::FilePath partition_path;
+ Origin origin;
+ scoped_refptr<IndexedDBContextImpl> context;
+ if (!GetOriginData(args, &partition_path, &origin, &context))
+ return;
+
+ context->TaskRunner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &IndexedDBInternalsUI::ForceSchemaDowngradeOriginOnIndexedDBThread,
+ base::Unretained(this), partition_path, context, origin));
+}
+
void IndexedDBInternalsUI::DownloadOriginDataOnIndexedDBThread(
const base::FilePath& partition_path,
const scoped_refptr<IndexedDBContextImpl> context,
@@ -260,10 +281,33 @@ void IndexedDBInternalsUI::ForceCloseOriginOnIndexedDBThread(
context->ForceClose(origin, IndexedDBContextImpl::FORCE_CLOSE_INTERNALS_PAGE);
size_t connection_count = context->GetConnectionCount(origin);
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::BindOnce(&IndexedDBInternalsUI::OnForcedClose,
- base::Unretained(this), partition_path,
- origin, connection_count));
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&IndexedDBInternalsUI::OnForcedSchemaDowngrade,
+ base::Unretained(this), partition_path, origin,
+ connection_count));
+}
+
+void IndexedDBInternalsUI::ForceSchemaDowngradeOriginOnIndexedDBThread(
+ const base::FilePath& partition_path,
+ const scoped_refptr<IndexedDBContextImpl> context,
+ const Origin& origin) {
+ DCHECK(context->TaskRunner()->RunsTasksInCurrentSequence());
+
+ // Make sure the database hasn't been deleted since the page was loaded.
+ if (!context->HasOrigin(origin))
+ return;
+
+ context->ForceSchemaDowngrade(origin);
+ context->ForceClose(
+ origin, IndexedDBContextImpl::FORCE_SCHEMA_DOWNGRADE_INTERNALS_PAGE);
+ size_t connection_count = context->GetConnectionCount(origin);
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&IndexedDBInternalsUI::OnForcedSchemaDowngrade,
+ base::Unretained(this), partition_path, origin,
+ connection_count));
}
void IndexedDBInternalsUI::OnForcedClose(const base::FilePath& partition_path,
@@ -275,6 +319,16 @@ void IndexedDBInternalsUI::OnForcedClose(const base::FilePath& partition_path,
base::Value(static_cast<double>(connection_count)));
}
+void IndexedDBInternalsUI::OnForcedSchemaDowngrade(
+ const base::FilePath& partition_path,
+ const Origin& origin,
+ size_t connection_count) {
+ web_ui()->CallJavascriptFunctionUnsafe(
+ "indexeddb.onForcedSchemaDowngrade", base::Value(partition_path.value()),
+ base::Value(origin.Serialize()),
+ base::Value(static_cast<double>(connection_count)));
+}
+
void IndexedDBInternalsUI::OnDownloadDataReady(
const base::FilePath& partition_path,
const Origin& origin,
@@ -362,7 +416,7 @@ void FileDeleter::OnDownloadUpdated(download::DownloadItem* item) {
FileDeleter::~FileDeleter() {
base::PostTaskWithTraits(FROM_HERE,
- {base::MayBlock(), base::TaskPriority::BACKGROUND,
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
base::BindOnce(base::IgnoreResult(&base::DeleteFile),
std::move(temp_dir_), true));
diff --git a/chromium/content/browser/indexed_db/indexed_db_internals_ui.h b/chromium/content/browser/indexed_db/indexed_db_internals_ui.h
index 1cce5203b66..1a8a154042e 100644
--- a/chromium/content/browser/indexed_db/indexed_db_internals_ui.h
+++ b/chromium/content/browser/indexed_db/indexed_db_internals_ui.h
@@ -73,6 +73,16 @@ class IndexedDBInternalsUI : public WebUIController {
void OnForcedClose(const base::FilePath& partition_path,
const url::Origin& origin,
size_t connection_count);
+
+ void ForceSchemaDowngradeOrigin(const base::ListValue* args);
+ void ForceSchemaDowngradeOriginOnIndexedDBThread(
+ const base::FilePath& partition_path,
+ const scoped_refptr<IndexedDBContextImpl> context,
+ const url::Origin& origin);
+ void OnForcedSchemaDowngrade(const base::FilePath& partition_path,
+ const url::Origin& origin,
+ size_t connection_count);
+
bool GetOriginContext(const base::FilePath& path,
const url::Origin& origin,
scoped_refptr<IndexedDBContextImpl>* context);
diff --git a/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.cc b/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.cc
index d407f6018cf..7a9a4f25ea0 100644
--- a/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.cc
@@ -11,13 +11,13 @@
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/sys_byteorder.h"
-#include "content/common/indexed_db/indexed_db_key.h"
-#include "content/common/indexed_db/indexed_db_key_path.h"
// See leveldb_coding_scheme.md for detailed documentation of the coding
// scheme implemented here.
using base::StringPiece;
+using blink::IndexedDBKey;
+using blink::IndexedDBKeyPath;
using blink::WebIDBKeyType;
using blink::kWebIDBKeyTypeArray;
using blink::kWebIDBKeyTypeBinary;
diff --git a/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.h b/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.h
index 739982f55d4..fdc46986ace 100644
--- a/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.h
+++ b/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.h
@@ -18,8 +18,9 @@
#include "base/memory/ref_counted.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
-#include "content/common/indexed_db/indexed_db_key.h"
-#include "content/common/indexed_db/indexed_db_key_path.h"
+#include "content/common/content_export.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key_path.h"
namespace content {
@@ -50,8 +51,9 @@ CONTENT_EXPORT void EncodeStringWithLength(const base::string16& value,
std::string* into);
CONTENT_EXPORT void EncodeBinary(const std::string& value, std::string* into);
CONTENT_EXPORT void EncodeDouble(double value, std::string* into);
-CONTENT_EXPORT void EncodeIDBKey(const IndexedDBKey& value, std::string* into);
-CONTENT_EXPORT void EncodeIDBKeyPath(const IndexedDBKeyPath& value,
+CONTENT_EXPORT void EncodeIDBKey(const blink::IndexedDBKey& value,
+ std::string* into);
+CONTENT_EXPORT void EncodeIDBKeyPath(const blink::IndexedDBKeyPath& value,
std::string* into);
CONTENT_EXPORT void EncodeBlobJournal(const BlobJournalType& journal,
std::string* into);
@@ -75,10 +77,10 @@ CONTENT_EXPORT WARN_UNUSED_RESULT bool DecodeDouble(base::StringPiece* slice,
double* value);
CONTENT_EXPORT WARN_UNUSED_RESULT bool DecodeIDBKey(
base::StringPiece* slice,
- std::unique_ptr<IndexedDBKey>* value);
+ std::unique_ptr<blink::IndexedDBKey>* value);
CONTENT_EXPORT WARN_UNUSED_RESULT bool DecodeIDBKeyPath(
base::StringPiece* slice,
- IndexedDBKeyPath* value);
+ blink::IndexedDBKeyPath* value);
CONTENT_EXPORT WARN_UNUSED_RESULT bool DecodeBlobJournal(
base::StringPiece* slice,
BlobJournalType* journal);
@@ -415,8 +417,8 @@ class ObjectStoreDataKey {
const std::string encoded_user_key);
static std::string Encode(int64_t database_id,
int64_t object_store_id,
- const IndexedDBKey& user_key);
- std::unique_ptr<IndexedDBKey> user_key() const;
+ const blink::IndexedDBKey& user_key);
+ std::unique_ptr<blink::IndexedDBKey> user_key() const;
private:
std::string encoded_user_key_;
@@ -433,8 +435,8 @@ class ExistsEntryKey {
const std::string& encoded_key);
static std::string Encode(int64_t database_id,
int64_t object_store_id,
- const IndexedDBKey& user_key);
- std::unique_ptr<IndexedDBKey> user_key() const;
+ const blink::IndexedDBKey& user_key);
+ std::unique_ptr<blink::IndexedDBKey> user_key() const;
private:
static const int64_t kSpecialIndexNumber;
@@ -456,7 +458,7 @@ class BlobEntryKey {
int64_t object_store_id);
static std::string Encode(int64_t database_id,
int64_t object_store_id,
- const IndexedDBKey& user_key);
+ const blink::IndexedDBKey& user_key);
std::string Encode() const;
int64_t database_id() const { return database_id_; }
int64_t object_store_id() const { return object_store_id_; }
@@ -490,13 +492,13 @@ class IndexDataKey {
static std::string Encode(int64_t database_id,
int64_t object_store_id,
int64_t index_id,
- const IndexedDBKey& user_key);
+ const blink::IndexedDBKey& user_key);
CONTENT_EXPORT static std::string Encode(
int64_t database_id,
int64_t object_store_id,
int64_t index_id,
- const IndexedDBKey& user_key,
- const IndexedDBKey& user_primary_key);
+ const blink::IndexedDBKey& user_key,
+ const blink::IndexedDBKey& user_primary_key);
CONTENT_EXPORT static std::string EncodeMinKey(int64_t database_id,
int64_t object_store_id,
int64_t index_id);
@@ -506,8 +508,8 @@ class IndexDataKey {
int64_t DatabaseId() const;
int64_t ObjectStoreId() const;
int64_t IndexId() const;
- std::unique_ptr<IndexedDBKey> user_key() const;
- std::unique_ptr<IndexedDBKey> primary_key() const;
+ std::unique_ptr<blink::IndexedDBKey> user_key() const;
+ std::unique_ptr<blink::IndexedDBKey> primary_key() const;
CONTENT_EXPORT std::string Encode() const;
diff --git a/chromium/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc b/chromium/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc
index d2e4e8e775c..edea49ca768 100644
--- a/chromium/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc
@@ -14,12 +14,12 @@
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
-#include "content/common/indexed_db/indexed_db_key.h"
-#include "content/common/indexed_db/indexed_db_key_path.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::ASCIIToUTF16;
using base::StringPiece;
+using blink::IndexedDBKey;
+using blink::IndexedDBKeyPath;
using blink::kWebIDBKeyTypeDate;
using blink::kWebIDBKeyTypeNumber;
diff --git a/chromium/content/browser/indexed_db/indexed_db_leveldb_operations.cc b/chromium/content/browser/indexed_db/indexed_db_leveldb_operations.cc
index 0908595054e..1e981b9e563 100644
--- a/chromium/content/browser/indexed_db/indexed_db_leveldb_operations.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_leveldb_operations.cc
@@ -10,8 +10,9 @@
#include "content/browser/indexed_db/leveldb/leveldb_iterator.h"
#include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
-using leveldb::Status;
using base::StringPiece;
+using blink::IndexedDBKeyPath;
+using leveldb::Status;
namespace content {
namespace indexed_db {
diff --git a/chromium/content/browser/indexed_db/indexed_db_leveldb_operations.h b/chromium/content/browser/indexed_db/indexed_db_leveldb_operations.h
index 1f75df341d9..fbbc9957457 100644
--- a/chromium/content/browser/indexed_db/indexed_db_leveldb_operations.h
+++ b/chromium/content/browser/indexed_db/indexed_db_leveldb_operations.h
@@ -11,7 +11,7 @@
#include "base/strings/string_piece.h"
#include "base/time/time.h"
#include "content/common/content_export.h"
-#include "content/common/indexed_db/indexed_db_key_path.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key_path.h"
#include "third_party/leveldatabase/src/include/leveldb/status.h"
// Contains common operations for LevelDBTransactions and/or LevelDBDatabases.
@@ -69,7 +69,7 @@ void PutString(LevelDBTransaction* transaction,
void PutIDBKeyPath(LevelDBTransaction* transaction,
const base::StringPiece& key,
- const IndexedDBKeyPath& value);
+ const blink::IndexedDBKeyPath& value);
template <typename DBOrTransaction>
WARN_UNUSED_RESULT leveldb::Status GetMaxObjectStoreId(
diff --git a/chromium/content/browser/indexed_db/indexed_db_metadata_coding.cc b/chromium/content/browser/indexed_db/indexed_db_metadata_coding.cc
index dfb98770800..6ffb4bb256f 100644
--- a/chromium/content/browser/indexed_db/indexed_db_metadata_coding.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_metadata_coding.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "content/browser/indexed_db/indexed_db_metadata_coding.h"
+
#include "base/strings/string_piece.h"
#include "content/browser/indexed_db/indexed_db_class_factory.h"
#include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
@@ -11,9 +12,13 @@
#include "content/browser/indexed_db/indexed_db_tracing.h"
#include "content/browser/indexed_db/leveldb/leveldb_database.h"
#include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
-#include "content/common/indexed_db/indexed_db_metadata.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_metadata.h"
using base::StringPiece;
+using blink::IndexedDBDatabaseMetadata;
+using blink::IndexedDBIndexMetadata;
+using blink::IndexedDBKeyPath;
+using blink::IndexedDBObjectStoreMetadata;
using leveldb::Status;
namespace content {
diff --git a/chromium/content/browser/indexed_db/indexed_db_metadata_coding.h b/chromium/content/browser/indexed_db/indexed_db_metadata_coding.h
index 3abf22a822b..e6b579ef3c2 100644
--- a/chromium/content/browser/indexed_db/indexed_db_metadata_coding.h
+++ b/chromium/content/browser/indexed_db/indexed_db_metadata_coding.h
@@ -12,15 +12,19 @@
#include "base/macros.h"
#include "base/strings/string16.h"
-#include "content/common/indexed_db/indexed_db_key_path.h"
+#include "content/common/content_export.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key_path.h"
#include "third_party/leveldatabase/src/include/leveldb/status.h"
+namespace blink {
+struct IndexedDBDatabaseMetadata;
+struct IndexedDBIndexMetadata;
+struct IndexedDBObjectStoreMetadata;
+} // namespace blink
+
namespace content {
class LevelDBDatabase;
class LevelDBTransaction;
-struct IndexedDBDatabaseMetadata;
-struct IndexedDBObjectStoreMetadata;
-struct IndexedDBIndexMetadata;
// Creation, reading, and modification operations for IndexedDB metadata. All
// methods that write data to disk use the given |transaction| for writing (and
@@ -49,27 +53,28 @@ class CONTENT_EXPORT IndexedDBMetadataCoding {
LevelDBDatabase* db,
const std::string& origin_identifier,
const base::string16& name,
- IndexedDBDatabaseMetadata* metadata,
+ blink::IndexedDBDatabaseMetadata* metadata,
bool* found);
virtual leveldb::Status ReadMetadataForDatabaseName(
LevelDBTransaction* transaction,
const std::string& origin_identifier,
const base::string16& name,
- IndexedDBDatabaseMetadata* metadata,
+ blink::IndexedDBDatabaseMetadata* metadata,
bool* found);
// Creates a new database metadata entry and writes it to disk.
- virtual leveldb::Status CreateDatabase(LevelDBDatabase* database,
- const std::string& origin_identifier,
- const base::string16& name,
- int64_t version,
- IndexedDBDatabaseMetadata* metadata);
+ virtual leveldb::Status CreateDatabase(
+ LevelDBDatabase* database,
+ const std::string& origin_identifier,
+ const base::string16& name,
+ int64_t version,
+ blink::IndexedDBDatabaseMetadata* metadata);
// Changes the database version to |version|.
virtual void SetDatabaseVersion(LevelDBTransaction* transaction,
int64_t row_id,
int64_t version,
- IndexedDBDatabaseMetadata* metadata);
+ blink::IndexedDBDatabaseMetadata* metadata);
// Reads only the database id, if found.
virtual leveldb::Status FindDatabaseId(LevelDBDatabase* db,
@@ -84,16 +89,16 @@ class CONTENT_EXPORT IndexedDBMetadataCoding {
int64_t database_id,
int64_t object_store_id,
base::string16 name,
- IndexedDBKeyPath key_path,
+ blink::IndexedDBKeyPath key_path,
bool auto_increment,
- IndexedDBObjectStoreMetadata* metadata);
+ blink::IndexedDBObjectStoreMetadata* metadata);
// Deletes the given object store metadata on the transaction (but not any
// data entries or blobs in the object store).
virtual leveldb::Status DeleteObjectStore(
LevelDBTransaction* transaction,
int64_t database_id,
- const IndexedDBObjectStoreMetadata& object_store);
+ const blink::IndexedDBObjectStoreMetadata& object_store);
// Renames the given object store and writes it to the transaction.
virtual leveldb::Status RenameObjectStore(
@@ -101,7 +106,7 @@ class CONTENT_EXPORT IndexedDBMetadataCoding {
int64_t database_id,
base::string16 new_name,
base::string16* old_name,
- IndexedDBObjectStoreMetadata* metadata);
+ blink::IndexedDBObjectStoreMetadata* metadata);
// Creates a new index metadata and writes it to the transaction.
virtual leveldb::Status CreateIndex(LevelDBTransaction* transaction,
@@ -109,16 +114,17 @@ class CONTENT_EXPORT IndexedDBMetadataCoding {
int64_t object_store_id,
int64_t index_id,
base::string16 name,
- IndexedDBKeyPath key_path,
+ blink::IndexedDBKeyPath key_path,
bool is_unique,
bool is_multi_entry,
- IndexedDBIndexMetadata* metadata);
+ blink::IndexedDBIndexMetadata* metadata);
// Deletes the index metadata on the transaction (but not any index entries).
- virtual leveldb::Status DeleteIndex(LevelDBTransaction* transaction,
- int64_t database_id,
- int64_t object_store_id,
- const IndexedDBIndexMetadata& metadata);
+ virtual leveldb::Status DeleteIndex(
+ LevelDBTransaction* transaction,
+ int64_t database_id,
+ int64_t object_store_id,
+ const blink::IndexedDBIndexMetadata& metadata);
// Renames the given index and writes it to the transaction.
virtual leveldb::Status RenameIndex(LevelDBTransaction* transaction,
@@ -126,7 +132,7 @@ class CONTENT_EXPORT IndexedDBMetadataCoding {
int64_t object_store_id,
base::string16 new_name,
base::string16* old_name,
- IndexedDBIndexMetadata* metadata);
+ blink::IndexedDBIndexMetadata* metadata);
private:
DISALLOW_COPY_AND_ASSIGN(IndexedDBMetadataCoding);
diff --git a/chromium/content/browser/indexed_db/indexed_db_observer.h b/chromium/content/browser/indexed_db/indexed_db_observer.h
index c648455a75e..5b5ae2d3be9 100644
--- a/chromium/content/browser/indexed_db/indexed_db_observer.h
+++ b/chromium/content/browser/indexed_db/indexed_db_observer.h
@@ -14,7 +14,7 @@
#include "base/macros.h"
#include "base/stl_util.h"
#include "content/common/content_export.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_types.h"
+#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
namespace content {
diff --git a/chromium/content/browser/indexed_db/indexed_db_pre_close_task_queue.cc b/chromium/content/browser/indexed_db/indexed_db_pre_close_task_queue.cc
index 0be77f326e1..ec0ebcf5169 100644
--- a/chromium/content/browser/indexed_db/indexed_db_pre_close_task_queue.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_pre_close_task_queue.cc
@@ -6,8 +6,11 @@
#include "base/metrics/histogram_macros.h"
#include "base/threading/sequenced_task_runner_handle.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_metadata.h"
#include "third_party/leveldatabase/env_chromium.h"
+using blink::IndexedDBDatabaseMetadata;
+
namespace content {
IndexedDBPreCloseTaskQueue::PreCloseTask::~PreCloseTask() {}
@@ -45,9 +48,10 @@ void IndexedDBPreCloseTaskQueue::Start(
OnComplete();
return;
}
- timeout_timer_->Start(FROM_HERE, timeout_time_,
- base::Bind(&IndexedDBPreCloseTaskQueue::StopForTimout,
- ptr_factory_.GetWeakPtr()));
+ timeout_timer_->Start(
+ FROM_HERE, timeout_time_,
+ base::BindOnce(&IndexedDBPreCloseTaskQueue::StopForTimout,
+ ptr_factory_.GetWeakPtr()));
leveldb::Status status = std::move(metadata_fetcher).Run(&metadata_);
if (!status.ok()) {
StopForMetadataError(status);
diff --git a/chromium/content/browser/indexed_db/indexed_db_pre_close_task_queue.h b/chromium/content/browser/indexed_db/indexed_db_pre_close_task_queue.h
index 7e2aa847c55..988a941e596 100644
--- a/chromium/content/browser/indexed_db/indexed_db_pre_close_task_queue.h
+++ b/chromium/content/browser/indexed_db/indexed_db_pre_close_task_queue.h
@@ -14,9 +14,13 @@
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
-#include "content/common/indexed_db/indexed_db_metadata.h"
+#include "content/common/content_export.h"
#include "third_party/leveldatabase/src/include/leveldb/status.h"
+namespace blink {
+struct IndexedDBDatabaseMetadata;
+}
+
namespace content {
// Holds a queue of PreCloseTask's to be run after an IndexedDBBackingStore no
@@ -48,7 +52,7 @@ class CONTENT_EXPORT IndexedDBPreCloseTaskQueue {
// Called before RunRound. |metadata| is guaranteed to outlive this task.
virtual void SetMetadata(
- std::vector<IndexedDBDatabaseMetadata> const* metadata) = 0;
+ std::vector<blink::IndexedDBDatabaseMetadata> const* metadata) = 0;
// Tells the task to stop before completion. It will be destroyed after this
// call. Can be called at any time.
@@ -77,8 +81,9 @@ class CONTENT_EXPORT IndexedDBPreCloseTaskQueue {
void StopForNewConnection();
// Starts running tasks. Can only be called once.
- void Start(base::OnceCallback<leveldb::Status(
- std::vector<IndexedDBDatabaseMetadata>*)> metadata_fetcher);
+ void Start(
+ base::OnceCallback<leveldb::Status(
+ std::vector<blink::IndexedDBDatabaseMetadata>*)> metadata_fetcher);
private:
void OnComplete();
@@ -88,7 +93,7 @@ class CONTENT_EXPORT IndexedDBPreCloseTaskQueue {
void RunLoop();
- std::vector<IndexedDBDatabaseMetadata> metadata_;
+ std::vector<blink::IndexedDBDatabaseMetadata> metadata_;
bool started_ = false;
bool done_ = false;
diff --git a/chromium/content/browser/indexed_db/indexed_db_pre_close_task_queue_unittest.cc b/chromium/content/browser/indexed_db/indexed_db_pre_close_task_queue_unittest.cc
index 48bf2edc32f..18bfa258969 100644
--- a/chromium/content/browser/indexed_db/indexed_db_pre_close_task_queue_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_pre_close_task_queue_unittest.cc
@@ -14,9 +14,11 @@
#include "base/time/time.h"
#include "base/timer/mock_timer.h"
#include "base/timer/timer.h"
-#include "content/common/indexed_db/indexed_db_metadata.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_metadata.h"
+
+using blink::IndexedDBDatabaseMetadata;
namespace content {
diff --git a/chromium/content/browser/indexed_db/indexed_db_reporting.h b/chromium/content/browser/indexed_db/indexed_db_reporting.h
index 353e436e053..ef82e103ea2 100644
--- a/chromium/content/browser/indexed_db/indexed_db_reporting.h
+++ b/chromium/content/browser/indexed_db/indexed_db_reporting.h
@@ -47,6 +47,7 @@ enum IndexedDBBackingStoreErrorSource {
GET_BLOB_KEY_GENERATOR_CURRENT_NUMBER = 28,
GET_BLOB_INFO_FOR_RECORD = 29,
UPGRADING_SCHEMA_CORRUPTED_BLOBS = 30,
+ REVERT_SCHEMA_TO_V2 = 31,
INTERNAL_ERROR_MAX,
};
diff --git a/chromium/content/browser/indexed_db/indexed_db_return_value.h b/chromium/content/browser/indexed_db/indexed_db_return_value.h
index 6a50a26165f..a52851908f6 100644
--- a/chromium/content/browser/indexed_db/indexed_db_return_value.h
+++ b/chromium/content/browser/indexed_db/indexed_db_return_value.h
@@ -7,8 +7,8 @@
#include "content/browser/indexed_db/indexed_db_value.h"
#include "content/common/content_export.h"
-#include "content/common/indexed_db/indexed_db_key.h"
-#include "content/common/indexed_db/indexed_db_key_path.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key_path.h"
namespace content {
@@ -18,8 +18,9 @@ namespace content {
// database, so they are kept separately, and sent back with the original data
// so that the render process can amend the returned object.
struct CONTENT_EXPORT IndexedDBReturnValue : public IndexedDBValue {
- IndexedDBKey primary_key; // primary key (only when using key generator)
- IndexedDBKeyPath key_path;
+ blink::IndexedDBKey
+ primary_key; // primary key (only when using key generator)
+ blink::IndexedDBKeyPath key_path;
};
} // namespace content
diff --git a/chromium/content/browser/indexed_db/indexed_db_tombstone_sweeper.cc b/chromium/content/browser/indexed_db/indexed_db_tombstone_sweeper.cc
index e3d35567d14..37db1001464 100644
--- a/chromium/content/browser/indexed_db/indexed_db_tombstone_sweeper.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_tombstone_sweeper.cc
@@ -11,6 +11,8 @@
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/time/tick_clock.h"
#include "content/browser/indexed_db/indexed_db_backing_store.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_metadata.h"
#include "third_party/leveldatabase/env_chromium.h"
#include "third_party/leveldatabase/src/include/leveldb/db.h"
#include "third_party/leveldatabase/src/include/leveldb/iterator.h"
@@ -19,6 +21,10 @@ namespace content {
namespace {
using StopReason = IndexedDBPreCloseTaskQueue::StopReason;
+using blink::IndexedDBDatabaseMetadata;
+using blink::IndexedDBIndexMetadata;
+using blink::IndexedDBKey;
+using blink::IndexedDBObjectStoreMetadata;
} // namespace
diff --git a/chromium/content/browser/indexed_db/indexed_db_tombstone_sweeper.h b/chromium/content/browser/indexed_db/indexed_db_tombstone_sweeper.h
index ef335a71440..9ab45a69dee 100644
--- a/chromium/content/browser/indexed_db/indexed_db_tombstone_sweeper.h
+++ b/chromium/content/browser/indexed_db/indexed_db_tombstone_sweeper.h
@@ -18,7 +18,6 @@
#include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
#include "content/browser/indexed_db/indexed_db_pre_close_task_queue.h"
#include "content/common/content_export.h"
-#include "content/common/indexed_db/indexed_db_metadata.h"
#include "third_party/leveldatabase/src/include/leveldb/status.h"
#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
@@ -26,6 +25,12 @@ namespace base {
class TickClock;
}
+namespace blink {
+struct IndexedDBDatabaseMetadata;
+struct IndexedDBIndexMetadata;
+struct IndexedDBObjectStoreMetadata;
+} // namespace blink
+
namespace leveldb {
class DB;
class Iterator;
@@ -86,17 +91,17 @@ class CONTENT_EXPORT IndexedDBTombstoneSweeper
~IndexedDBTombstoneSweeper() override;
void SetMetadata(
- std::vector<IndexedDBDatabaseMetadata> const* metadata) override;
+ std::vector<blink::IndexedDBDatabaseMetadata> const* metadata) override;
void Stop(IndexedDBPreCloseTaskQueue::StopReason reason) override;
bool RunRound() override;
private:
- using DatabaseMetadataVector = std::vector<IndexedDBDatabaseMetadata>;
+ using DatabaseMetadataVector = std::vector<blink::IndexedDBDatabaseMetadata>;
using ObjectStoreMetadataMap =
- std::map<int64_t, IndexedDBObjectStoreMetadata>;
- using IndexMetadataMap = std::map<int64_t, IndexedDBIndexMetadata>;
+ std::map<int64_t, blink::IndexedDBObjectStoreMetadata>;
+ using IndexMetadataMap = std::map<int64_t, blink::IndexedDBIndexMetadata>;
friend class indexed_db_tombstone_sweeper_unittest::
IndexedDBTombstoneSweeperTest;
@@ -163,7 +168,7 @@ class CONTENT_EXPORT IndexedDBTombstoneSweeper
// Returns true if sweeper can continue iterating.
bool IterateIndex(int64_t database_id,
int64_t object_store_id,
- const IndexedDBIndexMetadata& index,
+ const blink::IndexedDBIndexMetadata& index,
Status* sweep_status,
leveldb::Status* leveldb_status,
int* round_iterations);
@@ -185,7 +190,8 @@ class CONTENT_EXPORT IndexedDBTombstoneSweeper
leveldb::WriteBatch round_deletion_batch_;
base::TimeDelta total_deletion_time_;
- std::vector<IndexedDBDatabaseMetadata> const* database_metadata_ = nullptr;
+ std::vector<blink::IndexedDBDatabaseMetadata> const* database_metadata_ =
+ nullptr;
std::unique_ptr<leveldb::Iterator> iterator_;
SweepState sweep_state_;
diff --git a/chromium/content/browser/indexed_db/indexed_db_tombstone_sweeper_unittest.cc b/chromium/content/browser/indexed_db/indexed_db_tombstone_sweeper_unittest.cc
index 2793b7449b7..4d8e872d43f 100644
--- a/chromium/content/browser/indexed_db/indexed_db_tombstone_sweeper_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_tombstone_sweeper_unittest.cc
@@ -14,15 +14,23 @@
#include "content/browser/indexed_db/leveldb/leveldb_comparator.h"
#include "content/browser/indexed_db/leveldb/leveldb_database.h"
#include "content/browser/indexed_db/leveldb/mock_level_db.h"
-#include "content/common/indexed_db/indexed_db_metadata.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key_path.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_metadata.h"
#include "third_party/leveldatabase/env_chromium.h"
#include "third_party/leveldatabase/src/include/leveldb/db.h"
#include "third_party/leveldatabase/src/include/leveldb/filter_policy.h"
#include "third_party/leveldatabase/src/include/leveldb/slice.h"
+using blink::IndexedDBDatabaseMetadata;
+using blink::IndexedDBIndexMetadata;
+using blink::IndexedDBKey;
+using blink::IndexedDBKeyPath;
+using blink::IndexedDBObjectStoreMetadata;
+
namespace content {
class BrowserContext;
diff --git a/chromium/content/browser/indexed_db/indexed_db_transaction.cc b/chromium/content/browser/indexed_db/indexed_db_transaction.cc
index 78ac2ba3600..7e2eff576ca 100644
--- a/chromium/content/browser/indexed_db/indexed_db_transaction.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_transaction.cc
@@ -526,9 +526,9 @@ void IndexedDBTransaction::ProcessTaskQueue() {
// never requests further activity. Read-only transactions don't
// block other transactions, so don't time those out.
if (mode_ != blink::kWebIDBTransactionModeReadOnly) {
- timeout_timer_.Start(
- FROM_HERE, GetInactivityTimeout(),
- base::Bind(&IndexedDBTransaction::Timeout, ptr_factory_.GetWeakPtr()));
+ timeout_timer_.Start(FROM_HERE, GetInactivityTimeout(),
+ base::BindOnce(&IndexedDBTransaction::Timeout,
+ ptr_factory_.GetWeakPtr()));
}
processing_event_queue_ = false;
}
@@ -571,18 +571,18 @@ void IndexedDBTransaction::RemovePendingObservers(
void IndexedDBTransaction::AddObservation(
int32_t connection_id,
- ::indexed_db::mojom::ObservationPtr observation) {
+ blink::mojom::IDBObservationPtr observation) {
auto it = connection_changes_map_.find(connection_id);
if (it == connection_changes_map_.end()) {
it = connection_changes_map_
- .insert(std::make_pair(
- connection_id, ::indexed_db::mojom::ObserverChanges::New()))
+ .insert(std::make_pair(connection_id,
+ blink::mojom::IDBObserverChanges::New()))
.first;
}
it->second->observations.push_back(std::move(observation));
}
-::indexed_db::mojom::ObserverChangesPtr*
+blink::mojom::IDBObserverChangesPtr*
IndexedDBTransaction::GetPendingChangesForConnection(int32_t connection_id) {
auto it = connection_changes_map_.find(connection_id);
if (it != connection_changes_map_.end())
diff --git a/chromium/content/browser/indexed_db/indexed_db_transaction.h b/chromium/content/browser/indexed_db/indexed_db_transaction.h
index fd690bcc345..f7bc5f07a14 100644
--- a/chromium/content/browser/indexed_db/indexed_db_transaction.h
+++ b/chromium/content/browser/indexed_db/indexed_db_transaction.h
@@ -23,8 +23,8 @@
#include "content/browser/indexed_db/indexed_db_database.h"
#include "content/browser/indexed_db/indexed_db_database_error.h"
#include "content/browser/indexed_db/indexed_db_observer.h"
-#include "content/common/indexed_db/indexed_db.mojom.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_types.h"
+#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
namespace content {
@@ -95,9 +95,9 @@ class CONTENT_EXPORT IndexedDBTransaction {
// Adds observation for the connection.
void AddObservation(int32_t connection_id,
- ::indexed_db::mojom::ObservationPtr observation);
+ blink::mojom::IDBObservationPtr observation);
- ::indexed_db::mojom::ObserverChangesPtr* GetPendingChangesForConnection(
+ blink::mojom::IDBObserverChangesPtr* GetPendingChangesForConnection(
int32_t connection_id);
IndexedDBBackingStore::Transaction* BackingStoreTransaction() {
@@ -195,7 +195,7 @@ class CONTENT_EXPORT IndexedDBTransaction {
// Observers in pending queue do not listen to changes until activated.
std::vector<std::unique_ptr<IndexedDBObserver>> pending_observers_;
- std::map<int32_t, ::indexed_db::mojom::ObserverChangesPtr>
+ std::map<int32_t, blink::mojom::IDBObserverChangesPtr>
connection_changes_map_;
// Metrics for quota.
diff --git a/chromium/content/browser/indexed_db/indexed_db_transaction_coordinator.cc b/chromium/content/browser/indexed_db/indexed_db_transaction_coordinator.cc
index eb714dde14d..91dd95712ad 100644
--- a/chromium/content/browser/indexed_db/indexed_db_transaction_coordinator.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_transaction_coordinator.cc
@@ -7,7 +7,7 @@
#include "base/logging.h"
#include "content/browser/indexed_db/indexed_db_tracing.h"
#include "content/browser/indexed_db/indexed_db_transaction.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_types.h"
+#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
namespace content {
namespace {
diff --git a/chromium/content/browser/indexed_db/indexed_db_unittest.cc b/chromium/content/browser/indexed_db/indexed_db_unittest.cc
index 705a2ed309c..4763c2f5eaf 100644
--- a/chromium/content/browser/indexed_db/indexed_db_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_unittest.cc
@@ -26,6 +26,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "url/origin.h"
+using blink::IndexedDBDatabaseMetadata;
using url::Origin;
namespace content {
diff --git a/chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc b/chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc
index 266205bdb14..742de2e5732 100644
--- a/chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc
+++ b/chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc
@@ -64,7 +64,7 @@ class IndexedDBTestDatabase : public IndexedDBDatabase {
protected:
~IndexedDBTestDatabase() override {}
- size_t GetMaxMessageSizeInBytes() const override {
+ size_t GetUsableMessageSizeInBytes() const override {
return 10 * 1024 * 1024; // 10MB
}
};
diff --git a/chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h b/chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h
index 0c520868636..64e9ce487f1 100644
--- a/chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h
+++ b/chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h
@@ -14,7 +14,7 @@
#include "content/browser/indexed_db/indexed_db_backing_store.h"
#include "content/browser/indexed_db/indexed_db_class_factory.h"
#include "content/browser/indexed_db/indexed_db_database.h"
-#include "third_party/blink/public/platform/modules/indexeddb/web_idb_types.h"
+#include "third_party/blink/public/common/indexeddb/web_idb_types.h"
namespace content {
diff --git a/chromium/content/browser/indexed_db/mock_indexed_db_callbacks.cc b/chromium/content/browser/indexed_db/mock_indexed_db_callbacks.cc
index fe8a6a12c9c..eb7a20405b1 100644
--- a/chromium/content/browser/indexed_db/mock_indexed_db_callbacks.cc
+++ b/chromium/content/browser/indexed_db/mock_indexed_db_callbacks.cc
@@ -8,6 +8,9 @@
#include "testing/gtest/include/gtest/gtest.h"
+using blink::IndexedDBDatabaseMetadata;
+using blink::IndexedDBKey;
+
namespace content {
MockIndexedDBCallbacks::MockIndexedDBCallbacks()
@@ -41,7 +44,7 @@ void MockIndexedDBCallbacks::OnSuccess(
void MockIndexedDBCallbacks::OnUpgradeNeeded(
int64_t old_version,
std::unique_ptr<IndexedDBConnection> connection,
- const content::IndexedDBDatabaseMetadata& metadata,
+ const IndexedDBDatabaseMetadata& metadata,
const IndexedDBDataLossInfo& data_loss_info) {
connection_ = std::move(connection);
upgrade_called_ = true;
diff --git a/chromium/content/browser/indexed_db/mock_indexed_db_callbacks.h b/chromium/content/browser/indexed_db/mock_indexed_db_callbacks.h
index 10fa56e204e..bc67121a9cd 100644
--- a/chromium/content/browser/indexed_db/mock_indexed_db_callbacks.h
+++ b/chromium/content/browser/indexed_db/mock_indexed_db_callbacks.h
@@ -12,6 +12,11 @@
#include "base/macros.h"
#include "content/browser/indexed_db/indexed_db_callbacks.h"
#include "content/browser/indexed_db/indexed_db_connection.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
+
+namespace blink {
+struct IndexedDBDatabaseMetadata;
+}
namespace content {
@@ -25,14 +30,14 @@ class MockIndexedDBCallbacks : public IndexedDBCallbacks {
void OnSuccess() override;
void OnSuccess(int64_t result) override;
void OnSuccess(const std::vector<base::string16>& result) override;
- void OnSuccess(const IndexedDBKey& key) override;
+ void OnSuccess(const blink::IndexedDBKey& key) override;
void OnSuccess(std::unique_ptr<IndexedDBConnection> connection,
- const IndexedDBDatabaseMetadata& metadata) override;
+ const blink::IndexedDBDatabaseMetadata& metadata) override;
IndexedDBConnection* connection() { return connection_.get(); }
void OnUpgradeNeeded(int64_t old_version,
std::unique_ptr<IndexedDBConnection> connection,
- const content::IndexedDBDatabaseMetadata& metadata,
+ const blink::IndexedDBDatabaseMetadata& metadata,
const IndexedDBDataLossInfo& data_loss_info) override;
bool error_called() { return error_called_; }
diff --git a/chromium/content/browser/indexed_db/mock_indexed_db_factory.h b/chromium/content/browser/indexed_db/mock_indexed_db_factory.h
index 6a3022197a0..b2747857a84 100644
--- a/chromium/content/browser/indexed_db/mock_indexed_db_factory.h
+++ b/chromium/content/browser/indexed_db/mock_indexed_db_factory.h
@@ -78,6 +78,7 @@ class MockIndexedDBFactory : public IndexedDBFactory {
// deal with std::pair's. This means we can't use GoogleMock for this method
OriginDBs GetOpenDatabasesForOrigin(const url::Origin& origin) const override;
MOCK_METHOD1(ForceClose, void(const url::Origin& origin));
+ MOCK_METHOD1(ForceSchemaDowngrade, void(const url::Origin& origin));
MOCK_METHOD0(ContextDestroyed, void());
MOCK_METHOD1(DatabaseDeleted,
void(const IndexedDBDatabase::Identifier& identifier));
diff --git a/chromium/content/browser/indexed_db/mock_mojo_indexed_db_callbacks.cc b/chromium/content/browser/indexed_db/mock_mojo_indexed_db_callbacks.cc
index 7f0f9bdb43d..358a6703e9a 100644
--- a/chromium/content/browser/indexed_db/mock_mojo_indexed_db_callbacks.cc
+++ b/chromium/content/browser/indexed_db/mock_mojo_indexed_db_callbacks.cc
@@ -9,9 +9,9 @@ namespace content {
MockMojoIndexedDBCallbacks::MockMojoIndexedDBCallbacks() : binding_(this) {}
MockMojoIndexedDBCallbacks::~MockMojoIndexedDBCallbacks() {}
-::indexed_db::mojom::CallbacksAssociatedPtrInfo
+blink::mojom::IDBCallbacksAssociatedPtrInfo
MockMojoIndexedDBCallbacks::CreateInterfacePtrAndBind() {
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo ptr_info;
+ blink::mojom::IDBCallbacksAssociatedPtrInfo ptr_info;
binding_.Bind(::mojo::MakeRequest(&ptr_info));
return ptr_info;
}
diff --git a/chromium/content/browser/indexed_db/mock_mojo_indexed_db_callbacks.h b/chromium/content/browser/indexed_db/mock_mojo_indexed_db_callbacks.h
index ca8fb743097..ee92e16a517 100644
--- a/chromium/content/browser/indexed_db/mock_mojo_indexed_db_callbacks.h
+++ b/chromium/content/browser/indexed_db/mock_mojo_indexed_db_callbacks.h
@@ -9,18 +9,23 @@
#include <string>
#include "base/macros.h"
-#include "content/common/indexed_db/indexed_db.mojom.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
#include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
+
+namespace blink {
+struct IndexedDBDatabaseMetadata;
+}
namespace content {
-class MockMojoIndexedDBCallbacks : public ::indexed_db::mojom::Callbacks {
+class MockMojoIndexedDBCallbacks : public blink::mojom::IDBCallbacks {
public:
explicit MockMojoIndexedDBCallbacks();
~MockMojoIndexedDBCallbacks() override;
- ::indexed_db::mojom::CallbacksAssociatedPtrInfo CreateInterfacePtrAndBind();
+ blink::mojom::IDBCallbacksAssociatedPtrInfo CreateInterfacePtrAndBind();
MOCK_METHOD2(Error, void(int32_t code, const base::string16& message));
@@ -29,89 +34,87 @@ class MockMojoIndexedDBCallbacks : public ::indexed_db::mojom::Callbacks {
MOCK_METHOD1(Blocked, void(int64_t existing_version));
- MOCK_METHOD5(
- MockedUpgradeNeeded,
- void(::indexed_db::mojom::DatabaseAssociatedPtrInfo* database_info,
- int64_t old_version,
- blink::WebIDBDataLoss data_loss,
- const std::string& data_loss_message,
- const content::IndexedDBDatabaseMetadata& metadata));
+ MOCK_METHOD5(MockedUpgradeNeeded,
+ void(blink::mojom::IDBDatabaseAssociatedPtrInfo* database_info,
+ int64_t old_version,
+ blink::WebIDBDataLoss data_loss,
+ const std::string& data_loss_message,
+ const blink::IndexedDBDatabaseMetadata& metadata));
// Move-only types not supported by mock methods.
void UpgradeNeeded(
- ::indexed_db::mojom::DatabaseAssociatedPtrInfo database_info,
+ blink::mojom::IDBDatabaseAssociatedPtrInfo database_info,
int64_t old_version,
blink::WebIDBDataLoss data_loss,
const std::string& data_loss_message,
- const content::IndexedDBDatabaseMetadata& metadata) override {
+ const blink::IndexedDBDatabaseMetadata& metadata) override {
MockedUpgradeNeeded(&database_info, old_version, data_loss,
data_loss_message, metadata);
}
- MOCK_METHOD2(
- MockedSuccessDatabase,
- void(::indexed_db::mojom::DatabaseAssociatedPtrInfo* database_info,
- const content::IndexedDBDatabaseMetadata& metadata));
+ MOCK_METHOD2(MockedSuccessDatabase,
+ void(blink::mojom::IDBDatabaseAssociatedPtrInfo* database_info,
+ const blink::IndexedDBDatabaseMetadata& metadata));
void SuccessDatabase(
- ::indexed_db::mojom::DatabaseAssociatedPtrInfo database_info,
- const content::IndexedDBDatabaseMetadata& metadata) override {
+ blink::mojom::IDBDatabaseAssociatedPtrInfo database_info,
+ const blink::IndexedDBDatabaseMetadata& metadata) override {
MockedSuccessDatabase(&database_info, metadata);
}
MOCK_METHOD4(MockedSuccessCursor,
- void(::indexed_db::mojom::CursorAssociatedPtrInfo* cursor,
- const IndexedDBKey& key,
- const IndexedDBKey& primary_key,
- ::indexed_db::mojom::ValuePtr* value));
- void SuccessCursor(::indexed_db::mojom::CursorAssociatedPtrInfo cursor,
- const IndexedDBKey& key,
- const IndexedDBKey& primary_key,
- ::indexed_db::mojom::ValuePtr value) override {
+ void(blink::mojom::IDBCursorAssociatedPtrInfo* cursor,
+ const blink::IndexedDBKey& key,
+ const blink::IndexedDBKey& primary_key,
+ blink::mojom::IDBValuePtr* value));
+ void SuccessCursor(blink::mojom::IDBCursorAssociatedPtrInfo cursor,
+ const blink::IndexedDBKey& key,
+ const blink::IndexedDBKey& primary_key,
+ blink::mojom::IDBValuePtr value) override {
MockedSuccessCursor(&cursor, key, primary_key, &value);
}
MOCK_METHOD1(MockedSuccessValue,
- void(::indexed_db::mojom::ReturnValuePtr* value));
- void SuccessValue(::indexed_db::mojom::ReturnValuePtr value) override {
+ void(blink::mojom::IDBReturnValuePtr* value));
+ void SuccessValue(blink::mojom::IDBReturnValuePtr value) override {
MockedSuccessValue(&value);
}
MOCK_METHOD3(MockedSuccessCursorContinue,
- void(const IndexedDBKey& key,
- const IndexedDBKey& primary_key,
- ::indexed_db::mojom::ValuePtr* value));
+ void(const blink::IndexedDBKey& key,
+ const blink::IndexedDBKey& primary_key,
+ blink::mojom::IDBValuePtr* value));
- void SuccessCursorContinue(const IndexedDBKey& key,
- const IndexedDBKey& primary_key,
- ::indexed_db::mojom::ValuePtr value) override {
+ void SuccessCursorContinue(const blink::IndexedDBKey& key,
+ const blink::IndexedDBKey& primary_key,
+ blink::mojom::IDBValuePtr value) override {
MockedSuccessCursorContinue(key, primary_key, &value);
}
MOCK_METHOD3(MockedSuccessCursorPrefetch,
- void(const std::vector<IndexedDBKey>& keys,
- const std::vector<IndexedDBKey>& primary_keys,
- std::vector<::indexed_db::mojom::ValuePtr>* values));
+ void(const std::vector<blink::IndexedDBKey>& keys,
+ const std::vector<blink::IndexedDBKey>& primary_keys,
+ std::vector<blink::mojom::IDBValuePtr>* values));
void SuccessCursorPrefetch(
- const std::vector<IndexedDBKey>& keys,
- const std::vector<IndexedDBKey>& primary_keys,
- std::vector<::indexed_db::mojom::ValuePtr> values) override {
+ const std::vector<blink::IndexedDBKey>& keys,
+ const std::vector<blink::IndexedDBKey>& primary_keys,
+ std::vector<blink::mojom::IDBValuePtr> values) override {
MockedSuccessCursorPrefetch(keys, primary_keys, &values);
}
MOCK_METHOD1(MockedSuccessArray,
- void(std::vector<::indexed_db::mojom::ReturnValuePtr>* values));
+ void(std::vector<blink::mojom::IDBReturnValuePtr>* values));
void SuccessArray(
- std::vector<::indexed_db::mojom::ReturnValuePtr> values) override {
+ std::vector<blink::mojom::IDBReturnValuePtr> values) override {
MockedSuccessArray(&values);
}
- MOCK_METHOD1(SuccessKey, void(const IndexedDBKey& key));
+ MOCK_METHOD1(SuccessKey, void(const blink::IndexedDBKey& key));
MOCK_METHOD1(SuccessInteger, void(int64_t value));
MOCK_METHOD0(Success, void());
private:
- mojo::AssociatedBinding<::indexed_db::mojom::Callbacks> binding_;
+ mojo::AssociatedBinding<blink::mojom::IDBCallbacks> binding_;
DISALLOW_COPY_AND_ASSIGN(MockMojoIndexedDBCallbacks);
};
diff --git a/chromium/content/browser/indexed_db/mock_mojo_indexed_db_database_callbacks.cc b/chromium/content/browser/indexed_db/mock_mojo_indexed_db_database_callbacks.cc
index db53b3f7550..b53faf06cb3 100644
--- a/chromium/content/browser/indexed_db/mock_mojo_indexed_db_database_callbacks.cc
+++ b/chromium/content/browser/indexed_db/mock_mojo_indexed_db_database_callbacks.cc
@@ -10,9 +10,9 @@ MockMojoIndexedDBDatabaseCallbacks::MockMojoIndexedDBDatabaseCallbacks()
: binding_(this) {}
MockMojoIndexedDBDatabaseCallbacks::~MockMojoIndexedDBDatabaseCallbacks() {}
-::indexed_db::mojom::DatabaseCallbacksAssociatedPtrInfo
+blink::mojom::IDBDatabaseCallbacksAssociatedPtrInfo
MockMojoIndexedDBDatabaseCallbacks::CreateInterfacePtrAndBind() {
- ::indexed_db::mojom::DatabaseCallbacksAssociatedPtrInfo ptr_info;
+ blink::mojom::IDBDatabaseCallbacksAssociatedPtrInfo ptr_info;
binding_.Bind(::mojo::MakeRequest(&ptr_info));
return ptr_info;
}
diff --git a/chromium/content/browser/indexed_db/mock_mojo_indexed_db_database_callbacks.h b/chromium/content/browser/indexed_db/mock_mojo_indexed_db_database_callbacks.h
index cff98884f15..b19047754e9 100644
--- a/chromium/content/browser/indexed_db/mock_mojo_indexed_db_database_callbacks.h
+++ b/chromium/content/browser/indexed_db/mock_mojo_indexed_db_database_callbacks.h
@@ -8,19 +8,19 @@
#include <stdint.h>
#include "base/macros.h"
-#include "content/common/indexed_db/indexed_db.mojom.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
#include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
namespace content {
class MockMojoIndexedDBDatabaseCallbacks
- : public ::indexed_db::mojom::DatabaseCallbacks {
+ : public blink::mojom::IDBDatabaseCallbacks {
public:
MockMojoIndexedDBDatabaseCallbacks();
~MockMojoIndexedDBDatabaseCallbacks() override;
- ::indexed_db::mojom::DatabaseCallbacksAssociatedPtrInfo
+ blink::mojom::IDBDatabaseCallbacksAssociatedPtrInfo
CreateInterfacePtrAndBind();
MOCK_METHOD0(ForcedClose, void());
@@ -32,13 +32,13 @@ class MockMojoIndexedDBDatabaseCallbacks
MOCK_METHOD1(Complete, void(int64_t transaction_id));
MOCK_METHOD1(MockedChanges,
- void(::indexed_db::mojom::ObserverChangesPtr* changes));
- void Changes(::indexed_db::mojom::ObserverChangesPtr changes) override {
+ void(blink::mojom::IDBObserverChangesPtr* changes));
+ void Changes(blink::mojom::IDBObserverChangesPtr changes) override {
MockedChanges(&changes);
}
private:
- mojo::AssociatedBinding<::indexed_db::mojom::DatabaseCallbacks> binding_;
+ mojo::AssociatedBinding<blink::mojom::IDBDatabaseCallbacks> binding_;
DISALLOW_COPY_AND_ASSIGN(MockMojoIndexedDBDatabaseCallbacks);
};
diff --git a/chromium/content/browser/indexed_db/scopes/README.md b/chromium/content/browser/indexed_db/scopes/README.md
new file mode 100644
index 00000000000..75982fe42f1
--- /dev/null
+++ b/chromium/content/browser/indexed_db/scopes/README.md
@@ -0,0 +1,184 @@
+# LevelDB Scopes Implementation Design
+
+This document is the implementation plan and design for LevelDB Scopes. It serves to both document the current state and the future plans for implementing LevelDB Scopes.
+
+See LevelDB Scopes general design doc [here](https://docs.google.com/document/d/16_igCI15Gfzb6UYqeuJTmJPrzEtawz6Y1tVOKNtYgiU/edit).
+
+# Status / Current State
+
+The only thing implemented so far is the lock manager interface & descrete implementation.
+
+# Vocabulary
+
+**Scope**
+
+A scope encompases a group of changes that can be reverted. It is basically synonymous with a transaction, and would be used for readwrite and versionchange transactions in LevelDB. The scope has a defined list of key ranges where the changes can occur. It operates by keeping an undo log, which is either discarded on commit, or replayed on revert.
+
+**Undo Log**
+
+Each scope saves an undo log, which has all the information needed to undo all changes performed in the scope.
+
+**Scope Number (scope#)**
+
+Each scope has an identifier unique to the backing store that is auto-incrementing. During recovery, it is set to the minimum unused scope (see more in the recovery section).
+
+**Sequence Number (seq#)**
+
+Every undo log entry has a unique sequence number within the scope. These should start at <max int> (using Fixed64) and decrement. The sequence number '0' is reserved for the commit point
+
+**Commit Point**
+
+This signifies that a scope has been committed. It also means that a specific sequence number was written for a scope.
+
+**Key Range**
+
+Represents a range of LevelDB keys. Every operation has a key or a key range associated with it. Sometimes key ranges are expected to be re-used or modified again by subsequent operations, and sometimes key ranges are known to be never used again.
+
+**Lock**
+
+To prevent reading uncommitted data, IndexedDB 'locks' objects stores when there are (readwrite) transactions operating on them.
+
+## New LevelDB Table Data
+
+|Purpose|Key |Final format|Value (protobufs)|
+|---|---|---|---|
+|Metadata|undo-metadata|`prefix-0`|`{version: 1}`|
+|Scope Metadata|undo-scopes-<scope#>|`prefix-1-<scope#>`|key ranges if scope is active, or \<empty\> if committed.|
+|Undo log operations|undo-log-<scope#>-<seq#>|`prefix-2-<scope#>-<seq#>`|undo operation|
+|Commit point|undo-log-<scope#>-0|`prefix-2-<scope#>-0`| \<empty\> OR \<ranges to delete\> |
+
+
+### Key Format
+
+* Allow the 'user' of the scopes system to choose the key prefix (`prefix`).
+* Scope # is a varint
+* Sequence # is a Fixed64
+
+### Value Format
+
+All values will be protobufs
+
+# Operation Flows
+
+## Creating & Using a Scope
+IndexedDB Sequence
+
+* Input - key ranges for the scope. Eg - the applicable object stores (and indexes) for a readwrite txn, or a whole database for a versionchange txn.
+* If any of the key ranges are currently locked, then wait until they are free. This would replace the IDB transaction sequencing logic.
+* Create the scope
+ * Use the next available scope # (and increment the next scope #)
+ * Signal the locks service that the key ranges for this scope are now locked
+ * Write undo-scopes-scope# -> key_ranges to LevelDB
+* Enable operations on the scope (probably eventually by binding it using mojo)
+* For every operation, the scope must read the database to generate the undo log
+ * See the [Undo Operation Generation](#undo-operations) section below
+* Output - a Scope
+
+## Committing a Scope
+**IndexedDB Sequence**
+
+* Input - a Scope
+* The scope is marked as 'committed', the commit point is written to the undo log (undo-scope#-0), and the metadatais updated to remove the key ranges (undo-scopes-scope# -> <empty>). This change is flushed to disk.
+* The Cleanup & Revert Sequence is signalled for cleaning up the committed scope #.
+* Output - Scope is committed, and lock is released.
+
+## Reverting a Scope
+**Cleanup & Revert Sequence**
+
+* Input - revert a given scope number.
+* Opens a cursor to undo-<scope#>-0
+ * Cursor should be at the first undo entry
+ * If sequence #0 exists (this key exists), then error - reverting a committed scope is an invalid state in this design
+* Iterate through undo log, commiting operations and deleting each undo entry.
+* Delete the lock entry at undo-scopes-<scope#>, and flush this change to disk.
+* Output - Scope was successfully reverted, and lock released.
+
+## Startup & Recovery
+**IndexedDB Sequence**
+
+* Input - the database
+* Reads undo-metadata (fail for unknown version)
+* Opens a cursor to undo-scopes- & iterates to read in all scopes
+ * If the scope metadata has key ranges, then those are considered locked
+ * The maximum scope # is found and used to determine the next scope number (used in scope creation)
+* Signals the lock system which locks are held
+* Signals IndexedDB that it can start accepting operations (IndexedDB can now start running)
+* For every undo-scopes- metadata that is empty
+ * Kick off an [Undo Log Cleanup](#undo-log-cleanup) task to eventually clean this up.
+* For every undo-scopes- metadata with key ranges
+ * If there is a commit point for any of these scopes, then that is an invalid state / corruption (as the scopes value should have been emptied in the same writebatch that wrote the commit point).
+ * Kick off a [Reverting a Scope](#reverting-a-scope) task. This state indicates a shutdown while a revert was in progress.
+* Output - nothing, done
+
+## Undo Log Cleanup
+**Cleanup & Revert Sequence**
+
+* Input - nothing
+* Scan the undo- namespace for commit points. If a undo-scope#-0 is found, then start deleting that undo log
+ * This can happen in multiple write batches
+* If ranges are found in the undo-scope#-0 (commit point), then
+ * Those ranges are also deleted, in batches.
+ * Possibly compact these ranges at the end.
+* The undo-scope#-0 and undo-scopes-scope# entries must be deleted last, in the last deletion write batch, so this scope isn't mistaken later as something to be reverted.
+* Output - nothing
+
+# Lock Manager
+
+The scopes feature needs a fairly generic lock manager. This lock manager needs two levels, because versionchange transactions need to lock a whole database, where other transactions will lock smaller ranges within the level one range.
+
+### API Methods
+
+#### AcquireLock
+
+Accepts a lock type (shared or exclusive), a level number, a key range, and a callback which is given a moveable-only lock object, which releases its lock on destruction. The levels are totally independent from the perspective of the lock manager. IF an application wants to use multiple levels, they should employ an acquisition order (like, always acquire locks in increasing level order) so they don't deadlock.
+
+### Internal Data Structure
+
+The lock manager basically holds ranges, and needs to know if a new range intersects any old ranges. A good data structure for this is an Interval Tree.
+
+# Undo Operations
+
+## Types
+
+* `Put(key, value)`
+* `Delete(key)`
+* `DeleteRange(key_range)`
+
+## Generation
+
+### Normal Cases
+
+Note - all cases where "old_value" is used requires reading the current value from the database.
+
+**`Put(key, value)`**
+
+* `Delete(key)` if an old value doesn't exist,
+* `Put(key, old_value)` if an old value does exist, or
+* Nothing if the old value and new value matches
+
+**`Add(key, value)`**
+
+* Delete(key), trusting the client that there wasn't a value here before.
+
+**`Delete(key)`**
+
+* `Put(key, old_value)` if the old_value exists, or
+* Nothing if no old_value exists.
+
+**`DeleteRange(key_range)`**
+
+* `Put(key, old_value)` for every entry in that key range. This requires iterating the database using the key_range to find all entries.
+
+### Special Case - Empty Unique Key Range
+
+#### Creation - key range is empty initially
+
+If the values being created are in a key range that is initially empty (we trust the API caller here - there is no verification), and if the key range will never be reused if it is reverted, then the undo log can consist of a single:
+
+`DeleteRange(key_range)`
+
+Examples of this are creating new databases or indexes in a versionchange transaction. The scopes system can check to make sure it's range is empty before doing operations. This can either be done as a hint (per-range, per-scope), or always.
+
+#### Deletion - key range will never be used again.
+
+This is done by having commit ranges in the value of the commit point. A new scope is created, and commited, with the key ranges never-to-be-used-again will be the value of the commit point record.
diff --git a/chromium/content/browser/indexed_db/scopes/disjoint_range_lock_manager.cc b/chromium/content/browser/indexed_db/scopes/disjoint_range_lock_manager.cc
new file mode 100644
index 00000000000..19daa4f0a43
--- /dev/null
+++ b/chromium/content/browser/indexed_db/scopes/disjoint_range_lock_manager.cc
@@ -0,0 +1,166 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/indexed_db/scopes/disjoint_range_lock_manager.h"
+
+namespace content {
+
+DisjointRangeLockManager::LockRequest::LockRequest() = default;
+DisjointRangeLockManager::LockRequest::LockRequest(LockType type,
+ LockAquiredCallback callback)
+ : requested_type(type), callback(std::move(callback)) {}
+DisjointRangeLockManager::LockRequest::LockRequest(LockRequest&&) noexcept =
+ default;
+DisjointRangeLockManager::LockRequest::~LockRequest() = default;
+DisjointRangeLockManager::Lock::Lock() = default;
+DisjointRangeLockManager::Lock::Lock(Lock&&) noexcept = default;
+DisjointRangeLockManager::Lock::~Lock() = default;
+DisjointRangeLockManager::Lock& DisjointRangeLockManager::Lock::operator=(
+ DisjointRangeLockManager::Lock&&) noexcept = default;
+
+DisjointRangeLockManager::DisjointRangeLockManager(
+ int level_count,
+ const leveldb::Comparator* comparator,
+ scoped_refptr<base::SequencedTaskRunner> task_runner)
+ : comparator_(comparator), task_runner_(task_runner), weak_factory_(this) {
+ for (int level = 0; level < level_count; ++level) {
+ locks_.emplace_back(RangeLessThan(comparator));
+ }
+}
+
+DisjointRangeLockManager::~DisjointRangeLockManager() = default;
+
+int64_t DisjointRangeLockManager::LocksHeldForTesting() const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ int64_t locks = 0;
+ for (const LockLevelMap& map : locks_) {
+ for (const auto& pair : map) {
+ locks += pair.second.acquired_count;
+ }
+ }
+ return locks;
+}
+int64_t DisjointRangeLockManager::RequestsWaitingForTesting() const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ int64_t requests = 0;
+ for (const LockLevelMap& map : locks_) {
+ for (const auto& pair : map) {
+ requests += pair.second.queue.size();
+ }
+ }
+ return requests;
+}
+
+void DisjointRangeLockManager::AcquireLock(int level,
+ const LockRange& range,
+ LockType type,
+ LockAquiredCallback callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_LT(level, static_cast<int>(locks_.size()));
+ DCHECK_LT(comparator_->Compare(leveldb::Slice(range.begin),
+ leveldb::Slice(range.end)),
+ 0)
+ << "Range is invalid: " << range;
+
+ auto& level_locks = locks_[level];
+
+ auto it = level_locks.find(range);
+ if (it == level_locks.end()) {
+ it = level_locks
+ .emplace(std::piecewise_construct, std::forward_as_tuple(range),
+ std::forward_as_tuple())
+ .first;
+ }
+
+ DCHECK_EQ(it->first, range)
+ << range << " does not match what is in the lock map " << it->first;
+#if DCHECK_IS_ON()
+ DCHECK(IsRangeDisjointFromNeighbors(level_locks, range, comparator_))
+ << "Range not discrete: " << range;
+#endif
+ Lock& lock = it->second;
+
+ if (lock.CanBeAcquired(type)) {
+ ++lock.acquired_count;
+ lock.lock_mode = type;
+ std::move(callback).Run(
+ ScopeLock(range, level,
+ base::BindOnce(&DisjointRangeLockManager::LockReleased,
+ weak_factory_.GetWeakPtr(), level, range)));
+ } else {
+ lock.queue.emplace_back(type, std::move(callback));
+ }
+}
+
+void DisjointRangeLockManager::RemoveLockRange(int level,
+ const LockRange& range) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_LT(level, static_cast<int>(locks_.size()));
+ auto& level_locks = locks_[level];
+ auto it = level_locks.find(range);
+ if (it != level_locks.end()) {
+ DCHECK_EQ(0, it->second.acquired_count);
+ level_locks.erase(it);
+ }
+}
+
+void DisjointRangeLockManager::LockReleased(int level, LockRange range) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_LT(level, static_cast<int>(locks_.size()));
+ auto& level_locks = locks_[level];
+ auto it = level_locks.find(range);
+ DCHECK(it != level_locks.end());
+ Lock& lock = it->second;
+
+ DCHECK_GT(lock.acquired_count, 0);
+ --(lock.acquired_count);
+ if (lock.acquired_count == 0) {
+ // Either the lock isn't acquired yet or more shared locks can be granted.
+ while (!lock.queue.empty() &&
+ (lock.acquired_count == 0 ||
+ lock.queue.front().requested_type == LockType::kShared)) {
+ LockRequest requester = std::move(lock.queue.front());
+ lock.queue.pop_front();
+ ++lock.acquired_count;
+ lock.lock_mode = requester.requested_type;
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ std::move(requester.callback),
+ ScopeLock(range, level,
+ base::BindOnce(&DisjointRangeLockManager::LockReleased,
+ weak_factory_.GetWeakPtr(), level,
+ std::move(range)))));
+ // This can only happen if acquired_count was 0.
+ if (requester.requested_type == LockType::kExclusive)
+ return;
+ }
+ }
+}
+
+#if DCHECK_IS_ON()
+// static
+bool DisjointRangeLockManager::IsRangeDisjointFromNeighbors(
+ const LockLevelMap& map,
+ const LockRange& range,
+ const leveldb::Comparator* const comparator) {
+ DCHECK_EQ(map.count(range), 1ull);
+ auto it = map.find(range);
+ auto next_it = it;
+ ++next_it;
+ if (next_it != map.end()) {
+ return comparator->Compare(leveldb::Slice(range.end),
+ leveldb::Slice(next_it->first.begin)) <= 0;
+ }
+ auto last_it = it;
+ if (last_it != map.begin()) {
+ --last_it;
+ return comparator->Compare(leveldb::Slice(last_it->first.end),
+ leveldb::Slice(range.begin)) <= 0;
+ }
+ return true;
+}
+#endif
+
+} // namespace content
diff --git a/chromium/content/browser/indexed_db/scopes/disjoint_range_lock_manager.h b/chromium/content/browser/indexed_db/scopes/disjoint_range_lock_manager.h
new file mode 100644
index 00000000000..f01a5abf161
--- /dev/null
+++ b/chromium/content/browser/indexed_db/scopes/disjoint_range_lock_manager.h
@@ -0,0 +1,127 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_INDEXED_DB_SCOPES_DISJOINT_RANGE_LOCK_MANAGER_H_
+#define CONTENT_BROWSER_INDEXED_DB_SCOPES_DISJOINT_RANGE_LOCK_MANAGER_H_
+
+#include <list>
+#include <vector>
+
+#include "base/containers/flat_map.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "base/sequence_checker.h"
+#include "base/sequenced_task_runner.h"
+#include "content/browser/indexed_db/scopes/scopes_lock_manager.h"
+#include "content/common/content_export.h"
+#include "third_party/leveldatabase/src/include/leveldb/comparator.h"
+#include "third_party/leveldatabase/src/include/leveldb/slice.h"
+
+namespace content {
+
+// Holds locks of the scopes system. To be performant without an Interval Tree,
+// this implementation has the following invariants:
+// * All lock range requests at a level must be disjoint - they cannot overlap.
+// * Lock ranges are remembered for future performance - remove them using
+// RemoveLockRange.
+// * All calls must happen from the same sequenced task runner.
+class CONTENT_EXPORT DisjointRangeLockManager : public ScopesLockManager {
+ public:
+ // Creates a lock manager with the given number of levels, the comparator for
+ // leveldb keys, and the current task runner that we are running on. The task
+ // runner will be used for the lock acquisition callbacks.
+ DisjointRangeLockManager(
+ int level_count,
+ const leveldb::Comparator* comparator,
+ scoped_refptr<base::SequencedTaskRunner> task_runner);
+ ~DisjointRangeLockManager() override;
+
+ int64_t LocksHeldForTesting() const override;
+ int64_t RequestsWaitingForTesting() const override;
+
+ void AcquireLock(int level,
+ const LockRange& range,
+ LockType type,
+ LockAquiredCallback callback) override;
+
+ // Remove the given lock range at the given level. The lock range must not be
+ // in use. Use this if the lock will never be used again.
+ void RemoveLockRange(int level, const LockRange& range);
+
+ private:
+ struct LockRequest {
+ public:
+ LockRequest();
+ LockRequest(LockRequest&&) noexcept;
+ LockRequest(LockType type, LockAquiredCallback callback);
+ ~LockRequest();
+
+ LockType requested_type = LockType::kShared;
+ LockAquiredCallback callback;
+ };
+
+ // Represents a lock, which has a range and a level. To support shared access,
+ // there can be multiple acquisitions of this lock, represented in
+ // |acquired_count|. Also holds the pending requests for this lock.
+ struct Lock {
+ public:
+ Lock();
+ Lock(Lock&&) noexcept;
+ ~Lock();
+ Lock& operator=(Lock&&) noexcept;
+
+ bool CanBeAcquired(LockType lock_type) {
+ return acquired_count == 0 ||
+ (queue.empty() && this->lock_mode == LockType::kShared &&
+ lock_type == LockType::kShared);
+ }
+
+ int acquired_count = 0;
+ LockType lock_mode = LockType::kShared;
+ std::list<LockRequest> queue;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Lock);
+ };
+
+ // This is a proxy between a LevelDB Comparator and the interface expected by
+ // std::map. It sorts using the |begin| entry of the ranges.
+ class RangeLessThan {
+ public:
+ explicit RangeLessThan(const leveldb::Comparator* comparator)
+ : comparator_(comparator) {}
+ bool operator()(const LockRange& a, const LockRange& b) const {
+ return comparator_->Compare(leveldb::Slice(a.begin),
+ leveldb::Slice(b.begin)) < 0;
+ }
+
+ private:
+ const leveldb::Comparator* const comparator_;
+ };
+
+ using LockLevelMap = base::flat_map<LockRange, Lock, RangeLessThan>;
+
+ void LockReleased(int level, LockRange range);
+
+#if DCHECK_IS_ON()
+ static bool IsRangeDisjointFromNeighbors(
+ const LockLevelMap& map,
+ const LockRange& range,
+ const leveldb::Comparator* const comparator_);
+#endif
+
+ const leveldb::Comparator* const comparator_;
+ const scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ // This vector should never be modified after construction.
+ std::vector<LockLevelMap> locks_;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+ base::WeakPtrFactory<DisjointRangeLockManager> weak_factory_;
+ DISALLOW_COPY_AND_ASSIGN(DisjointRangeLockManager);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_INDEXED_DB_SCOPES_DISJOINT_RANGE_LOCK_MANAGER_H_
diff --git a/chromium/content/browser/indexed_db/scopes/disjoint_range_lock_manager_unittest.cc b/chromium/content/browser/indexed_db/scopes/disjoint_range_lock_manager_unittest.cc
new file mode 100644
index 00000000000..1e952f51e2e
--- /dev/null
+++ b/chromium/content/browser/indexed_db/scopes/disjoint_range_lock_manager_unittest.cc
@@ -0,0 +1,221 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <content/browser/indexed_db/scopes/disjoint_range_lock_manager.h>
+#include <content/test/barrier_builder.h>
+
+#include "base/barrier_closure.h"
+#include "base/bind_helpers.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace {
+using ScopeLock = ScopesLockManager::ScopeLock;
+using LockRange = ScopesLockManager::LockRange;
+
+template <typename T>
+void SetValue(T* out, T value) {
+ *out = value;
+}
+
+std::string IntegerKey(size_t num) {
+ return base::StringPrintf("%010zd", num);
+}
+
+void StoreLock(ScopeLock* lock_out, base::OnceClosure done, ScopeLock lock) {
+ (*lock_out) = std::move(lock);
+ std::move(done).Run();
+}
+
+class DisjointRangeLockManagerTest : public testing::Test {
+ public:
+ DisjointRangeLockManagerTest() = default;
+ ~DisjointRangeLockManagerTest() override = default;
+
+ private:
+ base::test::ScopedTaskEnvironment task_env_;
+};
+
+TEST_F(DisjointRangeLockManagerTest, BasicAcquisition) {
+ const size_t kTotalLocks = 1000;
+ DisjointRangeLockManager lock_manager(1, leveldb::BytewiseComparator(),
+ base::SequencedTaskRunnerHandle::Get());
+
+ EXPECT_EQ(0ll, lock_manager.LocksHeldForTesting());
+ EXPECT_EQ(0ll, lock_manager.RequestsWaitingForTesting());
+
+ base::RunLoop loop;
+ std::vector<ScopeLock> locks;
+ locks.resize(kTotalLocks);
+ {
+ BarrierBuilder barrier(loop.QuitClosure());
+
+ for (size_t i = 0; i < kTotalLocks / 2; ++i) {
+ LockRange range = {IntegerKey(i), IntegerKey(i + 1)};
+ lock_manager.AcquireLock(
+ 0, range, ScopesLockManager::LockType::kExclusive,
+ base::BindOnce(&StoreLock, &locks[i], barrier.AddClosure()));
+ }
+
+ for (size_t i = kTotalLocks - 1; i >= kTotalLocks / 2; --i) {
+ LockRange range = {IntegerKey(i), IntegerKey(i + 1)};
+ lock_manager.AcquireLock(
+ 0, range, ScopesLockManager::LockType::kExclusive,
+ base::BindOnce(&StoreLock, &locks[i], barrier.AddClosure()));
+ }
+ }
+ loop.Run();
+ EXPECT_EQ(static_cast<int64_t>(kTotalLocks),
+ lock_manager.LocksHeldForTesting());
+ EXPECT_EQ(0ll, lock_manager.RequestsWaitingForTesting());
+ // All locks should be acquired.
+ for (const auto& lock : locks) {
+ EXPECT_TRUE(lock.is_locked());
+ }
+
+ locks.clear();
+ EXPECT_EQ(0ll, lock_manager.LocksHeldForTesting());
+}
+
+TEST_F(DisjointRangeLockManagerTest, Shared) {
+ DisjointRangeLockManager lock_manager(1, leveldb::BytewiseComparator(),
+ base::SequencedTaskRunnerHandle::Get());
+ EXPECT_EQ(0ll, lock_manager.LocksHeldForTesting());
+ EXPECT_EQ(0ll, lock_manager.RequestsWaitingForTesting());
+
+ LockRange range = {IntegerKey(0), IntegerKey(1)};
+
+ ScopeLock lock1;
+ ScopeLock lock2;
+ base::RunLoop loop;
+ {
+ BarrierBuilder barrier(loop.QuitClosure());
+ lock_manager.AcquireLock(
+ 0, range, ScopesLockManager::LockType::kShared,
+ base::BindOnce(&StoreLock, &lock1, barrier.AddClosure()));
+ lock_manager.AcquireLock(
+ 0, range, ScopesLockManager::LockType::kShared,
+ base::BindOnce(&StoreLock, &lock2, barrier.AddClosure()));
+ }
+ loop.Run();
+ EXPECT_EQ(2ll, lock_manager.LocksHeldForTesting());
+
+ EXPECT_TRUE(lock1.is_locked());
+ EXPECT_TRUE(lock2.is_locked());
+}
+
+TEST_F(DisjointRangeLockManagerTest, SharedAndExclusiveQueuing) {
+ DisjointRangeLockManager lock_manager(1, leveldb::BytewiseComparator(),
+ base::SequencedTaskRunnerHandle::Get());
+ EXPECT_EQ(0ll, lock_manager.LocksHeldForTesting());
+ EXPECT_EQ(0ll, lock_manager.RequestsWaitingForTesting());
+
+ LockRange range = {IntegerKey(0), IntegerKey(1)};
+
+ ScopeLock shared_lock1;
+ ScopeLock shared_lock2;
+ ScopeLock exclusive_lock3;
+ ScopeLock shared_lock4;
+
+ {
+ base::RunLoop loop;
+ base::RepeatingClosure barrier =
+ base::BarrierClosure(2, loop.QuitClosure());
+ lock_manager.AcquireLock(
+ 0, range, ScopesLockManager::LockType::kShared,
+ base::BindOnce(&StoreLock, &shared_lock1, barrier));
+ lock_manager.AcquireLock(
+ 0, range, ScopesLockManager::LockType::kShared,
+ base::BindOnce(&StoreLock, &shared_lock2, barrier));
+ loop.Run();
+ }
+
+ // Both of the following locks should be queued - the exclusive is next in
+ // line, then the shared lock will come after it.
+ lock_manager.AcquireLock(
+ 0, range, ScopesLockManager::LockType::kExclusive,
+ base::BindOnce(&StoreLock, &exclusive_lock3, base::DoNothing::Once()));
+ lock_manager.AcquireLock(
+ 0, range, ScopesLockManager::LockType::kShared,
+ base::BindOnce(&StoreLock, &shared_lock4, base::DoNothing::Once()));
+ // Flush the task queue.
+ {
+ base::RunLoop loop;
+ base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ loop.QuitClosure());
+ loop.Run();
+ }
+ EXPECT_FALSE(exclusive_lock3.is_locked());
+ EXPECT_FALSE(shared_lock4.is_locked());
+ EXPECT_EQ(2ll, lock_manager.LocksHeldForTesting());
+ EXPECT_EQ(2ll, lock_manager.RequestsWaitingForTesting());
+
+ // Release the shared locks.
+ shared_lock1.Release();
+ shared_lock2.Release();
+ EXPECT_FALSE(shared_lock1.is_locked());
+ EXPECT_FALSE(shared_lock2.is_locked());
+
+ // Flush the task queue to propagate the lock releases and grant the exclusive
+ // lock.
+ {
+ base::RunLoop loop;
+ base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ loop.QuitClosure());
+ loop.Run();
+ }
+ EXPECT_TRUE(exclusive_lock3.is_locked());
+ EXPECT_FALSE(shared_lock4.is_locked());
+ EXPECT_EQ(1ll, lock_manager.LocksHeldForTesting());
+ EXPECT_EQ(1ll, lock_manager.RequestsWaitingForTesting());
+
+ exclusive_lock3.Release();
+ EXPECT_FALSE(exclusive_lock3.is_locked());
+
+ // Flush the task queue to propagate the lock releases and grant the exclusive
+ // lock.
+ {
+ base::RunLoop loop;
+ base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ loop.QuitClosure());
+ loop.Run();
+ }
+ EXPECT_TRUE(shared_lock4.is_locked());
+ EXPECT_EQ(1ll, lock_manager.LocksHeldForTesting());
+ EXPECT_EQ(0ll, lock_manager.RequestsWaitingForTesting());
+}
+
+TEST_F(DisjointRangeLockManagerTest, LevelsOperateSeparately) {
+ DisjointRangeLockManager lock_manager(2, leveldb::BytewiseComparator(),
+ base::SequencedTaskRunnerHandle::Get());
+ base::RunLoop loop;
+ ScopeLock l0_lock;
+ ScopeLock l1_lock;
+ {
+ BarrierBuilder barrier(loop.QuitClosure());
+ LockRange range = {IntegerKey(0), IntegerKey(1)};
+ lock_manager.AcquireLock(
+ 0, range, ScopesLockManager::LockType::kExclusive,
+ base::BindOnce(&StoreLock, &l0_lock, barrier.AddClosure()));
+ lock_manager.AcquireLock(
+ 1, range, ScopesLockManager::LockType::kExclusive,
+ base::BindOnce(&StoreLock, &l1_lock, barrier.AddClosure()));
+ }
+ loop.Run();
+ EXPECT_TRUE(l0_lock.is_locked());
+ EXPECT_TRUE(l1_lock.is_locked());
+ EXPECT_EQ(2ll, lock_manager.LocksHeldForTesting());
+ EXPECT_EQ(0ll, lock_manager.RequestsWaitingForTesting());
+ l0_lock.Release();
+ l1_lock.Release();
+ EXPECT_EQ(0ll, lock_manager.LocksHeldForTesting());
+}
+
+} // namespace
+} // namespace content
diff --git a/chromium/content/browser/indexed_db/scopes/scopes_lock_manager.cc b/chromium/content/browser/indexed_db/scopes/scopes_lock_manager.cc
new file mode 100644
index 00000000000..1b687396daf
--- /dev/null
+++ b/chromium/content/browser/indexed_db/scopes/scopes_lock_manager.cc
@@ -0,0 +1,61 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/indexed_db/scopes/scopes_lock_manager.h"
+
+#include <ostream>
+
+namespace content {
+
+ScopesLockManager::LockRange::LockRange(std::string begin, std::string end)
+ : begin(std::move(begin)), end(std::move(end)) {}
+
+ScopesLockManager::ScopeLock::ScopeLock() = default;
+ScopesLockManager::ScopeLock::ScopeLock(ScopeLock&& other) noexcept {
+ DCHECK(!this->is_locked_) << "Cannot move a lock onto an active lock.";
+ this->is_locked_ = other.is_locked_;
+ this->range_ = std::move(other.range_);
+ this->level_ = other.level_;
+ this->closure_runner_ = std::move(other.closure_runner_);
+ other.is_locked_ = false;
+}
+ScopesLockManager::ScopeLock::ScopeLock(LockRange range,
+ int level,
+ base::OnceClosure closure)
+ : is_locked_(!closure.is_null()),
+ range_(std::move(range)),
+ level_(level),
+ closure_runner_(std::move(closure)) {}
+
+ScopesLockManager::ScopeLock& ScopesLockManager::ScopeLock::operator=(
+ ScopesLockManager::ScopeLock&& other) noexcept {
+ DCHECK(!this->is_locked_);
+ this->is_locked_ = other.is_locked_;
+ this->range_ = std::move(other.range_);
+ this->level_ = other.level_;
+ this->closure_runner_ = std::move(other.closure_runner_);
+ other.is_locked_ = false;
+ return *this;
+};
+
+void ScopesLockManager::ScopeLock::Release() {
+ is_locked_ = false;
+ closure_runner_.RunAndReset();
+}
+
+std::ostream& operator<<(std::ostream& out,
+ const ScopesLockManager::LockRange& range) {
+ return out << "<ScopesLockManager::ScopeLock>{begin: " << range.begin
+ << ", end: " << range.end << "}";
+}
+
+bool operator==(const ScopesLockManager::LockRange& x,
+ const ScopesLockManager::LockRange& y) {
+ return x.begin == y.begin && x.end == y.end;
+}
+bool operator!=(const ScopesLockManager::LockRange& x,
+ const ScopesLockManager::LockRange& y) {
+ return !(x == y);
+}
+} // namespace content
diff --git a/chromium/content/browser/indexed_db/scopes/scopes_lock_manager.h b/chromium/content/browser/indexed_db/scopes/scopes_lock_manager.h
new file mode 100644
index 00000000000..075da81bd22
--- /dev/null
+++ b/chromium/content/browser/indexed_db/scopes/scopes_lock_manager.h
@@ -0,0 +1,103 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_INDEXED_DB_SCOPES_SCOPES_LOCK_MANAGER_H_
+#define CONTENT_BROWSER_INDEXED_DB_SCOPES_SCOPES_LOCK_MANAGER_H_
+
+#include <iosfwd>
+#include <string>
+
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+// Generic two-level lock management system based on ranges. Granted locks are
+// represented by the |ScopeLock| class.
+class CONTENT_EXPORT ScopesLockManager {
+ public:
+ // Shared locks can share access to a lock range, while exclusive locks
+ // require that they are the only lock for their range.
+ enum class LockType { kShared, kExclusive };
+
+ // The range is [begin, end).
+ struct CONTENT_EXPORT LockRange {
+ LockRange(std::string begin, std::string end);
+ LockRange() = default;
+ ~LockRange() = default;
+ std::string begin;
+ std::string end;
+ };
+
+ // Represents a granted lock in the ScopesLockManager. When this object is
+ // destroyed, the lock is released. Since default construction is supported,
+ // |is_locked()| can be used to inquire locked status. Also, |Release()| can
+ // be called to manually release the lock, which appropriately updates the
+ // |is_locked()| result.
+ class CONTENT_EXPORT ScopeLock {
+ public:
+ ScopeLock();
+ ScopeLock(ScopeLock&&) noexcept;
+ // The |closure| is called when the lock is released, either by destruction
+ // of this object or by the |Released()| call. It will be called
+ // synchronously on the sequence runner this lock is released on.
+ ScopeLock(LockRange range, int level, base::OnceClosure closure);
+ ~ScopeLock() = default;
+ // This does NOT release the lock if one is being held.
+ ScopeLock& operator=(ScopeLock&&) noexcept;
+
+ // Returns true if this object is holding a lock.
+ bool is_locked() const { return is_locked_; }
+
+ // Releases this lock.
+ void Release();
+
+ int level() const { return level_; }
+ const LockRange& range() const { return range_; }
+
+ private:
+ bool is_locked_ = false;
+ LockRange range_;
+ int level_ = 0;
+ base::ScopedClosureRunner closure_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopeLock);
+ };
+
+ using LockAquiredCallback = base::OnceCallback<void(ScopeLock)>;
+
+ ScopesLockManager() = default;
+
+ virtual ~ScopesLockManager() = default;
+
+ virtual int64_t LocksHeldForTesting() const = 0;
+ virtual int64_t RequestsWaitingForTesting() const = 0;
+
+ // Acquires a lock for a given lock level. Lock levels are treated as
+ // completely independent domains. The lock levels start at zero.
+ virtual void AcquireLock(int level,
+ const LockRange& range,
+ LockType type,
+ LockAquiredCallback callback) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopesLockManager);
+};
+
+// Stream operator so lock range can be used in log statements.
+CONTENT_EXPORT std::ostream& operator<<(
+ std::ostream& out,
+ const ScopesLockManager::LockRange& range);
+
+CONTENT_EXPORT bool operator==(const ScopesLockManager::LockRange& x,
+ const ScopesLockManager::LockRange& y);
+CONTENT_EXPORT bool operator!=(const ScopesLockManager::LockRange& x,
+ const ScopesLockManager::LockRange& y);
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_INDEXED_DB_SCOPES_SCOPES_LOCK_MANAGER_H_
diff --git a/chromium/content/browser/indexed_db/scopes/scopes_lock_manager_unittest.cc b/chromium/content/browser/indexed_db/scopes/scopes_lock_manager_unittest.cc
new file mode 100644
index 00000000000..a4240c660f8
--- /dev/null
+++ b/chromium/content/browser/indexed_db/scopes/scopes_lock_manager_unittest.cc
@@ -0,0 +1,17 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/indexed_db/scopes/scopes_lock_manager.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+TEST(ScopesLockManager, TestRangePopulation) {
+ ScopesLockManager::LockRange range("a", "b");
+ EXPECT_EQ("a", range.begin);
+ EXPECT_EQ("b", range.end);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/isolated_origin_browsertest.cc b/chromium/content/browser/isolated_origin_browsertest.cc
index 365f03302cb..7c0f014d404 100644
--- a/chromium/content/browser/isolated_origin_browsertest.cc
+++ b/chromium/content/browser/isolated_origin_browsertest.cc
@@ -568,10 +568,12 @@ IN_PROC_BROWSER_TEST_F(IsolatedOriginTest, ProcessLimit) {
// Sanity-check IsSuitableHost values for the current processes.
BrowserContext* browser_context = web_contents()->GetBrowserContext();
auto is_suitable_host = [browser_context](RenderProcessHost* process,
- GURL url) {
- return RenderProcessHostImpl::IsSuitableHost(
- process, browser_context,
- SiteInstance::GetSiteForURL(browser_context, url));
+ const GURL& url) {
+ GURL site_url(SiteInstance::GetSiteForURL(browser_context, url));
+ GURL lock_url(
+ SiteInstanceImpl::DetermineProcessLockURL(browser_context, url));
+ return RenderProcessHostImpl::IsSuitableHost(process, browser_context,
+ site_url, lock_url);
};
EXPECT_TRUE(is_suitable_host(foo_process, foo_url));
EXPECT_FALSE(is_suitable_host(foo_process, isolated_foo_url));
@@ -1102,10 +1104,14 @@ class IsolatedOriginFieldTrialTest : public ContentBrowserTest {
};
IN_PROC_BROWSER_TEST_F(IsolatedOriginFieldTrialTest, Test) {
+ bool expected_to_isolate = !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableSiteIsolationTrials);
+
auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
- EXPECT_TRUE(policy->IsIsolatedOrigin(
- url::Origin::Create(GURL("https://field.trial.com/"))));
- EXPECT_TRUE(
+ EXPECT_EQ(expected_to_isolate, policy->IsIsolatedOrigin(url::Origin::Create(
+ GURL("https://field.trial.com/"))));
+ EXPECT_EQ(
+ expected_to_isolate,
policy->IsIsolatedOrigin(url::Origin::Create(GURL("https://bar.com/"))));
}
diff --git a/chromium/content/browser/keyboard_lock/keyboard_lock_service_impl.cc b/chromium/content/browser/keyboard_lock/keyboard_lock_service_impl.cc
index f783d5356c8..b0aa16010bb 100644
--- a/chromium/content/browser/keyboard_lock/keyboard_lock_service_impl.cc
+++ b/chromium/content/browser/keyboard_lock/keyboard_lock_service_impl.cc
@@ -38,20 +38,22 @@ void LogKeyboardLockMethodCalled(KeyboardLockMethods method) {
} // namespace
KeyboardLockServiceImpl::KeyboardLockServiceImpl(
- RenderFrameHost* render_frame_host)
- : render_frame_host_(static_cast<RenderFrameHostImpl*>(render_frame_host)) {
+ RenderFrameHost* render_frame_host,
+ blink::mojom::KeyboardLockServiceRequest request)
+ : FrameServiceBase(render_frame_host, std::move(request)),
+ render_frame_host_(static_cast<RenderFrameHostImpl*>(render_frame_host)) {
DCHECK(render_frame_host_);
}
-KeyboardLockServiceImpl::~KeyboardLockServiceImpl() = default;
-
// static
void KeyboardLockServiceImpl::CreateMojoService(
RenderFrameHost* render_frame_host,
blink::mojom::KeyboardLockServiceRequest request) {
- mojo::MakeStrongBinding(
- std::make_unique<KeyboardLockServiceImpl>(render_frame_host),
- std::move(request));
+ DCHECK(render_frame_host);
+
+ // The object is bound to the lifetime of |render_frame_host| and the mojo
+ // connection. See FrameServiceBase for details.
+ new KeyboardLockServiceImpl(render_frame_host, std::move(request));
}
void KeyboardLockServiceImpl::RequestKeyboardLock(
@@ -131,4 +133,6 @@ void KeyboardLockServiceImpl::GetKeyboardLayoutMap(
std::move(callback).Run(std::move(response));
}
+KeyboardLockServiceImpl::~KeyboardLockServiceImpl() = default;
+
} // namespace content
diff --git a/chromium/content/browser/keyboard_lock/keyboard_lock_service_impl.h b/chromium/content/browser/keyboard_lock/keyboard_lock_service_impl.h
index 19c2f994758..eecefd26e44 100644
--- a/chromium/content/browser/keyboard_lock/keyboard_lock_service_impl.h
+++ b/chromium/content/browser/keyboard_lock/keyboard_lock_service_impl.h
@@ -9,6 +9,7 @@
#include <vector>
#include "content/common/content_export.h"
+#include "content/public/browser/frame_service_base.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "third_party/blink/public/platform/modules/keyboard_lock/keyboard_lock.mojom.h"
@@ -17,11 +18,11 @@ namespace content {
class RenderFrameHost;
class RenderFrameHostImpl;
-class CONTENT_EXPORT KeyboardLockServiceImpl
- : public blink::mojom::KeyboardLockService {
+class CONTENT_EXPORT KeyboardLockServiceImpl final
+ : public FrameServiceBase<blink::mojom::KeyboardLockService> {
public:
- explicit KeyboardLockServiceImpl(RenderFrameHost* render_frame_host);
- ~KeyboardLockServiceImpl() override;
+ KeyboardLockServiceImpl(RenderFrameHost* render_frame_host,
+ blink::mojom::KeyboardLockServiceRequest request);
static void CreateMojoService(
RenderFrameHost* render_frame_host,
@@ -34,6 +35,9 @@ class CONTENT_EXPORT KeyboardLockServiceImpl
void GetKeyboardLayoutMap(GetKeyboardLayoutMapCallback callback) override;
private:
+ // |this| can only be destroyed by FrameServiceBase.
+ ~KeyboardLockServiceImpl() override;
+
RenderFrameHostImpl* const render_frame_host_;
};
diff --git a/chromium/content/browser/loader/cross_site_document_blocking_browsertest.cc b/chromium/content/browser/loader/cross_site_document_blocking_browsertest.cc
index 321ab2c8e87..fa11009de25 100644
--- a/chromium/content/browser/loader/cross_site_document_blocking_browsertest.cc
+++ b/chromium/content/browser/loader/cross_site_document_blocking_browsertest.cc
@@ -89,7 +89,7 @@ void InspectHistograms(const base::HistogramTester& histograms,
const std::string& resource_name,
ResourceType resource_type) {
// //services/network doesn't have access to content::ResourceType and
- // therefore cannot log some XSDB UMAs.
+ // therefore cannot log some CORB UMAs.
bool is_restricted_uma_expected = false;
if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
is_restricted_uma_expected = true;
@@ -613,38 +613,21 @@ IN_PROC_BROWSER_TEST_F(CrossSiteDocumentBlockingTest, BlockHeaders) {
ASSERT_EQ(net::OK, interceptor.completion_status().error_code);
ASSERT_TRUE(interceptor.completion_status().should_report_corb_blocking);
- // Verify that safelisted headers have not been removed by XSDB.
- // See https://fetch.spec.whatwg.org/#cors-safelisted-response-header-name.
+ // Verify that most response headers have been removed by CORB.
const std::string& headers =
interceptor.response_head().headers->raw_headers();
- EXPECT_THAT(headers,
- HasSubstr("Cache-Control: no-cache, no-store, must-revalidate"));
- EXPECT_THAT(headers, HasSubstr("Content-Language: TestLanguage"));
- EXPECT_THAT(headers,
- HasSubstr("Content-Type: application/json; charset=utf-8"));
- EXPECT_THAT(headers, HasSubstr("Expires: Wed, 21 Oct 2199 07:28:00 GMT"));
- EXPECT_THAT(headers,
- HasSubstr("Last-Modified: Wed, 07 Feb 2018 13:55:00 PST"));
- EXPECT_THAT(headers, HasSubstr("Pragma: TestPragma"));
-
- // Make sure the test covers all the safelisted headers known to the product
- // code.
- for (const std::string& safelisted_header :
- network::CrossOriginReadBlocking::GetCorsSafelistedHeadersForTesting()) {
- EXPECT_TRUE(
- interceptor.response_head().headers->HasHeader(safelisted_header));
-
- std::string value;
- interceptor.response_head().headers->EnumerateHeader(
- nullptr, safelisted_header, &value);
- EXPECT_FALSE(value.empty());
- }
-
- // Verify that other response headers have been removed by XSDB.
+ EXPECT_THAT(headers, HasSubstr("Access-Control-Allow-Origin: https://other"));
+ EXPECT_THAT(headers, Not(HasSubstr("Cache-Control")));
+ EXPECT_THAT(headers, Not(HasSubstr("Content-Language")));
EXPECT_THAT(headers, Not(HasSubstr("Content-Length")));
- EXPECT_THAT(headers, Not(HasSubstr("X-My-Secret-Header")));
+ EXPECT_THAT(headers, Not(HasSubstr("Content-Type")));
+ EXPECT_THAT(headers, Not(HasSubstr("Expires")));
+ EXPECT_THAT(headers, Not(HasSubstr("Last-Modified")));
EXPECT_THAT(headers, Not(HasSubstr("MySecretCookieKey")));
EXPECT_THAT(headers, Not(HasSubstr("MySecretCookieValue")));
+ EXPECT_THAT(headers, Not(HasSubstr("Pragma")));
+ EXPECT_THAT(headers, Not(HasSubstr("X-Content-Type-Options")));
+ EXPECT_THAT(headers, Not(HasSubstr("X-My-Secret-Header")));
// Verify that the body is empty.
EXPECT_EQ("", interceptor.response_body());
@@ -899,7 +882,7 @@ IN_PROC_BROWSER_TEST_F(CrossSiteDocumentBlockingServiceWorkerTest, NoNetwork) {
}); )";
EXPECT_TRUE(ExecuteScriptAndExtractString(shell(), script, &response));
- // Verify that XSDB didn't block the response (since it was "faked" within the
+ // Verify that CORB didn't block the response (since it was "faked" within the
// service worker and didn't cross any security boundaries).
EXPECT_EQ("Response created by service worker", response);
InspectHistograms(histograms, kShouldBeAllowedWithoutSniffing, "blah.html",
@@ -938,13 +921,13 @@ IN_PROC_BROWSER_TEST_F(CrossSiteDocumentBlockingServiceWorkerTest,
std::string response;
EXPECT_TRUE(ExecuteScriptAndExtractString(shell(), script, &response));
- // Verify that XSDB blocked the response from the network (from
+ // Verify that CORB blocked the response from the network (from
// |cross_origin_https_server_|) to the service worker.
InspectHistograms(histograms, kShouldBeBlockedWithoutSniffing, "network.txt",
RESOURCE_TYPE_XHR);
// Verify that the service worker replied with an expected error.
- // Replying with an error means that XSDB is only active once (for the
+ // Replying with an error means that CORB is only active once (for the
// initial, real network request) and therefore the test doesn't get
// confused (second successful response would have added noise to the
// histograms captured by the test).
diff --git a/chromium/content/browser/loader/cross_site_document_resource_handler.cc b/chromium/content/browser/loader/cross_site_document_resource_handler.cc
index 90792270128..585868689f6 100644
--- a/chromium/content/browser/loader/cross_site_document_resource_handler.cc
+++ b/chromium/content/browser/loader/cross_site_document_resource_handler.cc
@@ -221,6 +221,16 @@ void CrossSiteDocumentResourceHandler::OnResponseStarted(
std::unique_ptr<ResourceController> controller) {
has_response_started_ = true;
+ if (request()->initiator().has_value()) {
+ const char* initiator_scheme_exception =
+ GetContentClient()
+ ->browser()
+ ->GetInitiatorSchemeBypassingDocumentBlocking();
+ is_initiator_scheme_excluded_ =
+ initiator_scheme_exception &&
+ request()->initiator().value().scheme() == initiator_scheme_exception;
+ }
+
network::CrossOriginReadBlocking::LogAction(
network::CrossOriginReadBlocking::Action::kResponseStarted);
@@ -358,6 +368,12 @@ void CrossSiteDocumentResourceHandler::OnReadCompleted(
return;
}
+ // If |next_handler_->OnReadCompleted(...)| was not called above, then the
+ // response bytes are being accumulated in the local buffer we've allocated in
+ // ResumeOnWillRead.
+ const size_t new_data_offset = local_buffer_bytes_read_;
+ local_buffer_bytes_read_ += bytes_read;
+
// If we intended to block the response and haven't sniffed yet, try to
// confirm that we should block it. If sniffing is needed, look at the local
// buffer and either report that zero bytes were read (to indicate the
@@ -377,8 +393,6 @@ void CrossSiteDocumentResourceHandler::OnReadCompleted(
// JSONP, or another allowable data type and we should let it through.
// Record how many bytes were read to see how often it's too small. (This
// will typically be under 100,000.)
- const size_t new_data_offset = local_buffer_bytes_read_;
- local_buffer_bytes_read_ += bytes_read;
DCHECK_LE(local_buffer_bytes_read_, next_handler_buffer_size_);
const bool more_data_possible =
bytes_read != 0 && local_buffer_bytes_read_ < net::kMaxBytesToSniff &&
@@ -406,6 +420,16 @@ void CrossSiteDocumentResourceHandler::OnReadCompleted(
}
}
+ // At this point the block-vs-allow decision was made, but might be still
+ // suppressed because of |is_initiator_scheme_excluded_|. We perform the
+ // suppression at such a late point, because we want to ensure we only call
+ // LogInitiatorSchemeBypassingDocumentBlocking for cases that actuall matter
+ // in practice.
+ if (confirmed_blockable && is_initiator_scheme_excluded_) {
+ initiator_scheme_prevented_blocking_ = true;
+ confirmed_blockable = false;
+ }
+
// At this point we have already made a block-vs-allow decision and we know
// that we can wake the |next_handler_| and let it catch-up with our
// processing of the response. The first step will always be calling
@@ -532,10 +556,22 @@ void CrossSiteDocumentResourceHandler::OnResponseCompleted(
next_handler_->OnResponseCompleted(net::URLRequestStatus(),
std::move(controller));
} else {
- // Only report XSDB status for successful (i.e. non-aborted,
+ // Only report CORB status for successful (i.e. non-aborted,
// non-errored-out) requests.
- if (status.is_success())
+ if (status.is_success()) {
analyzer_->LogAllowedResponse();
+ if (initiator_scheme_prevented_blocking_ &&
+ analyzer_->ShouldReportBlockedResponse() && GetRequestInfo()) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&ContentBrowserClient::
+ LogInitiatorSchemeBypassingDocumentBlocking,
+ base::Unretained(GetContentClient()->browser()),
+ request()->initiator().value(),
+ GetRequestInfo()->GetChildID(),
+ GetRequestInfo()->GetResourceType()));
+ }
+ }
next_handler_->OnResponseCompleted(status, std::move(controller));
}
@@ -543,16 +579,12 @@ void CrossSiteDocumentResourceHandler::OnResponseCompleted(
bool CrossSiteDocumentResourceHandler::ShouldBlockBasedOnHeaders(
const network::ResourceResponse& response) {
- // Give embedder a chance to skip document blocking for this response.
- const char* initiator_scheme_exception =
- GetContentClient()
- ->browser()
- ->GetInitatorSchemeBypassingDocumentBlocking();
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Delegate most decisions to CrossOriginReadBlocking::ResponseAnalyzer.
analyzer_ =
std::make_unique<network::CrossOriginReadBlocking::ResponseAnalyzer>(
- *request(), response, initiator_scheme_exception);
+ *request(), response);
if (analyzer_->ShouldAllow())
return false;
@@ -582,14 +614,22 @@ bool CrossSiteDocumentResourceHandler::ShouldBlockBasedOnHeaders(
if (!info || info->GetChildID() == -1)
return false;
- // Don't block plugin requests.
- // TODO(lukasza): Only disable CORB for plugins with universal access (see
- // PepperURLLoaderHost::has_universal_access_), because only such plugins may
- // have their own CORS-like mechanisms - e.g. crossdomain.xml in Flash). We
- // should still enforce CORB for other kinds of plugins (i.e. ones without
- // universal access).
+ // Don't block some plugin requests.
+ //
+ // Note that in practice this exception only only matters to Flash and test
+ // plugins (both can issue requests without CORS and both will be covered by
+ // CORB::ShouldAllowForPlugin below).
+ //
+ // This exception is not needed for:
+ // - PNaCl (which always issues CORS requests)
+ // - PDF (which is already covered by the exception for chrome-extension://...
+ // initiators and therefore doesn't need another exception here;
+ // additionally PDF doesn't _really_ make *cross*-origin requests - it just
+ // seems that way because of the usage of the Chrome extension).
if (info->GetResourceType() == RESOURCE_TYPE_PLUGIN_RESOURCE &&
- is_nocors_plugin_request_) {
+ is_nocors_plugin_request_ &&
+ network::CrossOriginReadBlocking::ShouldAllowForPlugin(
+ info->GetChildID())) {
return false;
}
diff --git a/chromium/content/browser/loader/cross_site_document_resource_handler.h b/chromium/content/browser/loader/cross_site_document_resource_handler.h
index 1598fb024bd..5f11dc707ce 100644
--- a/chromium/content/browser/loader/cross_site_document_resource_handler.h
+++ b/chromium/content/browser/loader/cross_site_document_resource_handler.h
@@ -164,6 +164,14 @@ class CONTENT_EXPORT CrossSiteDocumentResourceHandler
// completed, and thus it is safe to cancel or detach on the next read.
bool blocked_read_completed_ = false;
+ // Whether the request should be allowed because of
+ // ContentBrowserClient::GetInitatorSchemeBypassingDocumentBlocking
+ bool is_initiator_scheme_excluded_ = false;
+
+ // Whether |is_initiator_scheme_excluded_| actually prevented blocking from
+ // happening.
+ bool initiator_scheme_prevented_blocking_ = false;
+
base::WeakPtrFactory<CrossSiteDocumentResourceHandler> weak_this_;
DISALLOW_COPY_AND_ASSIGN(CrossSiteDocumentResourceHandler);
diff --git a/chromium/content/browser/loader/cross_site_document_resource_handler_unittest.cc b/chromium/content/browser/loader/cross_site_document_resource_handler_unittest.cc
index 99405d1b48e..e09e9a1b602 100644
--- a/chromium/content/browser/loader/cross_site_document_resource_handler_unittest.cc
+++ b/chromium/content/browser/loader/cross_site_document_resource_handler_unittest.cc
@@ -345,7 +345,13 @@ const TestScenario kScenarios[] = {
kVerdictPacketForHeadersBasedVerdict, // verdict_packet
},
{
- "Allowed: Cross-site fetch HTML from Flash without CORS",
+ // Blocked, because the unit test doesn't make a call to
+ // CrossOriginReadBlocking::AddExceptionForFlash (simulating a behavior
+ // of a compromised renderer that only pretends to be hosting Flash).
+ //
+ // The regular scenario is covered by integration tests:
+ // OutOfProcessPPAPITest.URLLoaderTrusted.
+ "Blocked: Cross-site fetch HTML from Flash without CORS",
__LINE__,
"http://www.b.com/plugin.html", // target_url
RESOURCE_TYPE_PLUGIN_RESOURCE, // resource_type
@@ -357,7 +363,7 @@ const TestScenario kScenarios[] = {
false, // simulate_range_response
AccessControlAllowOriginHeader::kOmit, // cors_response
{"<html><head>this should sniff as HTML"}, // packets
- Verdict::kAllow, // verdict
+ Verdict::kBlock, // verdict
kVerdictPacketForHeadersBasedVerdict, // verdict_packet
},
{
diff --git a/chromium/content/browser/loader/global_routing_id.h b/chromium/content/browser/loader/global_routing_id.h
deleted file mode 100644
index 3f5aadf94c0..00000000000
--- a/chromium/content/browser/loader/global_routing_id.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_LOADER_GLOBAL_ROUTING_ID_H_
-#define CONTENT_BROWSER_LOADER_GLOBAL_ROUTING_ID_H_
-
-#include <tuple>
-
-#include "ipc/ipc_message.h"
-
-namespace content {
-
-// Uniquely identifies the route from which a net::URLRequest comes.
-struct GlobalRoutingID {
- GlobalRoutingID() : child_id(-1), route_id(-1) {
- }
-
- GlobalRoutingID(int child_id, int route_id)
- : child_id(child_id),
- route_id(route_id) {
- }
-
- // The unique ID of the child process (different from OS's PID).
- int child_id;
-
- // The route ID (unique for each URLRequest source).
- int route_id;
-
- bool operator<(const GlobalRoutingID& other) const {
- return std::tie(child_id, route_id) <
- std::tie(other.child_id, other.route_id);
- }
- bool operator==(const GlobalRoutingID& other) const {
- return child_id == other.child_id &&
- route_id == other.route_id;
- }
- bool operator!=(const GlobalRoutingID& other) const {
- return !(*this == other);
- }
-};
-
-// Same as GlobalRoutingID except the route_id must be a RenderFrameHost routing
-// id.
-struct GlobalFrameRoutingId {
- GlobalFrameRoutingId() : child_id(0), frame_routing_id(MSG_ROUTING_NONE) {}
-
- GlobalFrameRoutingId(int child_id, int frame_routing_id)
- : child_id(child_id), frame_routing_id(frame_routing_id) {}
-
- // The unique ID of the child process (different from OS's PID).
- int child_id;
-
- // The route ID (unique for each URLRequest source).
- int frame_routing_id;
-
- bool operator<(const GlobalFrameRoutingId& other) const {
- return std::tie(child_id, frame_routing_id) <
- std::tie(other.child_id, other.frame_routing_id);
- }
- bool operator==(const GlobalFrameRoutingId& other) const {
- return child_id == other.child_id &&
- frame_routing_id == other.frame_routing_id;
- }
- bool operator!=(const GlobalFrameRoutingId& other) const {
- return !(*this == other);
- }
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_LOADER_GLOBAL_ROUTING_ID_H_
diff --git a/chromium/content/browser/loader/loader_browsertest.cc b/chromium/content/browser/loader/loader_browsertest.cc
index 024fadee921..927f2af62d3 100644
--- a/chromium/content/browser/loader/loader_browsertest.cc
+++ b/chromium/content/browser/loader/loader_browsertest.cc
@@ -25,6 +25,7 @@
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/resource_dispatcher_host_delegate.h"
#include "content/public/browser/resource_request_info.h"
+#include "content/public/browser/site_isolation_policy.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/browser_side_navigation_policy.h"
#include "content/public/common/previews_state.h"
@@ -627,6 +628,100 @@ IN_PROC_BROWSER_TEST_F(LoaderBrowserTest, PageTransitionClientRedirect) {
EXPECT_TRUE(delegate.page_transition() & ui::PAGE_TRANSITION_CLIENT_REDIRECT);
}
+IN_PROC_BROWSER_TEST_F(LoaderBrowserTest, SubresourceRedirectToDataURLBlocked) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+
+ EXPECT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL("/echo")));
+
+ GURL subresource_url = embedded_test_server()->GetURL(
+ "/server-redirect?data:text/plain,redirected1");
+ std::string script = R"((url => {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', url, true);
+ xhr.onload = () => domAutomationController.send("ALLOWED");
+ xhr.onerror = () => domAutomationController.send("BLOCKED");
+ xhr.send();
+ }))";
+ std::string result;
+ ASSERT_TRUE(ExecuteScriptAndExtractString(
+ shell(), script + "('" + subresource_url.spec() + "')", &result));
+
+ EXPECT_EQ("BLOCKED", result);
+}
+
+IN_PROC_BROWSER_TEST_F(LoaderBrowserTest, RedirectToDataURLBlocked) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ EXPECT_FALSE(NavigateToURL(
+ shell(), embedded_test_server()->GetURL(
+ "/server-redirect?data:text/plain,redirected1")));
+}
+
+IN_PROC_BROWSER_TEST_F(LoaderBrowserTest, RedirectToAboutURLBlocked) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ EXPECT_FALSE(NavigateToURL(
+ shell(), embedded_test_server()->GetURL(
+ "/server-redirect?" + std::string(url::kAboutBlankURL))));
+}
+
+namespace {
+
+// Creates a valid filesystem URL.
+GURL CreateFileSystemURL(Shell* window) {
+ std::string filesystem_url_string;
+ EXPECT_TRUE(
+ ExecuteScriptAndExtractString(window, R"(
+ var blob = new Blob(['<html><body>hello</body></html>'],
+ {type: 'text/html'});
+ window.webkitRequestFileSystem(TEMPORARY, blob.size, fs => {
+ fs.root.getFile('foo.html', {create: true}, file => {
+ file.createWriter(writer => {
+ writer.write(blob);
+ writer.onwriteend = () => {
+ domAutomationController.send(file.toURL());
+ }
+ });
+ });
+ });)", &filesystem_url_string));
+ GURL filesystem_url(filesystem_url_string);
+ EXPECT_TRUE(filesystem_url.is_valid());
+ EXPECT_TRUE(filesystem_url.SchemeIsFileSystem());
+ return filesystem_url;
+}
+
+} // namespace
+
+IN_PROC_BROWSER_TEST_F(LoaderBrowserTest,
+ SubresourceRedirectToFileSystemURLBlocked) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+
+ EXPECT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL("/echo")));
+
+ GURL subresource_url = embedded_test_server()->GetURL(
+ "/server-redirect?" + CreateFileSystemURL(shell()).spec());
+ std::string script = R"((url => {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', url, true);
+ xhr.onload = () => domAutomationController.send("ALLOWED");
+ xhr.onerror = () => domAutomationController.send("BLOCKED");
+ xhr.send();
+ }))";
+ std::string result;
+ ASSERT_TRUE(ExecuteScriptAndExtractString(
+ shell(), script + "('" + subresource_url.spec() + "')", &result));
+
+ EXPECT_EQ("BLOCKED", result);
+}
+
+IN_PROC_BROWSER_TEST_F(LoaderBrowserTest, RedirectToFileSystemURLBlocked) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ // Need to navigate to a URL first so the filesystem can be created.
+ EXPECT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL("/echo")));
+
+ EXPECT_FALSE(NavigateToURL(
+ shell(), embedded_test_server()->GetURL(
+ "/server-redirect?" + CreateFileSystemURL(shell()).spec())));
+}
+
namespace {
// Checks whether the given urls are requested, and that GetPreviewsState()
@@ -1172,6 +1267,11 @@ IN_PROC_BROWSER_TEST_F(RequestDataBrowserTest, CrossOriginNested) {
// bypass cookies SameSite=Strict protections by navigating a new window twice.
IN_PROC_BROWSER_TEST_F(LoaderBrowserTest,
CookieSameSiteStrictOpenNewNamedWindowTwice) {
+ // TODO(lukasza): https://crbug.com/417518: Get tests working with
+ // --site-per-process.
+ if (SiteIsolationPolicy::UseDedicatedProcessesForAllSites())
+ return;
+
ASSERT_TRUE(embedded_test_server()->Start());
// 1) Add cookies for 'a.com', one of them with the "SameSite=Strict" option.
diff --git a/chromium/content/browser/loader/loader_io_thread_notifier.cc b/chromium/content/browser/loader/loader_io_thread_notifier.cc
index 47efe2831fe..215e2f95fac 100644
--- a/chromium/content/browser/loader/loader_io_thread_notifier.cc
+++ b/chromium/content/browser/loader/loader_io_thread_notifier.cc
@@ -5,9 +5,9 @@
#include "content/browser/loader/loader_io_thread_notifier.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
-#include "content/browser/loader/global_routing_id.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/global_routing_id.h"
namespace content {
diff --git a/chromium/content/browser/loader/merkle_integrity_source_stream.cc b/chromium/content/browser/loader/merkle_integrity_source_stream.cc
index 94c532f18e2..77497667434 100644
--- a/chromium/content/browser/loader/merkle_integrity_source_stream.cc
+++ b/chromium/content/browser/loader/merkle_integrity_source_stream.cc
@@ -6,7 +6,7 @@
#include <string.h>
-#include "base/base64url.h"
+#include "base/base64.h"
#include "base/big_endian.h"
#include "base/numerics/safe_conversions.h"
#include "net/base/io_buffer.h"
@@ -19,7 +19,7 @@ namespace {
// maximum record size in TLS and the default maximum frame size in HTTP/2.
constexpr uint64_t kMaxRecordSize = 16 * 1024;
-constexpr char kMiSha256Header[] = "mi-sha256-draft2=";
+constexpr char kMiSha256Header[] = "mi-sha256-03=";
constexpr size_t kMiSha256HeaderLength = sizeof(kMiSha256Header) - 1;
// Copies as many bytes from |input| as will fit in |output| and advances both.
@@ -34,16 +34,14 @@ size_t CopyClamped(base::span<const char>* input, base::span<char>* output) {
} // namespace
MerkleIntegritySourceStream::MerkleIntegritySourceStream(
- base::StringPiece mi_header_value,
+ base::StringPiece digest_header_value,
std::unique_ptr<SourceStream> upstream)
// TODO(ksakamoto): Use appropriate SourceType.
: net::FilterSourceStream(SourceStream::TYPE_NONE, std::move(upstream)) {
- // TODO(ksakamoto): Support quoted parameter value.
std::string next_proof;
- if (!mi_header_value.starts_with(kMiSha256Header) ||
- !base::Base64UrlDecode(mi_header_value.substr(kMiSha256HeaderLength),
- base::Base64UrlDecodePolicy::DISALLOW_PADDING,
- &next_proof) ||
+ if (!digest_header_value.starts_with(kMiSha256Header) ||
+ !base::Base64Decode(digest_header_value.substr(kMiSha256HeaderLength),
+ &next_proof) ||
next_proof.size() != SHA256_DIGEST_LENGTH) {
failed_ = true;
} else {
@@ -91,7 +89,17 @@ bool MerkleIntegritySourceStream::FilterDataImpl(base::span<char>* output,
if (record_size_ == 0) {
base::span<const char> bytes;
if (!ConsumeBytes(input, 8, &bytes, &storage)) {
- return !upstream_eof_reached;
+ if (!upstream_eof_reached) {
+ return true; // Wait for more data later.
+ }
+ if (partial_input_.empty()) {
+ // As a special case, the encoding of an empty payload is itself an
+ // empty message (i.e. it omits the initial record size), and its
+ // integrity proof is SHA-256("\0").
+ final_record_done_ = true;
+ return ProcessRecord({}, final_record_done_, output);
+ }
+ return false;
}
uint64_t record_size;
base::ReadBigEndian(bytes.data(), &record_size);
@@ -124,14 +132,8 @@ bool MerkleIntegritySourceStream::FilterDataImpl(base::span<char>* output,
}
// The final record is shorter and does not contain a hash. Process all
- // remaining input the final record.
- //
- // TODO(davidben): This matches the previous implementation in that it
- // allows empty final records, but this does not match the specification
- // and means some inputs have two valid encodings. However, the
- // specification's version cannot represent the empty string. Update this
- // when https://github.com/martinthomson/http-mice/issues/3 is resolved.
- if (partial_input_.size() > record_size_) {
+ // remaining input as the final record.
+ if (partial_input_.empty() || partial_input_.size() > record_size_) {
return false;
}
record = partial_input_;
diff --git a/chromium/content/browser/loader/merkle_integrity_source_stream.h b/chromium/content/browser/loader/merkle_integrity_source_stream.h
index d2554372a48..7fe7e4f18b6 100644
--- a/chromium/content/browser/loader/merkle_integrity_source_stream.h
+++ b/chromium/content/browser/loader/merkle_integrity_source_stream.h
@@ -19,12 +19,12 @@ namespace content {
// MerkleIntegritySourceStream decodes and validates content encoded with the
// "mi-sha256" content encoding
-// (https://tools.ietf.org/html/draft-thomson-http-mice-02).
+// (https://tools.ietf.org/html/draft-thomson-http-mice-03).
// TODO(ksakamoto): This class should eventually live in src/net/filter/.
class CONTENT_EXPORT MerkleIntegritySourceStream
: public net::FilterSourceStream {
public:
- MerkleIntegritySourceStream(base::StringPiece mi_header_value,
+ MerkleIntegritySourceStream(base::StringPiece digest_header_value,
std::unique_ptr<SourceStream> upstream);
~MerkleIntegritySourceStream() override;
diff --git a/chromium/content/browser/loader/merkle_integrity_source_stream_unittest.cc b/chromium/content/browser/loader/merkle_integrity_source_stream_unittest.cc
index 61c61692ec5..8765b844ae8 100644
--- a/chromium/content/browser/loader/merkle_integrity_source_stream_unittest.cc
+++ b/chromium/content/browser/loader/merkle_integrity_source_stream_unittest.cc
@@ -3,7 +3,7 @@
// found in the LICENSE file.
#include "content/browser/loader/merkle_integrity_source_stream.h"
-#include "base/base64url.h"
+#include "base/base64.h"
#include "net/base/io_buffer.h"
#include "net/base/test_completion_callback.h"
#include "net/filter/mock_source_stream.h"
@@ -17,13 +17,13 @@ const int kBigBufferSize = 4096;
const int kSmallBufferSize = 1;
const char kMIEmptyBody[] =
- "mi-sha256-draft2=bjQLnP-zepicpUTmu3gKLHiQHT-zNzh2hRGjBhevoB0";
+ "mi-sha256-03=bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=";
const char kMISingleRecord[] =
- "mi-sha256-draft2=dcRDgR2GM35DluAV13PzgnG6-pvQwPywfFvAu1UeFrs";
+ "mi-sha256-03=dcRDgR2GM35DluAV13PzgnG6+pvQwPywfFvAu1UeFrs=";
const char kMIMultipleRecords[] =
- "mi-sha256-draft2=IVa9shfs0nyKEhHqtB3WVNANJ2Njm5KjQLjRtnbkYJ4";
+ "mi-sha256-03=IVa9shfs0nyKEhHqtB3WVNANJ2Njm5KjQLjRtnbkYJ4=";
const char kMIWholeNumberOfRecords[] =
- "mi-sha256-draft2=L2vdwBplKvIr0ZPkcuskWZfEVDgVdHa6aD363UpKuZs";
+ "mi-sha256-03=L2vdwBplKvIr0ZPkcuskWZfEVDgVdHa6aD363UpKuZs=";
enum class ReadResultType {
// Each call to AddReadResult is a separate read from the lower layer
@@ -112,8 +112,7 @@ class MerkleIntegritySourceStreamTest
std::string Base64Decode(const char* hash) {
std::string out;
- EXPECT_TRUE(base::Base64UrlDecode(
- hash, base::Base64UrlDecodePolicy::DISALLOW_PADDING, &out));
+ EXPECT_TRUE(base::Base64Decode(hash, &out));
EXPECT_EQ(32u, out.size());
return out;
}
@@ -160,6 +159,14 @@ TEST_P(MerkleIntegritySourceStreamTest, EmptyStream) {
source()->AddReadResult(nullptr, 0, net::OK, GetParam().mode);
std::string actual_output;
int result = ReadStream(&actual_output);
+ EXPECT_EQ(net::OK, result);
+}
+
+TEST_P(MerkleIntegritySourceStreamTest, EmptyStreamWrongHash) {
+ Init(kMISingleRecord);
+ source()->AddReadResult(nullptr, 0, net::OK, GetParam().mode);
+ std::string actual_output;
+ int result = ReadStream(&actual_output);
EXPECT_EQ(net::ERR_CONTENT_DECODING_FAILED, result);
}
@@ -180,7 +187,7 @@ TEST_P(MerkleIntegritySourceStreamTest, MalformedMIHeader) {
}
TEST_P(MerkleIntegritySourceStreamTest, WrongMIAttributeName) {
- Init("mi-sha256-draft1=bjQLnP-zepicpUTmu3gKLHiQHT-zNzh2hRGjBhevoB0");
+ Init("mi-sha256-01=bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=");
source()->AddReadResult(nullptr, 0, net::OK, GetParam().mode);
std::string actual_output;
int result = ReadStream(&actual_output);
@@ -188,7 +195,7 @@ TEST_P(MerkleIntegritySourceStreamTest, WrongMIAttributeName) {
}
TEST_P(MerkleIntegritySourceStreamTest, HashTooShort) {
- Init("mi-sha256-draft2=bjQLnP-zepicpUTmu3gKLHiQHT-zNzh2hRGjBhevoA");
+ Init("mi-sha256-03=bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoA==");
source()->AddReadResult(nullptr, 0, net::OK, GetParam().mode);
std::string actual_output;
int result = ReadStream(&actual_output);
@@ -196,7 +203,7 @@ TEST_P(MerkleIntegritySourceStreamTest, HashTooShort) {
}
TEST_P(MerkleIntegritySourceStreamTest, HashTooLong) {
- Init("mi-sha256-draft2=bjQLnP-zepicpUTmu3gKLHiQHT-zNzh2hRGjBhevoB0A");
+ Init("mi-sha256-03=bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0A");
source()->AddReadResult(nullptr, 0, net::OK, GetParam().mode);
std::string actual_output;
int result = ReadStream(&actual_output);
@@ -211,7 +218,7 @@ TEST_P(MerkleIntegritySourceStreamTest, RecordSizeOnly) {
source()->AddReadResult(nullptr, 0, net::OK, GetParam().mode);
std::string actual_output;
int result = ReadStream(&actual_output);
- EXPECT_EQ(net::OK, result);
+ EXPECT_EQ(net::ERR_CONTENT_DECODING_FAILED, result);
}
TEST_P(MerkleIntegritySourceStreamTest, TruncatedRecordSize) {
@@ -329,11 +336,11 @@ TEST_P(MerkleIntegritySourceStreamTest, MultipleRecords) {
sizeof(kRecordSize), net::OK, GetParam().mode);
source()->AddReadResult(kMessage.data(), 16, net::OK, GetParam().mode);
std::string hash1 =
- Base64Decode("OElbplJlPK-Rv6JNK6p5_515IaoPoZo-2elWL7OQ60A");
+ Base64Decode("OElbplJlPK+Rv6JNK6p5/515IaoPoZo+2elWL7OQ60A=");
source()->AddReadResult(hash1.data(), 32, net::OK, GetParam().mode);
source()->AddReadResult(kMessage.data() + 16, 16, net::OK, GetParam().mode);
std::string hash2 =
- Base64Decode("iPMpmgExHPrbEX3_RvwP4d16fWlK4l--p75PUu_KyN0");
+ Base64Decode("iPMpmgExHPrbEX3/RvwP4d16fWlK4l++p75PUu/KyN0=");
source()->AddReadResult(hash2.data(), 32, net::OK, GetParam().mode);
source()->AddReadResult(kMessage.data() + 32, kMessage.size() - 32, net::OK,
GetParam().mode);
@@ -353,9 +360,9 @@ TEST_P(MerkleIntegritySourceStreamTest, MultipleRecordsAllAtOnce) {
std::string body(reinterpret_cast<const char*>(kRecordSize),
sizeof(kRecordSize));
body += kMessage.substr(0, 16);
- body += Base64Decode("OElbplJlPK-Rv6JNK6p5_515IaoPoZo-2elWL7OQ60A");
+ body += Base64Decode("OElbplJlPK+Rv6JNK6p5/515IaoPoZo+2elWL7OQ60A=");
body += kMessage.substr(16, 16);
- body += Base64Decode("iPMpmgExHPrbEX3_RvwP4d16fWlK4l--p75PUu_KyN0");
+ body += Base64Decode("iPMpmgExHPrbEX3/RvwP4d16fWlK4l++p75PUu/KyN0=");
body += kMessage.substr(32);
source()->AddReadResult(body.data(), body.size(), net::OK, GetParam().mode);
@@ -375,11 +382,11 @@ TEST_P(MerkleIntegritySourceStreamTest, MultipleRecordsWrongLastRecordHash) {
sizeof(kRecordSize), net::OK, GetParam().mode);
source()->AddReadResult(kMessage.data(), 16, net::OK, GetParam().mode);
std::string hash1 =
- Base64Decode("OElbplJlPK-Rv6JNK6p5_515IaoPoZo-2elWL7OQ60A");
+ Base64Decode("OElbplJlPK+Rv6JNK6p5/515IaoPoZo+2elWL7OQ60A=");
source()->AddReadResult(hash1.data(), 32, net::OK, GetParam().mode);
source()->AddReadResult(kMessage.data() + 16, 16, net::OK, GetParam().mode);
std::string hash2 =
- Base64Decode("iPMpmgExHPrbEX3_RvwP4d16fWlK4l--p75PUu_KyN0");
+ Base64Decode("iPMpmgExHPrbEX3/RvwP4d16fWlK4l++p75PUu/KyN0=");
source()->AddReadResult(hash2.data(), 32, net::OK, GetParam().mode);
source()->AddReadResult(kMessage.data() + 32, kMessage.size() - 32, net::OK,
GetParam().mode);
@@ -400,7 +407,7 @@ TEST_P(MerkleIntegritySourceStreamTest, MultipleRecordsWrongFirstRecordHash) {
sizeof(kRecordSize), net::OK, GetParam().mode);
source()->AddReadResult(kMessage.data(), 16, net::OK, GetParam().mode);
std::string hash1 =
- Base64Decode("OElbplJlPK-Rv6JNK6p5_515IaoPoZo-2elWL7OQ60A");
+ Base64Decode("OElbplJlPK+Rv6JNK6p5/515IaoPoZo+2elWL7OQ60A=");
source()->AddReadResult(hash1.data(), 32, net::OK, GetParam().mode);
std::string actual_output;
@@ -418,11 +425,11 @@ TEST_P(MerkleIntegritySourceStreamTest, TrailingNetError) {
sizeof(kRecordSize), net::OK, GetParam().mode);
source()->AddReadResult(kMessage.data(), 16, net::OK, GetParam().mode);
std::string hash1 =
- Base64Decode("OElbplJlPK-Rv6JNK6p5_515IaoPoZo-2elWL7OQ60A");
+ Base64Decode("OElbplJlPK+Rv6JNK6p5/515IaoPoZo+2elWL7OQ60A=");
source()->AddReadResult(hash1.data(), 32, net::OK, GetParam().mode);
source()->AddReadResult(kMessage.data() + 16, 16, net::OK, GetParam().mode);
std::string hash2 =
- Base64Decode("iPMpmgExHPrbEX3_RvwP4d16fWlK4l--p75PUu_KyN0");
+ Base64Decode("iPMpmgExHPrbEX3/RvwP4d16fWlK4l++p75PUu/KyN0=");
source()->AddReadResult(hash2.data(), 32, net::OK, GetParam().mode);
source()->AddReadResult(kMessage.data() + 32, kMessage.size() - 32, net::OK,
GetParam().mode);
@@ -447,11 +454,11 @@ TEST_P(MerkleIntegritySourceStreamTest, Truncated) {
sizeof(kRecordSize), net::OK, GetParam().mode);
source()->AddReadResult(kMessage.data(), 16, net::OK, GetParam().mode);
std::string hash1 =
- Base64Decode("OElbplJlPK-Rv6JNK6p5_515IaoPoZo-2elWL7OQ60A");
+ Base64Decode("OElbplJlPK+Rv6JNK6p5/515IaoPoZo+2elWL7OQ60A=");
source()->AddReadResult(hash1.data(), 32, net::OK, GetParam().mode);
source()->AddReadResult(kMessage.data() + 16, 16, net::OK, GetParam().mode);
std::string hash2 =
- Base64Decode("iPMpmgExHPrbEX3_RvwP4d16fWlK4l--p75PUu_KyN0");
+ Base64Decode("iPMpmgExHPrbEX3/RvwP4d16fWlK4l++p75PUu/KyN0=");
source()->AddReadResult(hash2.data(), 32, net::OK, GetParam().mode);
// |hash2| is the hash of "atermelon", but this stream ends early. Decoding
// thus should fail.
@@ -463,14 +470,9 @@ TEST_P(MerkleIntegritySourceStreamTest, Truncated) {
EXPECT_EQ(kMessage, actual_output);
}
-// Test that the final record is allowed to be empty.
-//
-// TODO(davidben): This does not match the specification and means some inputs
-// have two valid encodings. However, the specification's version cannot
-// represent the empty string. Update the code and possibly this test depending
-// on how https://github.com/martinthomson/http-mice/issues/3 is resolved.
+// Test that the final record is not allowed to be empty.
TEST_P(MerkleIntegritySourceStreamTest, EmptyFinalRecord) {
- Init("mi-sha256-draft2=JJnIuaOEc2247K9V88VQAQy1GJuQ6ylaVM7mG69QkE4");
+ Init("mi-sha256-03=JJnIuaOEc2247K9V88VQAQy1GJuQ6ylaVM7mG69QkE4=");
const uint8_t kRecordSize[] = {0, 0, 0, 0, 0, 0, 0, 16};
const std::string kMessage(
"When I grow up, I want to be a watermelon!! \xf0\x9f\x8d\x89");
@@ -479,21 +481,21 @@ TEST_P(MerkleIntegritySourceStreamTest, EmptyFinalRecord) {
sizeof(kRecordSize), net::OK, GetParam().mode);
source()->AddReadResult(kMessage.data(), 16, net::OK, GetParam().mode);
std::string hash1 =
- Base64Decode("hhJEKpkbuZoWUjzBPAZxMUN2DXdJ6epkS0McZh77IXo");
+ Base64Decode("hhJEKpkbuZoWUjzBPAZxMUN2DXdJ6epkS0McZh77IXo=");
source()->AddReadResult(hash1.data(), 32, net::OK, GetParam().mode);
source()->AddReadResult(kMessage.data() + 16, 16, net::OK, GetParam().mode);
std::string hash2 =
- Base64Decode("RKTTVSMiH3bkxUQKreVATPL1KUd5eqRdmDgRQcZq_80");
+ Base64Decode("RKTTVSMiH3bkxUQKreVATPL1KUd5eqRdmDgRQcZq/80=");
source()->AddReadResult(hash2.data(), 32, net::OK, GetParam().mode);
source()->AddReadResult(kMessage.data() + 32, 16, net::OK, GetParam().mode);
std::string hash3 =
- Base64Decode("bjQLnP-zepicpUTmu3gKLHiQHT-zNzh2hRGjBhevoB0");
+ Base64Decode("bjQLnP+zepicpUTmu3gKLHiQHT+zNzh2hRGjBhevoB0=");
source()->AddReadResult(hash3.data(), 32, net::OK, GetParam().mode);
source()->AddReadResult(nullptr, 0, net::OK, GetParam().mode);
std::string actual_output;
int rv = ReadStream(&actual_output);
- EXPECT_EQ(static_cast<int>(kMessage.size()), rv);
+ EXPECT_EQ(net::ERR_CONTENT_DECODING_FAILED, rv);
EXPECT_EQ(kMessage, actual_output);
}
@@ -507,11 +509,11 @@ TEST_P(MerkleIntegritySourceStreamTest, WholeNumberOfRecords) {
sizeof(kRecordSize), net::OK, GetParam().mode);
source()->AddReadResult(kMessage.data(), 16, net::OK, GetParam().mode);
std::string hash1 =
- Base64Decode("2s-MNG6NrTt556s__HYnQTjG3WOktEcXZ61O8mzG9f4");
+ Base64Decode("2s+MNG6NrTt556s//HYnQTjG3WOktEcXZ61O8mzG9f4=");
source()->AddReadResult(hash1.data(), 32, net::OK, GetParam().mode);
source()->AddReadResult(kMessage.data() + 16, 16, net::OK, GetParam().mode);
std::string hash2 =
- Base64Decode("qa_cQSMjFyZsm0cnYG4H6LqwOM_hzMSclK6I8iVoZYQ");
+ Base64Decode("qa/cQSMjFyZsm0cnYG4H6LqwOM/hzMSclK6I8iVoZYQ=");
source()->AddReadResult(hash2.data(), 32, net::OK, GetParam().mode);
source()->AddReadResult(kMessage.data() + 32, 16, net::OK, GetParam().mode);
@@ -530,9 +532,9 @@ TEST_P(MerkleIntegritySourceStreamTest, WholeNumberOfRecordsAllAtOnce) {
std::string body(reinterpret_cast<const char*>(kRecordSize),
sizeof(kRecordSize));
body += kMessage.substr(0, 16);
- body += Base64Decode("2s-MNG6NrTt556s__HYnQTjG3WOktEcXZ61O8mzG9f4");
+ body += Base64Decode("2s+MNG6NrTt556s//HYnQTjG3WOktEcXZ61O8mzG9f4=");
body += kMessage.substr(16, 16);
- body += Base64Decode("qa_cQSMjFyZsm0cnYG4H6LqwOM_hzMSclK6I8iVoZYQ");
+ body += Base64Decode("qa/cQSMjFyZsm0cnYG4H6LqwOM/hzMSclK6I8iVoZYQ=");
body += kMessage.substr(32, 16);
source()->AddReadResult(body.data(), body.size(), net::OK, GetParam().mode);
diff --git a/chromium/content/browser/loader/mime_sniffing_resource_handler.cc b/chromium/content/browser/loader/mime_sniffing_resource_handler.cc
index 89e2c5351c4..74707ef3128 100644
--- a/chromium/content/browser/loader/mime_sniffing_resource_handler.cc
+++ b/chromium/content/browser/loader/mime_sniffing_resource_handler.cc
@@ -250,6 +250,7 @@ void MimeSniffingResourceHandler::OnReadCompleted(
// the mime type. However, even if it returns false, it returns a new type
// that is probably better than the current one.
response_->head.mime_type.assign(new_type);
+ response_->head.did_mime_sniff = true;
if (!made_final_decision && (bytes_read > 0)) {
controller->Resume();
diff --git a/chromium/content/browser/loader/mime_sniffing_resource_handler_unittest.cc b/chromium/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
index 6ac35383ea9..6d23266622c 100644
--- a/chromium/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
+++ b/chromium/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
@@ -473,6 +473,8 @@ void MimeSniffingResourceHandlerTest::TestHandlerSniffing(
EXPECT_EQ(1, test_handler->on_will_read_called());
EXPECT_EQ(1, test_handler->on_read_completed_called());
+ EXPECT_TRUE(test_handler->resource_response()->head.did_mime_sniff);
+
// Process all messages to ensure proper test teardown.
content::RunAllPendingInMessageLoop();
}
@@ -601,6 +603,8 @@ void MimeSniffingResourceHandlerTest::TestHandlerNoSniffing(
EXPECT_EQ(1, test_handler->on_will_read_called());
EXPECT_EQ(1, test_handler->on_read_completed_called());
+ EXPECT_FALSE(test_handler->resource_response()->head.did_mime_sniff);
+
if (!read_completed) {
EXPECT_EQ(MockResourceLoader::Status::CANCELED, mock_loader.status());
EXPECT_EQ(net::ERR_ABORTED, mock_loader.error_code());
diff --git a/chromium/content/browser/loader/mojo_async_resource_handler.cc b/chromium/content/browser/loader/mojo_async_resource_handler.cc
index 4910201a2d1..de7d58c0a73 100644
--- a/chromium/content/browser/loader/mojo_async_resource_handler.cc
+++ b/chromium/content/browser/loader/mojo_async_resource_handler.cc
@@ -13,6 +13,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/time/time.h"
+#include "base/timer/timer.h"
#include "content/browser/loader/resource_controller.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/loader/resource_request_info_impl.h"
@@ -115,6 +116,7 @@ MojoAsyncResourceHandler::MojoAsyncResourceHandler(
mojo::SimpleWatcher::ArmingPolicy::MANUAL,
base::SequencedTaskRunnerHandle::Get()),
url_loader_client_(std::move(url_loader_client)),
+ report_transfer_size_async_timer_(std::make_unique<base::OneShotTimer>()),
weak_factory_(this) {
DCHECK(IsResourceTypeFrame(resource_type) ||
resource_type == RESOURCE_TYPE_SERVICE_WORKER ||
@@ -304,6 +306,37 @@ void MojoAsyncResourceHandler::OnWillRead(
controller->Resume();
}
+void MojoAsyncResourceHandler::set_report_transfer_size_async_timer_for_testing(
+ std::unique_ptr<base::OneShotTimer> timer) {
+ report_transfer_size_async_timer_ = std::move(timer);
+}
+
+void MojoAsyncResourceHandler::SendTransferSizeUpdate() {
+ int64_t transfer_size_diff = CalculateRecentlyReceivedBytes();
+ if (transfer_size_diff > 0) {
+ url_loader_client_->OnTransferSizeUpdated(transfer_size_diff);
+ }
+}
+
+void MojoAsyncResourceHandler::EnsureTransferSizeUpdate() {
+ auto current_time = base::TimeTicks::Now();
+ if (earliest_time_next_transfer_size_report_.is_null() ||
+ earliest_time_next_transfer_size_report_ <= current_time) {
+ report_transfer_size_async_timer_->Stop();
+ SendTransferSizeUpdate();
+ earliest_time_next_transfer_size_report_ =
+ current_time + kTransferSizeReportInterval;
+ } else {
+ // Ensure that a single transfer update will eventually occur even if reads
+ // stop. Unretained is safe here because the callback will only live as long
+ // as |report_transfer_size_async_timer_|.
+ report_transfer_size_async_timer_->Start(
+ FROM_HERE, kTransferSizeReportInterval,
+ base::BindOnce(&MojoAsyncResourceHandler::SendTransferSizeUpdate,
+ base::Unretained(this)));
+ }
+}
+
void MojoAsyncResourceHandler::OnReadCompleted(
int bytes_read,
std::unique_ptr<ResourceController> controller) {
@@ -318,15 +351,8 @@ void MojoAsyncResourceHandler::OnReadCompleted(
return;
}
- if (ShouldReportTransferSize(GetRequestInfo()) &&
- (time_transfer_size_next_report_.is_null() ||
- time_transfer_size_next_report_ <= base::TimeTicks::Now())) {
- auto transfer_size_diff = CalculateRecentlyReceivedBytes();
- if (transfer_size_diff > 0) {
- url_loader_client_->OnTransferSizeUpdated(transfer_size_diff);
- time_transfer_size_next_report_ =
- base::TimeTicks::Now() + kTransferSizeReportInterval;
- }
+ if (ShouldReportTransferSize(GetRequestInfo())) {
+ EnsureTransferSizeUpdate();
}
if (response_body_consumer_handle_.is_valid()) {
@@ -507,9 +533,9 @@ void MojoAsyncResourceHandler::OnResponseCompleted(
}
if (ShouldReportTransferSize(GetRequestInfo())) {
- auto transfer_size_diff = CalculateRecentlyReceivedBytes();
- if (transfer_size_diff > 0)
- url_loader_client_->OnTransferSizeUpdated(transfer_size_diff);
+ // All received bytes will be reported.
+ report_transfer_size_async_timer_->Stop();
+ SendTransferSizeUpdate();
}
url_loader_client_->OnComplete(loader_status);
diff --git a/chromium/content/browser/loader/mojo_async_resource_handler.h b/chromium/content/browser/loader/mojo_async_resource_handler.h
index ad87065771e..73ae262665c 100644
--- a/chromium/content/browser/loader/mojo_async_resource_handler.h
+++ b/chromium/content/browser/loader/mojo_async_resource_handler.h
@@ -28,6 +28,7 @@ class GURL;
namespace base {
class Location;
+class OneShotTimer;
}
namespace net {
@@ -93,6 +94,8 @@ class CONTENT_EXPORT MojoAsyncResourceHandler
void PauseReadingBodyFromNet() override;
void ResumeReadingBodyFromNet() override;
+ void set_report_transfer_size_async_timer_for_testing(
+ std::unique_ptr<base::OneShotTimer> timer);
void OnWritableForTesting();
static void SetAllocationSizeForTesting(size_t size);
static constexpr size_t kDefaultAllocationSize = 512 * 1024;
@@ -123,6 +126,8 @@ class CONTENT_EXPORT MojoAsyncResourceHandler
// |reported_total_received_bytes_|, returns it, and updates
// |reported_total_received_bytes_|.
int64_t CalculateRecentlyReceivedBytes();
+ void SendTransferSizeUpdate();
+ void EnsureTransferSizeUpdate();
// These functions can be overriden only for tests.
virtual void ReportBadMessage(const std::string& error);
@@ -150,9 +155,6 @@ class CONTENT_EXPORT MojoAsyncResourceHandler
bool did_defer_on_redirect_ = false;
bool did_defer_on_response_started_ = false;
- // The time transfer size should be reported next.
- base::TimeTicks time_transfer_size_next_report_;
- int64_t reported_total_received_bytes_ = 0;
int64_t total_written_bytes_ = 0;
// Pointer to parent's information about the read buffer. Only non-null while
@@ -171,6 +173,14 @@ class CONTENT_EXPORT MojoAsyncResourceHandler
std::unique_ptr<network::UploadProgressTracker> upload_progress_tracker_;
+ // Timer to report transfer size after a read is completed but not reported.
+ // Gurantees that all received bytes will be reported eventually, regardless
+ // of read rate or completion, as long as the client is alive.
+ std::unique_ptr<base::OneShotTimer> report_transfer_size_async_timer_;
+ // The time transfer size should be reported next.
+ base::TimeTicks earliest_time_next_transfer_size_report_;
+ int64_t reported_total_received_bytes_ = 0;
+
base::WeakPtrFactory<MojoAsyncResourceHandler> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(MojoAsyncResourceHandler);
};
diff --git a/chromium/content/browser/loader/mojo_async_resource_handler_unittest.cc b/chromium/content/browser/loader/mojo_async_resource_handler_unittest.cc
index a4170df9f58..68e6a784850 100644
--- a/chromium/content/browser/loader/mojo_async_resource_handler_unittest.cc
+++ b/chromium/content/browser/loader/mojo_async_resource_handler_unittest.cc
@@ -19,6 +19,7 @@
#include "base/run_loop.h"
#include "base/test/gtest_util.h"
#include "base/test/test_simple_task_runner.h"
+#include "base/timer/mock_timer.h"
#include "content/browser/loader/mock_resource_loader.h"
#include "content/browser/loader/resource_controller.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
@@ -1523,6 +1524,62 @@ TEST_F(MojoAsyncResourceHandlerTest,
EXPECT_LT(0, request_->GetTotalReceivedBytes());
}
+TEST_F(MojoAsyncResourceHandlerTest,
+ TransferSizeUpdateCalledWithoutResponseComplete) {
+ const char kResponseHeaders[] = "response headers";
+ const char kResponseData[] = "response data";
+ // Create a mock timer to control when the final transfersizeupdate is sent.
+ auto timer = std::make_unique<base::MockOneShotTimer>();
+ auto* raw_timer = timer.get();
+ handler_->set_report_transfer_size_async_timer_for_testing(std::move(timer));
+
+ // Create a test job so the underlying URLRequest will receive bytes.
+ net::URLRequestJobFactoryImpl test_job_factory_;
+ auto test_job = std::make_unique<net::URLRequestTestJob>(
+ request_.get(), request_context_->network_delegate(), kResponseHeaders,
+ kResponseData, true);
+ auto test_job_interceptor = std::make_unique<net::TestJobInterceptor>();
+ net::TestJobInterceptor* raw_test_job_interceptor =
+ test_job_interceptor.get();
+ EXPECT_TRUE(test_job_factory_.SetProtocolHandler(
+ url::kHttpScheme, std::move(test_job_interceptor)));
+ request_context_->set_job_factory(&test_job_factory_);
+ raw_test_job_interceptor->set_main_intercept_job(std::move(test_job));
+ request_->Start();
+
+ // Prepare for loader read complete.
+ ASSERT_TRUE(CallOnWillStartAndOnResponseStarted());
+ EXPECT_EQ(MockResourceLoader::Status::IDLE,
+ mock_loader_->OnWillStart(request_->url()));
+ EXPECT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->OnWillRead());
+ // Only headers are read by the time the response is started.
+ mock_loader_->OnReadCompleted(kResponseHeaders);
+
+ // Make the loader process another read of the rest of the URLTestJob data.
+ EXPECT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->OnWillRead());
+ mock_loader_->OnReadCompleted(kResponseData);
+
+ // Process the entire URL request.
+ url_request_delegate_.RunUntilComplete();
+
+ // All data received by the request.
+ EXPECT_EQ(
+ request_->GetTotalReceivedBytes(),
+ static_cast<int64_t>(strlen(kResponseHeaders) + strlen(kResponseData)));
+
+ // Wait for a transfer size update to be received.
+ url_loader_client_.RunUntilTransferSizeUpdated();
+ // Only the first read caused a transfer size update.
+ EXPECT_EQ(static_cast<int64_t>(strlen(kResponseHeaders)),
+ url_loader_client_.body_transfer_size());
+ // Firing the timer will cause the rest of the bytes to be reported.
+ // Without timer fire no transfer size updates would be received.
+ raw_timer->Fire();
+ url_loader_client_.RunUntilTransferSizeUpdated();
+ EXPECT_EQ(request_->GetTotalReceivedBytes(),
+ url_loader_client_.body_transfer_size());
+}
+
INSTANTIATE_TEST_CASE_P(MojoAsyncResourceHandlerWithAllocationSizeTest,
MojoAsyncResourceHandlerWithAllocationSizeTest,
::testing::Values(8, 32 * 2014));
diff --git a/chromium/content/browser/loader/navigation_loader_interceptor.h b/chromium/content/browser/loader/navigation_loader_interceptor.h
index 2f4ad19e0ba..ca2f3ad6d5f 100644
--- a/chromium/content/browser/loader/navigation_loader_interceptor.h
+++ b/chromium/content/browser/loader/navigation_loader_interceptor.h
@@ -35,23 +35,49 @@ class CONTENT_EXPORT NavigationLoaderInterceptor {
using LoaderCallback =
base::OnceCallback<void(SingleRequestURLLoaderFactory::RequestHandler)>;
+ using FallbackCallback =
+ base::OnceCallback<void(bool /* reset_subresource_loader_params */)>;
// Asks this handler to handle this resource load request.
// The handler must invoke |callback| eventually with either a non-null
// RequestHandler indicating its willingness to handle the request, or a null
// RequestHandler to indicate that someone else should handle the request.
+ //
+ // The |tentative_resource_request| passed to this function and the resource
+ // request later passed to the RequestHandler given to |callback| may not be
+ // exactly the same, because URLLoaderThrottles may rewrite the request
+ // between the two calls. However the URL must remain constant between the
+ // two, as any modifications on the URL done by URLLoaderThrottles must result
+ // in an (internal) redirect, which must restart the request with a new
+ // MaybeCreateLoader().
+ //
+ // This handler might initially elect to handle the request, but later decide
+ // to fall back to the default behavior. In that case, it can invoke
+ // |fallback_callback| to do so. An example of this is when a service worker
+ // decides to handle the request because it is in-scope, but the service
+ // worker JavaScript execution does not result in a response provided, so
+ // fallback to network is required.
+ //
+ // If |fallback_callback| is called, it must be called prior to the
+ // RequestHandler making any URLLoaderClient calls. The
+ // |reset_subresource_loader_params| parameter to |fallback_callback|
+ // indicates whether to discard the subresource loader params previously
+ // returned by MaybeCreateSubresourceLoaderParams().
virtual void MaybeCreateLoader(
- const network::ResourceRequest& resource_request,
+ const network::ResourceRequest& tentative_resource_request,
ResourceContext* resource_context,
- LoaderCallback callback) = 0;
+ LoaderCallback callback,
+ FallbackCallback fallback_callback) = 0;
// Returns a SubresourceLoaderParams if any to be used for subsequent URL
// requests going forward. Subclasses who want to set-up custom loader for
// subresource requests may want to override this.
+ //
// Note that the handler can return a null callback to MaybeCreateLoader(),
// and at the same time can return non-null SubresourceLoaderParams here if it
// does NOT want to handle the specific request given to MaybeCreateLoader()
- // but wants to handle the subsequent resource requests.
+ // but wants to handle the subsequent resource requests or ensure other
+ // interceptors are skipped.
virtual base::Optional<SubresourceLoaderParams>
MaybeCreateSubresourceLoaderParams();
diff --git a/chromium/content/browser/loader/navigation_url_loader_delegate.h b/chromium/content/browser/loader/navigation_url_loader_delegate.h
index c7d238283e1..c1f56144194 100644
--- a/chromium/content/browser/loader/navigation_url_loader_delegate.h
+++ b/chromium/content/browser/loader/navigation_url_loader_delegate.h
@@ -11,6 +11,7 @@
#include "base/memory/ref_counted.h"
#include "base/optional.h"
#include "content/common/content_export.h"
+#include "content/public/common/previews_state.h"
#include "services/network/public/mojom/url_loader.mojom.h"
namespace net {
@@ -45,6 +46,7 @@ class CONTENT_EXPORT NavigationURLLoaderDelegate {
// necessary info to create a custom subresource loader in the renderer
// process if the navigated context is controlled by a request interceptor
// like AppCache or ServiceWorker.
+ // |previews_state| is updated in common params.
virtual void OnResponseStarted(
const scoped_refptr<network::ResourceResponse>& response,
network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
@@ -52,6 +54,7 @@ class CONTENT_EXPORT NavigationURLLoaderDelegate {
const GlobalRequestID& request_id,
bool is_download,
bool is_stream,
+ PreviewsState previews_state,
base::Optional<SubresourceLoaderParams> subresource_loader_params) = 0;
// Called if the request fails before receving a response. Specific
diff --git a/chromium/content/browser/loader/navigation_url_loader_impl.cc b/chromium/content/browser/loader/navigation_url_loader_impl.cc
index 0fb15c7c1be..f14b46b86a8 100644
--- a/chromium/content/browser/loader/navigation_url_loader_impl.cc
+++ b/chromium/content/browser/loader/navigation_url_loader_impl.cc
@@ -10,11 +10,13 @@
#include "base/bind_helpers.h"
#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
+#include "base/optional.h"
#include "base/stl_util.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/trace_event/trace_event.h"
#include "components/download/public/common/download_stats.h"
#include "content/browser/appcache/appcache_navigation_handle.h"
+#include "content/browser/appcache/appcache_navigation_handle_core.h"
#include "content/browser/appcache/appcache_request_handler.h"
#include "content/browser/blob_storage/chrome_blob_storage_context.h"
#include "content/browser/devtools/render_frame_devtools_agent_host.h"
@@ -39,6 +41,7 @@
#include "content/browser/web_package/signed_exchange_utils.h"
#include "content/browser/webui/url_data_manager_backend.h"
#include "content/browser/webui/web_ui_url_loader_factory_internal.h"
+#include "content/common/mime_sniffing_throttle.h"
#include "content/common/navigation_subresource_loader_params.h"
#include "content/common/net/record_load_histograms.h"
#include "content/common/throttling_url_loader.h"
@@ -59,8 +62,11 @@
#include "content/public/common/url_utils.h"
#include "content/public/common/webplugininfo.h"
#include "net/base/load_flags.h"
+#include "net/cert/sct_status_flags.h"
+#include "net/cert/signed_certificate_timestamp_and_status.h"
#include "net/http/http_content_disposition.h"
#include "net/http/http_request_headers.h"
+#include "net/ssl/ssl_info.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/redirect_util.h"
#include "net/url_request/url_request.h"
@@ -90,11 +96,13 @@ class NavigationLoaderInterceptorBrowserContainer
~NavigationLoaderInterceptorBrowserContainer() override = default;
- void MaybeCreateLoader(const network::ResourceRequest& resource_request,
- ResourceContext* resource_context,
- LoaderCallback callback) override {
- browser_interceptor_->MaybeCreateLoader(resource_request, resource_context,
- std::move(callback));
+ void MaybeCreateLoader(
+ const network::ResourceRequest& tentative_resource_request,
+ ResourceContext* resource_context,
+ LoaderCallback callback,
+ FallbackCallback fallback_callback) override {
+ browser_interceptor_->MaybeCreateLoader(
+ tentative_resource_request, resource_context, std::move(callback));
}
private:
@@ -290,13 +298,62 @@ std::unique_ptr<NavigationRequestInfo> CreateNavigationRequestInfoForRedirect(
}
// Called for requests that we don't have a URLLoaderFactory for.
-void UnknownSchemeCallback(bool handled_externally,
- network::mojom::URLLoaderRequest request,
- network::mojom::URLLoaderClientPtr client) {
+void UnknownSchemeCallback(
+ bool handled_externally,
+ const network::ResourceRequest& /* resource_request */,
+ network::mojom::URLLoaderRequest request,
+ network::mojom::URLLoaderClientPtr client) {
client->OnComplete(network::URLLoaderCompletionStatus(
handled_externally ? net::ERR_ABORTED : net::ERR_UNKNOWN_URL_SCHEME));
}
+// Returns whether this URL can be handled by the default network service
+// URLLoader.
+bool IsURLHandledByDefaultLoader(const GURL& url) {
+ // Data URLs are only handled by the network service if
+ // |enable_data_url_support| is set in NetworkContextParams. This is set to
+ // true for the context used by NavigationURLLoaderImpl, so in addition to
+ // checking whether the URL is handled by the network service, we also need to
+ // check for the data scheme.
+ return IsURLHandledByNetworkService(url) || url.SchemeIs(url::kDataScheme);
+}
+
+// Determines whether it is safe to redirect from |from_url| to |to_url|.
+bool IsRedirectSafe(const GURL& from_url,
+ const GURL& to_url,
+ ResourceContext* resource_context) {
+ return IsSafeRedirectTarget(from_url, to_url) &&
+ GetContentClient()->browser()->IsSafeRedirectTarget(to_url,
+ resource_context);
+}
+
+// URLLoaderFactory for handling about: URLs. This treats everything as
+// about:blank since no other about: features should be available to web
+// content.
+class AboutURLLoaderFactory : public network::mojom::URLLoaderFactory {
+ private:
+ // network::mojom::URLLoaderFactory:
+ void CreateLoaderAndStart(network::mojom::URLLoaderRequest loader,
+ int32_t routing_id,
+ int32_t request_id,
+ uint32_t options,
+ const network::ResourceRequest& request,
+ network::mojom::URLLoaderClientPtr client,
+ const net::MutableNetworkTrafficAnnotationTag&
+ traffic_annotation) override {
+ network::ResourceResponseHead response;
+ response.mime_type = "text/html";
+ client->OnReceiveResponse(response);
+ client->OnComplete(network::URLLoaderCompletionStatus(net::OK));
+ }
+
+ void Clone(network::mojom::URLLoaderFactoryRequest loader) override {
+ bindings_.AddBinding(this, std::move(loader));
+ }
+
+ mojo::BindingSet<network::mojom::URLLoaderFactory> bindings_;
+};
+
} // namespace
// Kept around during the lifetime of the navigation request, and is
@@ -315,19 +372,23 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
std::unique_ptr<network::ResourceRequest> resource_request,
ResourceContext* resource_context,
const GURL& url,
+ bool is_main_frame,
network::mojom::URLLoaderFactoryRequest proxied_factory_request,
network::mojom::URLLoaderFactoryPtrInfo proxied_factory_info,
std::set<std::string> known_schemes,
+ bool bypass_redirect_checks,
const base::WeakPtr<NavigationURLLoaderImpl>& owner)
: interceptors_(std::move(initial_interceptors)),
resource_request_(std::move(resource_request)),
resource_context_(resource_context),
url_(url),
+ is_main_frame_(is_main_frame),
owner_(owner),
response_loader_binding_(this),
proxied_factory_request_(std::move(proxied_factory_request)),
proxied_factory_info_(std::move(proxied_factory_info)),
known_schemes_(std::move(known_schemes)),
+ bypass_redirect_checks_(bypass_redirect_checks),
weak_factory_(this) {}
~URLLoaderRequestController() override {
@@ -347,13 +408,19 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
}
static uint32_t GetURLLoaderOptions(bool is_main_frame) {
- uint32_t options = network::mojom::kURLLoadOptionSendSSLInfoWithResponse;
- if (is_main_frame)
+ uint32_t options = network::mojom::kURLLoadOptionNone;
+
+ // Ensure that Mime sniffing works.
+ options |= network::mojom::kURLLoadOptionSniffMimeType;
+
+ if (is_main_frame) {
+ // SSLInfo is not needed on subframe responses because users can inspect
+ // only the certificate for the main frame when using the info bubble.
+ options |= network::mojom::kURLLoadOptionSendSSLInfoWithResponse;
options |= network::mojom::kURLLoadOptionSendSSLInfoForCertificateError;
+ }
- if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
- options |= network::mojom::kURLLoadOptionSniffMimeType;
- } else {
+ if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
// TODO(arthursonzogni): This is a temporary option. Remove this as soon
// as the InterceptingResourceHandler is removed.
// See https://crbug.com/791049.
@@ -400,14 +467,22 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
std::unique_ptr<NavigationRequestInfo> request_info,
ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core,
AppCacheNavigationHandleCore* appcache_handle_core,
+ const network::ResourceRequest& /* resource_request */,
network::mojom::URLLoaderRequest url_loader,
network::mojom::URLLoaderClientPtr url_loader_client) {
+ // |resource_request| is unused here. Its info may not be the same as
+ // |request_info|, because URLLoaderThrottles may have rewritten it. We
+ // don't propagate the fields to |request_info| here because the request
+ // will usually go to ResourceDispatcherHost which does its own request
+ // modification independent of URLLoaderThrottles.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
DCHECK(started_);
default_loader_used_ = true;
if (signed_exchange_utils::IsSignedExchangeHandlingEnabled()) {
+ // TODO(falken): Understand and add a comment about why
+ // SignedExchangeRequestHandler is the only interceptor being added here.
DCHECK(!network_loader_factory_);
// It is safe to pass the callback of CreateURLLoaderThrottles with the
// unretained |this|, because the passed callback will be used by a
@@ -426,8 +501,7 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
resource_context_, url_request_context_getter),
base::BindRepeating(
&URLLoaderRequestController::CreateURLLoaderThrottles,
- base::Unretained(this)),
- url_request_context_getter));
+ base::Unretained(this))));
}
uint32_t options = GetURLLoaderOptions(request_info->is_main_frame);
@@ -549,7 +623,6 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
}
void Start(
- net::URLRequestContextGetter* url_request_context_getter,
std::unique_ptr<network::SharedURLLoaderFactoryInfo>
network_loader_factory_info,
ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core,
@@ -615,8 +688,8 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
if (appcache_handle_core) {
std::unique_ptr<NavigationLoaderInterceptor> appcache_interceptor =
- AppCacheRequestHandler::InitializeForNavigationNetworkService(
- *resource_request_, appcache_handle_core,
+ AppCacheRequestHandler::InitializeForMainResourceNetworkService(
+ *resource_request_, appcache_handle_core->host()->GetWeakPtr(),
network_loader_factory_);
if (appcache_interceptor)
interceptors_.push_back(std::move(appcache_interceptor));
@@ -642,8 +715,7 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
request_info->begin_params->load_flags, network_loader_factory_,
base::BindRepeating(
&URLLoaderRequestController::CreateURLLoaderThrottles,
- base::Unretained(this)),
- url_request_context_getter));
+ base::Unretained(this))));
}
std::vector<std::unique_ptr<URLLoaderRequestInterceptor>>
@@ -670,9 +742,15 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
// the restarted request to use a new loader, instead of, e.g., reusing the
// AppCache or service worker loader. For an optimization, we keep and reuse
// the default url loader if the all |interceptors_| doesn't handle the
- // redirected request.
- if (!default_loader_used_)
+ // redirected request. If the network service is enabled, only certain
+ // schemes are handled by the default URL loader. We need to make sure the
+ // redirected URL is a handled scheme, otherwise reset the loader so the
+ // correct non-network service loader can be used.
+ if (!default_loader_used_ ||
+ (base::FeatureList::IsEnabled(network::features::kNetworkService) &&
+ !IsURLHandledByDefaultLoader(resource_request_->url))) {
url_loader_.reset();
+ }
interceptor_index_ = 0;
received_response_ = false;
MaybeStartLoader(nullptr /* interceptor */,
@@ -694,11 +772,19 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
// |interceptor| wants to handle the request with
// |single_request_handler|.
DCHECK(interceptor);
+
+ std::vector<std::unique_ptr<URLLoaderThrottle>> throttles =
+ CreateURLLoaderThrottles();
+ // Intercepted requests need MimeSniffingThrottle to do mime sniffing.
+ // Non-intercepted requests usually go through the regular network
+ // URLLoader, which does mime sniffing.
+ throttles.push_back(std::make_unique<MimeSniffingThrottle>());
+
default_loader_used_ = false;
url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
base::MakeRefCounted<SingleRequestURLLoaderFactory>(
std::move(single_request_handler)),
- CreateURLLoaderThrottles(), frame_tree_node_id_,
+ std::move(throttles), frame_tree_node_id_,
global_request_id_.request_id, network::mojom::kURLLoadOptionNone,
resource_request_.get(), this, kNavigationUrlLoaderTrafficAnnotation,
base::ThreadTaskRunnerHandle::Get());
@@ -714,9 +800,9 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
// that case we will just fall back to the default loader (i.e. won't go on
// to the next interceptors) but send the subresource_loader_params to the
// child process. This is necessary for correctness in the cases where, e.g.
- // there's a controlling ServiceWorker that doesn't handle main resource
- // loading, but may still want to control the page and/or handle subresource
- // loading. In that case we want to skip AppCache.
+ // there's a controlling service worker that doesn't have a fetch event
+ // handler so it doesn't intercept requests. In that case we still want to
+ // skip AppCache.
if (interceptor) {
subresource_loader_params_ =
interceptor->MaybeCreateSubresourceLoaderParams();
@@ -733,13 +819,16 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
next_interceptor->MaybeCreateLoader(
*resource_request_, resource_context_,
base::BindOnce(&URLLoaderRequestController::MaybeStartLoader,
- base::Unretained(this), next_interceptor));
+ base::Unretained(this), next_interceptor),
+ base::BindOnce(
+ &URLLoaderRequestController::FallbackToNonInterceptedRequest,
+ base::Unretained(this)));
return;
}
- // If we already have the default |url_loader_| we must come here after
- // a redirect. No interceptors wanted to intercept the redirected request,
- // so let it just follow the redirect.
+ // If we already have the default |url_loader_| we must come here after a
+ // redirect. No interceptors wanted to intercept the redirected request, so
+ // let the loader just follow the redirect.
if (url_loader_) {
DCHECK(!redirect_info_.new_url.is_empty());
url_loader_->FollowRedirect(
@@ -747,48 +836,87 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
return;
}
- // TODO(https://crbug.com/796425): We temporarily wrap raw
- // mojom::URLLoaderFactory pointers into SharedURLLoaderFactory. Need to
- // further refactor the factory getters to avoid this.
- scoped_refptr<network::SharedURLLoaderFactory> factory;
- DCHECK_EQ(interceptors_.size(), interceptor_index_);
+ // No interceptors wanted to handle this request.
+ uint32_t options = network::mojom::kURLLoadOptionNone;
+ scoped_refptr<network::SharedURLLoaderFactory> factory =
+ PrepareForNonInterceptedRequest(&options);
+ url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
+ std::move(factory), CreateURLLoaderThrottles(), frame_tree_node_id_,
+ global_request_id_.request_id, options, resource_request_.get(),
+ this /* client */, kNavigationUrlLoaderTrafficAnnotation,
+ base::ThreadTaskRunnerHandle::Get());
+ }
+ // This is the |fallback_callback| passed to
+ // NavigationLoaderInterceptor::MaybeCreateLoader. It allows an interceptor
+ // to initially elect to handle a request, and later decide to fallback to
+ // the default behavior. This is needed for service worker network fallback.
+ void FallbackToNonInterceptedRequest(bool reset_subresource_loader_params) {
+ if (reset_subresource_loader_params)
+ subresource_loader_params_.reset();
+
+ // Non-NetworkService:
+ // Cancel state on ResourceDispatcherHostImpl so it doesn't complain about
+ // reusing the request_id after redirects. Otherwise the following sequence
+ // can happen:
+ // RDHI Start(request_id) -> Redirect -> SW interception -> SW fallback to
+ // network -> RDHI Start(request_id).
+ if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ DCHECK(ResourceDispatcherHostImpl::Get());
+ ResourceDispatcherHostImpl::Get()->CancelRequest(
+ global_request_id_.child_id, global_request_id_.request_id);
+ }
+
+ // |url_loader_| is using the factory for the interceptor that decided to
+ // fallback, so restart it with the non-interceptor factory.
+ DCHECK(url_loader_);
+ uint32_t options = network::mojom::kURLLoadOptionNone;
+ scoped_refptr<network::SharedURLLoaderFactory> factory =
+ PrepareForNonInterceptedRequest(&options);
+ url_loader_->RestartWithFactory(std::move(factory), options);
+ }
+
+ scoped_refptr<network::SharedURLLoaderFactory>
+ PrepareForNonInterceptedRequest(uint32_t* out_options) {
// If NetworkService is not enabled (which means we come here because one of
// the loader interceptors is enabled), use the default request handler
// instead of going through the NetworkService path.
if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
DCHECK(!interceptors_.empty());
DCHECK(default_request_handler_factory_);
- // The only way to come here is to enable ServiceWorkerServicification
- // without NetworkService. We know that the service worker's request
- // interceptor has already intercepted and decided not to handle the
+ // The only way to come here is to enable ServiceWorkerServicification or
+ // SignedExchange without NetworkService. We know that their request
+ // interceptors have already intercepted and decided not to handle the
// request.
- DCHECK(blink::ServiceWorkerUtils::IsServicificationEnabled());
+ DCHECK(blink::ServiceWorkerUtils::IsServicificationEnabled() ||
+ signed_exchange_utils::IsSignedExchangeHandlingEnabled());
default_loader_used_ = true;
// Update |request_info_| when following a redirect.
if (url_chain_.size() > 0) {
request_info_ = CreateNavigationRequestInfoForRedirect(
*request_info_, *resource_request_);
}
+
// When |subresource_loader_params_| has its value, the request should not
// be intercepted by any other interceptors since it means that a request
// interceptor already intercepted the request and it attached its info to
// the request.
- url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
- base::MakeRefCounted<SingleRequestURLLoaderFactory>(
- default_request_handler_factory_.Run(
- subresource_loader_params_.has_value()
- /* was_request_intercepted */)),
- CreateURLLoaderThrottles(), frame_tree_node_id_,
- global_request_id_.request_id, network::mojom::kURLLoadOptionNone,
- resource_request_.get(), this /* client */,
- kNavigationUrlLoaderTrafficAnnotation,
- base::ThreadTaskRunnerHandle::Get());
- return;
+ bool was_request_intercepted = subresource_loader_params_.has_value();
+
+ // TODO(falken): Determine whether GetURLLoaderOptions() can be called
+ // here like below. It looks like |default_request_handler_factory_| just
+ // calls that.
+ *out_options = network::mojom::kURLLoadOptionNone;
+ return base::MakeRefCounted<SingleRequestURLLoaderFactory>(
+ default_request_handler_factory_.Run(was_request_intercepted));
}
- if (!IsURLHandledByNetworkService(resource_request_->url) &&
- !resource_request_->url.SchemeIs(url::kDataScheme)) {
+ // TODO(https://crbug.com/796425): We temporarily wrap raw
+ // mojom::URLLoaderFactory pointers into SharedURLLoaderFactory. Need to
+ // further refactor the factory getters to avoid this.
+ scoped_refptr<network::SharedURLLoaderFactory> factory;
+
+ if (!IsURLHandledByDefaultLoader(resource_request_->url)) {
if (known_schemes_.find(resource_request_->url.scheme()) ==
known_schemes_.end()) {
bool handled = GetContentClient()->browser()->HandleExternalProtocol(
@@ -836,13 +964,9 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
}
}
url_chain_.push_back(resource_request_->url);
- uint32_t options = GetURLLoaderOptions(resource_request_->resource_type ==
- RESOURCE_TYPE_MAIN_FRAME);
- url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
- factory, CreateURLLoaderThrottles(), frame_tree_node_id_,
- global_request_id_.request_id, options, resource_request_.get(), this,
- kNavigationUrlLoaderTrafficAnnotation,
- base::ThreadTaskRunnerHandle::Get());
+ *out_options = GetURLLoaderOptions(resource_request_->resource_type ==
+ RESOURCE_TYPE_MAIN_FRAME);
+ return factory;
}
void FollowRedirect(
@@ -897,6 +1021,11 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
private:
// network::mojom::URLLoaderClient implementation:
void OnReceiveResponse(const network::ResourceResponseHead& head) override {
+ // Record the SCT histogram before checking if anything wants to intercept
+ // the response, so interceptors like AppCache and extensions can't hide
+ // values from the histograms.
+ RecordSCTHistogramIfNeeded(head.ssl_info);
+
received_response_ = true;
// If the default loader (network) was used to handle the URL load request
@@ -922,86 +1051,105 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
bool is_download;
bool is_stream;
+ // If there is not an explicit PreviewsState set on the request, turn
+ // Previews off.
+ PreviewsState previews_state = PREVIEWS_OFF;
std::unique_ptr<NavigationData> cloned_navigation_data;
+
if (IsLoaderInterceptionEnabled()) {
bool must_download = download_utils::MustDownload(
url_, head.headers.get(), head.mime_type);
bool known_mime_type = blink::IsSupportedMimeType(head.mime_type);
+ bool is_download_if_not_handled_by_plugin =
+ !response_intercepted && (must_download || !known_mime_type);
+
#if BUILDFLAG(ENABLE_PLUGINS)
if (!response_intercepted && !must_download && !known_mime_type) {
CheckPluginAndContinueOnReceiveResponse(
head, std::move(url_loader_client_endpoints),
- std::vector<WebPluginInfo>());
+ is_download_if_not_handled_by_plugin, std::vector<WebPluginInfo>());
return;
}
#endif
- is_download =
- !response_intercepted && (must_download || !known_mime_type);
+ is_download = is_download_if_not_handled_by_plugin;
is_stream = false;
- } else {
- ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
- net::URLRequest* url_request = rdh->GetURLRequest(global_request_id_);
-
- // The |url_request| maybe have been removed from the resource dispatcher
- // host during the time it took for OnReceiveResponse() to be received.
- if (url_request) {
- ResourceRequestInfoImpl* info =
- ResourceRequestInfoImpl::ForRequest(url_request);
- is_download = !response_intercepted && info->IsDownload();
- is_stream = info->is_stream();
- if (rdh->delegate()) {
- NavigationData* navigation_data =
- rdh->delegate()->GetNavigationData(url_request);
-
- // Clone the embedder's NavigationData before moving it to the UI
- // thread.
- if (navigation_data)
- cloned_navigation_data = navigation_data->Clone();
- }
- // This is similar to what is done in
- // ServiceWorkerControlleeHandler::MaybeCreateSubresourceLoaderParams().
- // It takes the matching ControllerServiceWorkerInfo (if any) associated
- // with the request. It will be sent to the renderer process and used to
- // intercept requests.
- // TODO(arthursonzogni): This is needed only for the
- // non-S13nServiceWorker case. The S13nServiceWorker case is still not
- // supported without the NetworkService. This block needs to be updated
- // once support for it will be added.
- ServiceWorkerProviderHost* sw_provider_host =
- ServiceWorkerRequestHandler::GetProviderHost(url_request);
- if (sw_provider_host && sw_provider_host->controller()) {
- subresource_loader_params_ = SubresourceLoaderParams();
- subresource_loader_params_->controller_service_worker_info =
- mojom::ControllerServiceWorkerInfo::New();
- subresource_loader_params_->controller_service_worker_info->mode =
- sw_provider_host->GetControllerMode();
- base::WeakPtr<ServiceWorkerObjectHost> sw_object_host =
- sw_provider_host->GetOrCreateServiceWorkerObjectHost(
- sw_provider_host->controller());
- if (sw_object_host) {
- subresource_loader_params_->controller_service_worker_object_host =
- sw_object_host;
- subresource_loader_params_->controller_service_worker_info
- ->object_info = sw_object_host->CreateIncompleteObjectInfo();
- }
+ // If NetworkService is on, or an interceptor handled the request, the
+ // request doesn't use ResourceDispatcherHost so
+ // CallOnReceivedResponse and return here.
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService) ||
+ !default_loader_used_) {
+ CallOnReceivedResponse(head, std::move(url_loader_client_endpoints),
+ std::move(cloned_navigation_data), is_download,
+ is_stream, previews_state);
+ return;
+ }
+ }
+
+ // NetworkService is off and an interceptor didn't handle the request,
+ // so it went to ResourceDispatcherHost.
+ ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
+ net::URLRequest* url_request = rdh->GetURLRequest(global_request_id_);
+
+ // The |url_request| maybe have been removed from the resource dispatcher
+ // host during the time it took for OnReceiveResponse() to be received.
+ if (url_request) {
+ ResourceRequestInfoImpl* info =
+ ResourceRequestInfoImpl::ForRequest(url_request);
+ is_download = !response_intercepted && info->IsDownload();
+ is_stream = info->is_stream();
+ previews_state = info->GetPreviewsState();
+ if (rdh->delegate()) {
+ NavigationData* navigation_data =
+ rdh->delegate()->GetNavigationData(url_request);
+
+ // Clone the embedder's NavigationData before moving it to the UI
+ // thread.
+ if (navigation_data)
+ cloned_navigation_data = navigation_data->Clone();
+ }
+
+ // non-S13nServiceWorker:
+ // This is similar to what is done in
+ // ServiceWorkerControlleeHandler::MaybeCreateSubresourceLoaderParams()
+ // (which is used when S13nServiceWorker is on). It takes the matching
+ // ControllerServiceWorkerInfo (if any) associated with the request. It
+ // will be sent to the renderer process and used to intercept requests.
+ ServiceWorkerProviderHost* sw_provider_host =
+ ServiceWorkerRequestHandler::GetProviderHost(url_request);
+ if (sw_provider_host && sw_provider_host->controller()) {
+ DCHECK(!blink::ServiceWorkerUtils::IsServicificationEnabled());
+ subresource_loader_params_ = SubresourceLoaderParams();
+ subresource_loader_params_->controller_service_worker_info =
+ mojom::ControllerServiceWorkerInfo::New();
+ subresource_loader_params_->controller_service_worker_info->mode =
+ sw_provider_host->GetControllerMode();
+ base::WeakPtr<ServiceWorkerObjectHost> sw_object_host =
+ sw_provider_host->GetOrCreateServiceWorkerObjectHost(
+ sw_provider_host->controller());
+ if (sw_object_host) {
+ subresource_loader_params_->controller_service_worker_object_host =
+ sw_object_host;
+ subresource_loader_params_->controller_service_worker_info
+ ->object_info = sw_object_host->CreateIncompleteObjectInfo();
}
- } else {
- is_download = is_stream = false;
}
+ } else {
+ is_download = is_stream = false;
}
CallOnReceivedResponse(head, std::move(url_loader_client_endpoints),
std::move(cloned_navigation_data), is_download,
- is_stream);
+ is_stream, previews_state);
}
#if BUILDFLAG(ENABLE_PLUGINS)
void CheckPluginAndContinueOnReceiveResponse(
const network::ResourceResponseHead& head,
network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
+ bool is_download_if_not_handled_by_plugin,
const std::vector<WebPluginInfo>& plugins) {
bool stale;
WebPluginInfo plugin;
@@ -1020,16 +1168,16 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
PluginService::GetInstance()->GetPlugins(base::BindOnce(
&URLLoaderRequestController::CheckPluginAndContinueOnReceiveResponse,
weak_factory_.GetWeakPtr(), head,
- std::move(url_loader_client_endpoints)));
+ std::move(url_loader_client_endpoints),
+ is_download_if_not_handled_by_plugin));
return;
}
- bool is_download =
- !has_plugin &&
- (!head.headers || head.headers->response_code() / 100 == 2);
+ bool is_download = !has_plugin && is_download_if_not_handled_by_plugin;
CallOnReceivedResponse(head, std::move(url_loader_client_endpoints),
- nullptr, is_download, false /* is_stream */);
+ nullptr, is_download, false /* is_stream */,
+ PREVIEWS_OFF /* previews_state */);
}
#endif
@@ -1038,7 +1186,8 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
std::unique_ptr<NavigationData> cloned_navigation_data,
bool is_download,
- bool is_stream) {
+ bool is_stream,
+ PreviewsState previews_state) {
scoped_refptr<network::ResourceResponse> response(
new network::ResourceResponse());
response->head = head;
@@ -1055,11 +1204,18 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
response->DeepCopy(),
std::move(url_loader_client_endpoints),
std::move(cloned_navigation_data), global_request_id_,
- is_download, is_stream));
+ is_download, is_stream, previews_state));
}
void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
const network::ResourceResponseHead& head) override {
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService) &&
+ !bypass_redirect_checks_ &&
+ !IsRedirectSafe(url_, redirect_info.new_url, resource_context_)) {
+ OnComplete(network::URLLoaderCompletionStatus(net::ERR_UNSAFE_REDIRECT));
+ return;
+ }
+
if (--redirect_limit_ == 0) {
OnComplete(
network::URLLoaderCompletionStatus(net::ERR_TOO_MANY_REDIRECTS));
@@ -1100,6 +1256,8 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
}
void OnComplete(const network::URLLoaderCompletionStatus& status) override {
+ RecordSCTHistogramIfNeeded(status.ssl_info);
+
UMA_HISTOGRAM_BOOLEAN(
"Navigation.URLLoaderNetworkService.OnCompleteHasSSLInfo",
status.ssl_info.has_value());
@@ -1138,6 +1296,8 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
if (interceptor->MaybeCreateLoaderForResponse(
response, &response_url_loader_, &response_client_request,
url_loader_.get())) {
+ if (response_loader_binding_.is_bound())
+ response_loader_binding_.Close();
response_loader_binding_.Bind(std::move(response_client_request));
default_loader_used_ = false;
url_loader_.reset();
@@ -1147,8 +1307,7 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
return false;
}
- std::vector<std::unique_ptr<content::URLLoaderThrottle>>
- CreateURLLoaderThrottles() {
+ std::vector<std::unique_ptr<URLLoaderThrottle>> CreateURLLoaderThrottles() {
return GetContentClient()->browser()->CreateURLLoaderThrottles(
*resource_request_, resource_context_, web_contents_getter_,
navigation_ui_data_.get(), frame_tree_node_id_);
@@ -1168,7 +1327,7 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
storage::BlobStorageContext* blob_storage_context = GetBlobStorageContext(
GetChromeBlobStorageContextForResourceContext(resource_context_));
return ServiceWorkerRequestHandler::InitializeForNavigationNetworkService(
- *resource_request_, resource_context_,
+ resource_request_->url, resource_context_,
service_worker_navigation_handle_core, blob_storage_context,
request_info.begin_params->skip_service_worker, resource_type,
request_info.begin_params->request_context_type, frame_type,
@@ -1176,6 +1335,21 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
web_contents_getter_);
}
+ void RecordSCTHistogramIfNeeded(
+ const base::Optional<net::SSLInfo>& ssl_info) {
+ if (is_main_frame_ && url_.SchemeIsCryptographic() &&
+ ssl_info.has_value()) {
+ int num_valid_scts = 0;
+ for (const auto& signed_certificate_timestamps :
+ ssl_info->signed_certificate_timestamps) {
+ if (signed_certificate_timestamps.status == net::ct::SCT_STATUS_OK)
+ ++num_valid_scts;
+ }
+ UMA_HISTOGRAM_COUNTS_100(
+ "Net.CertificateTransparency.MainFrameValidSCTCount", num_valid_scts);
+ }
+ }
+
std::vector<std::unique_ptr<NavigationLoaderInterceptor>> interceptors_;
size_t interceptor_index_ = 0;
@@ -1204,6 +1378,8 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
// Current URL that is being navigated, updated after redirection.
GURL url_;
+ const bool is_main_frame_;
+
// Currently used by the AppCache loader to pass its factory to the
// renderer which enables it to handle subresources.
base::Optional<SubresourceLoaderParams> subresource_loader_params_;
@@ -1266,6 +1442,9 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
// protocol handlers.
std::set<std::string> known_schemes_;
+ // If true, redirect checks will be handled in a proxy, and not here.
+ bool bypass_redirect_checks_;
+
mutable base::WeakPtrFactory<URLLoaderRequestController> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(URLLoaderRequestController);
@@ -1312,10 +1491,10 @@ NavigationURLLoaderImpl::NavigationURLLoaderImpl(
/* initial_interceptors = */
std::vector<std::unique_ptr<NavigationLoaderInterceptor>>(),
std::move(new_request), resource_context,
- request_info->common_params.url,
+ request_info->common_params.url, request_info->is_main_frame,
/* proxied_url_loader_factory_request */ nullptr,
/* proxied_url_loader_factory_info */ nullptr, std::set<std::string>(),
- weak_factory_.GetWeakPtr());
+ /* bypass_redirect_checks */ false, weak_factory_.GetWeakPtr());
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
@@ -1344,6 +1523,7 @@ NavigationURLLoaderImpl::NavigationURLLoaderImpl(
network::mojom::URLLoaderFactoryPtrInfo proxied_factory_info;
network::mojom::URLLoaderFactoryRequest proxied_factory_request;
+ bool bypass_redirect_checks = false;
auto* partition = static_cast<StoragePartitionImpl*>(storage_partition);
if (frame_tree_node) {
// |frame_tree_node| may be null in some unit test environments.
@@ -1360,7 +1540,8 @@ NavigationURLLoaderImpl::NavigationURLLoaderImpl(
auto factory_request = mojo::MakeRequest(&factory_info);
bool use_proxy = GetContentClient()->browser()->WillCreateURLLoaderFactory(
partition->browser_context(), frame_tree_node->current_frame_host(),
- true /* is_navigation */, &factory_request);
+ true /* is_navigation */, new_request->url, &factory_request);
+ bypass_redirect_checks = use_proxy;
if (RenderFrameDevToolsAgentHost::WillCreateURLLoaderFactory(
frame_tree_node->current_frame_host(), true, false,
&factory_request)) {
@@ -1379,11 +1560,14 @@ NavigationURLLoaderImpl::NavigationURLLoaderImpl(
storage_domain);
}
+ non_network_url_loader_factories_[url::kAboutScheme] =
+ std::make_unique<AboutURLLoaderFactory>();
+
non_network_url_loader_factories_[url::kFileScheme] =
std::make_unique<FileURLLoaderFactory>(
partition->browser_context()->GetPath(),
base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::BACKGROUND,
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
std::set<std::string> known_schemes;
for (auto& iter : non_network_url_loader_factories_)
@@ -1392,15 +1576,15 @@ NavigationURLLoaderImpl::NavigationURLLoaderImpl(
DCHECK(!request_controller_);
request_controller_ = std::make_unique<URLLoaderRequestController>(
std::move(initial_interceptors), std::move(new_request), resource_context,
- request_info->common_params.url, std::move(proxied_factory_request),
- std::move(proxied_factory_info), std::move(known_schemes),
+ request_info->common_params.url, request_info->is_main_frame,
+ std::move(proxied_factory_request), std::move(proxied_factory_info),
+ std::move(known_schemes), bypass_redirect_checks,
weak_factory_.GetWeakPtr());
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::BindOnce(
&URLLoaderRequestController::Start,
base::Unretained(request_controller_.get()),
- base::RetainedRef(storage_partition->GetURLRequestContext()),
partition->url_loader_factory_getter()->GetNetworkFactoryInfo(),
service_worker_navigation_handle_core, appcache_handle_core,
std::move(request_info), std::move(navigation_ui_data),
@@ -1432,7 +1616,8 @@ void NavigationURLLoaderImpl::OnReceiveResponse(
std::unique_ptr<NavigationData> navigation_data,
const GlobalRequestID& global_request_id,
bool is_download,
- bool is_stream) {
+ bool is_stream,
+ PreviewsState previews_state) {
TRACE_EVENT_ASYNC_END2("navigation", "Navigation timeToResponseStarted", this,
"&NavigationURLLoaderImpl", this, "success", true);
@@ -1442,7 +1627,7 @@ void NavigationURLLoaderImpl::OnReceiveResponse(
delegate_->OnResponseStarted(
std::move(response), std::move(url_loader_client_endpoints),
std::move(navigation_data), global_request_id,
- allow_download_ && is_download, is_stream,
+ allow_download_ && is_download, is_stream, previews_state,
request_controller_->TakeSubresourceLoaderParams());
}
@@ -1491,7 +1676,7 @@ void NavigationURLLoaderImpl::BindNonNetworkURLLoaderFactoryRequest(
auto* frame = frame_tree_node->current_frame_host();
GetContentClient()->browser()->WillCreateURLLoaderFactory(
frame->GetSiteInstance()->GetBrowserContext(), frame,
- true /* is_navigation */, &factory);
+ true /* is_navigation */, url, &factory);
it->second->Clone(std::move(factory));
}
diff --git a/chromium/content/browser/loader/navigation_url_loader_impl.h b/chromium/content/browser/loader/navigation_url_loader_impl.h
index ac5e384a04d..1bcc9efb46d 100644
--- a/chromium/content/browser/loader/navigation_url_loader_impl.h
+++ b/chromium/content/browser/loader/navigation_url_loader_impl.h
@@ -12,6 +12,7 @@
#include "content/browser/loader/navigation_url_loader.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/ssl_status.h"
+#include "content/public/common/previews_state.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
@@ -22,9 +23,9 @@ struct RedirectInfo;
namespace content {
class NavigationData;
+class NavigationLoaderInterceptor;
class ResourceContext;
class StoragePartition;
-class NavigationLoaderInterceptor;
struct GlobalRequestID;
class CONTENT_EXPORT NavigationURLLoaderImpl : public NavigationURLLoader {
@@ -56,7 +57,8 @@ class CONTENT_EXPORT NavigationURLLoaderImpl : public NavigationURLLoader {
std::unique_ptr<NavigationData> navigation_data,
const GlobalRequestID& global_request_id,
bool is_download,
- bool is_stream);
+ bool is_stream,
+ PreviewsState previews_state);
void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
scoped_refptr<network::ResourceResponse> response);
void OnComplete(const network::URLLoaderCompletionStatus& status);
diff --git a/chromium/content/browser/loader/navigation_url_loader_impl_unittest.cc b/chromium/content/browser/loader/navigation_url_loader_impl_unittest.cc
index 538274d42a9..37cf04dda21 100644
--- a/chromium/content/browser/loader/navigation_url_loader_impl_unittest.cc
+++ b/chromium/content/browser/loader/navigation_url_loader_impl_unittest.cc
@@ -71,13 +71,13 @@ class TestNavigationLoaderInterceptor : public NavigationLoaderInterceptor {
void MaybeCreateLoader(const network::ResourceRequest& resource_request,
ResourceContext* resource_context,
- LoaderCallback callback) override {
- std::move(callback).Run(
- base::BindOnce(&TestNavigationLoaderInterceptor::StartLoader,
- base::Unretained(this), resource_request));
+ LoaderCallback callback,
+ FallbackCallback fallback_callback) override {
+ std::move(callback).Run(base::BindOnce(
+ &TestNavigationLoaderInterceptor::StartLoader, base::Unretained(this)));
}
- void StartLoader(network::ResourceRequest resource_request,
+ void StartLoader(const network::ResourceRequest& resource_request,
network::mojom::URLLoaderRequest request,
network::mojom::URLLoaderClientPtr client) {
*most_recent_resource_request_ = resource_request;
@@ -145,6 +145,10 @@ class NavigationURLLoaderImplTest : public testing::Test {
}
~NavigationURLLoaderImplTest() override {
+ // The context needs to be deleted before ServiceManagerConnection is
+ // destroyed, so the storage partition in the context does not try to
+ // reconnect to the network service after ServiceManagerConnection is dead.
+ browser_context_.reset();
ServiceManagerConnection::DestroyForProcess();
}
diff --git a/chromium/content/browser/loader/prefetch_browsertest.cc b/chromium/content/browser/loader/prefetch_browsertest.cc
index fb0726ef37c..b3776b2bac6 100644
--- a/chromium/content/browser/loader/prefetch_browsertest.cc
+++ b/chromium/content/browser/loader/prefetch_browsertest.cc
@@ -29,11 +29,8 @@
namespace content {
struct PrefetchBrowserTestParam {
- PrefetchBrowserTestParam(bool network_service_enabled,
- bool signed_exchange_enabled)
- : network_service_enabled(network_service_enabled),
- signed_exchange_enabled(signed_exchange_enabled) {}
- const bool network_service_enabled;
+ PrefetchBrowserTestParam(bool signed_exchange_enabled)
+ : signed_exchange_enabled(signed_exchange_enabled) {}
const bool signed_exchange_enabled;
};
@@ -69,8 +66,6 @@ class PrefetchBrowserTest
void SetUp() override {
std::vector<base::Feature> enable_features;
- if (GetParam().network_service_enabled)
- enable_features.push_back(network::features::kNetworkService);
if (GetParam().signed_exchange_enabled)
enable_features.push_back(features::kSignedHTTPExchange);
feature_list_.InitWithFeatures(enable_features, {});
@@ -110,12 +105,16 @@ class PrefetchBrowserTest
return nullptr;
}
- void WatchURLAndRunClosure(const std::string& relative_url,
- int* visit_count,
- base::OnceClosure closure,
- const net::test_server::HttpRequest& request) {
+ void WatchURLAndRunClosure(
+ const std::string& relative_url,
+ int* visit_count,
+ net::test_server::HttpRequest::HeaderMap* out_headers,
+ base::OnceClosure closure,
+ const net::test_server::HttpRequest& request) {
if (request.relative_url == relative_url) {
(*visit_count)++;
+ if (out_headers)
+ *out_headers = request.headers;
if (closure)
std::move(closure).Run();
}
@@ -124,8 +123,7 @@ class PrefetchBrowserTest
void OnPrefetchURLLoaderCalled() { prefetch_url_loader_called_++; }
bool CheckPrefetchURLLoaderCountIfSupported(int expected) const {
- if (!base::FeatureList::IsEnabled(features::kSignedHTTPExchange) &&
- !base::FeatureList::IsEnabled(network::features::kNetworkService))
+ if (!base::FeatureList::IsEnabled(features::kSignedHTTPExchange))
return true;
return prefetch_url_loader_called_ == expected;
}
@@ -153,7 +151,7 @@ IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest, Simple) {
base::RunLoop prefetch_waiter;
embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
&PrefetchBrowserTest::WatchURLAndRunClosure, base::Unretained(this),
- target_url, &target_fetch_count, prefetch_waiter.QuitClosure()));
+ target_url, &target_fetch_count, nullptr, prefetch_waiter.QuitClosure()));
embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
&PrefetchBrowserTest::ServeResponses, base::Unretained(this)));
ASSERT_TRUE(embedded_test_server()->Start());
@@ -191,7 +189,7 @@ IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest, DoublePrefetch) {
base::RunLoop prefetch_waiter;
embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
&PrefetchBrowserTest::WatchURLAndRunClosure, base::Unretained(this),
- target_url, &target_fetch_count, prefetch_waiter.QuitClosure()));
+ target_url, &target_fetch_count, nullptr, prefetch_waiter.QuitClosure()));
embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
&PrefetchBrowserTest::ServeResponses, base::Unretained(this)));
ASSERT_TRUE(embedded_test_server()->Start());
@@ -238,10 +236,12 @@ IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest, NoCacheAndNoStore) {
base::RunLoop nostore_waiter;
embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
&PrefetchBrowserTest::WatchURLAndRunClosure, base::Unretained(this),
- nocache_url, &nocache_fetch_count, nocache_waiter.QuitClosure()));
+ nocache_url, &nocache_fetch_count, nullptr,
+ nocache_waiter.QuitClosure()));
embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
&PrefetchBrowserTest::WatchURLAndRunClosure, base::Unretained(this),
- nostore_url, &nostore_fetch_count, nostore_waiter.QuitClosure()));
+ nostore_url, &nostore_fetch_count, nullptr,
+ nostore_waiter.QuitClosure()));
embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
&PrefetchBrowserTest::ServeResponses, base::Unretained(this)));
ASSERT_TRUE(embedded_test_server()->Start());
@@ -298,10 +298,11 @@ IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest, WithPreload) {
base::RunLoop preload_waiter;
embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
&PrefetchBrowserTest::WatchURLAndRunClosure, base::Unretained(this),
- target_url, &target_fetch_count, base::RepeatingClosure()));
+ target_url, &target_fetch_count, nullptr, base::RepeatingClosure()));
embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
&PrefetchBrowserTest::WatchURLAndRunClosure, base::Unretained(this),
- preload_url, &preload_fetch_count, preload_waiter.QuitClosure()));
+ preload_url, &preload_fetch_count, nullptr,
+ preload_waiter.QuitClosure()));
embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
&PrefetchBrowserTest::ServeResponses, base::Unretained(this)));
ASSERT_TRUE(embedded_test_server()->Start());
@@ -344,27 +345,30 @@ IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest, WebPackageWithPreload) {
RegisterResponse(
target_sxg,
// We mock the SignedExchangeHandler, so just return a HTML content
- // as "application/signed-exchange;v=b0".
+ // as "application/signed-exchange;v=b2".
ResponseEntry("<head><title>Prefetch Target (SXG)</title></head>",
- "application/signed-exchange;v=b0"));
+ "application/signed-exchange;v=b2"));
RegisterResponse(preload_url_in_sxg,
ResponseEntry("function foo() {}", "text/javascript"));
base::RunLoop preload_waiter;
base::RunLoop prefetch_waiter;
+ net::test_server::HttpRequest::HeaderMap prefetch_headers;
embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
&PrefetchBrowserTest::WatchURLAndRunClosure, base::Unretained(this),
- target_sxg, &target_fetch_count, prefetch_waiter.QuitClosure()));
+ target_sxg, &target_fetch_count, &prefetch_headers,
+ prefetch_waiter.QuitClosure()));
embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
&PrefetchBrowserTest::WatchURLAndRunClosure, base::Unretained(this),
- preload_url_in_sxg, &preload_fetch_count, preload_waiter.QuitClosure()));
+ preload_url_in_sxg, &preload_fetch_count, nullptr,
+ preload_waiter.QuitClosure()));
embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
&PrefetchBrowserTest::ServeResponses, base::Unretained(this)));
ASSERT_TRUE(embedded_test_server()->Start());
EXPECT_TRUE(CheckPrefetchURLLoaderCountIfSupported(0));
MockSignedExchangeHandlerFactory factory(
- net::OK, GURL(target_url), "text/html",
+ net::OK, GURL(embedded_test_server()->GetURL(target_url)), "text/html",
{base::StringPrintf(
"Link: <%s>;rel=\"preload\";as=\"script\"",
embedded_test_server()->GetURL(preload_url_in_sxg).spec().c_str())});
@@ -376,13 +380,14 @@ IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest, WebPackageWithPreload) {
prefetch_waiter.Run();
EXPECT_EQ(1, target_fetch_count);
EXPECT_TRUE(CheckPrefetchURLLoaderCountIfSupported(1));
-
- // Test after this point requires SignedHTTPExchange support, which is now
- // disabled when Network Service is enabled.
- // TODO(https://crbug.com/849935): Remove the second condition once we
- // re-enable Signed Exchange with Network Service.
- if (!base::FeatureList::IsEnabled(features::kSignedHTTPExchange) ||
- base::FeatureList::IsEnabled(network::features::kNetworkService))
+ if (base::FeatureList::IsEnabled(features::kSignedHTTPExchange))
+ EXPECT_EQ(prefetch_headers["Accept"],
+ "application/signed-exchange;v=b2;q=0.9,*/*;q=0.8");
+ else
+ EXPECT_EQ(prefetch_headers["Accept"], "*/*");
+
+ // Test after this point requires SignedHTTPExchange support
+ if (!base::FeatureList::IsEnabled(features::kSignedHTTPExchange))
return;
// If the header in the .sxg file is correctly extracted, we should
@@ -393,10 +398,7 @@ IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest, WebPackageWithPreload) {
INSTANTIATE_TEST_CASE_P(PrefetchBrowserTest,
PrefetchBrowserTest,
- testing::Values(PrefetchBrowserTestParam(true, true),
- PrefetchBrowserTestParam(true, false),
- PrefetchBrowserTestParam(false, true),
- PrefetchBrowserTestParam(false,
- false)));
+ testing::Values(PrefetchBrowserTestParam(true),
+ PrefetchBrowserTestParam(false)));
} // namespace content
diff --git a/chromium/content/browser/loader/resource_dispatcher_host_impl.cc b/chromium/content/browser/loader/resource_dispatcher_host_impl.cc
index 061ad189c46..2ed617dbab8 100644
--- a/chromium/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/chromium/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -28,8 +28,8 @@
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
-#include "base/task_scheduler/post_task.h"
-#include "base/task_scheduler/task_traits.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/timer/timer.h"
@@ -91,7 +91,6 @@
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/base/upload_data_stream.h"
#include "net/base/url_util.h"
-#include "net/cert/cert_status_flags.h"
#include "net/cookies/cookie_monster.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
@@ -169,11 +168,6 @@ void AbortRequestBeforeItStarts(
url_loader_client->OnComplete(status);
}
-bool IsValidatedSCT(
- const net::SignedCertificateTimestampAndStatus& sct_status) {
- return sct_status.status == net::ct::SCT_STATUS_OK;
-}
-
// Returns the PreviewsState for enabled previews after requesting it from
// the delegate. The PreviewsState is a bitmask of potentially several
// Previews optimizations that are initially enabled for a navigation.
@@ -605,18 +599,6 @@ void ResourceDispatcherHostImpl::DidReceiveResponse(
void ResourceDispatcherHostImpl::DidFinishLoading(ResourceLoader* loader) {
ResourceRequestInfoImpl* info = loader->GetRequestInfo();
- // Record final result of all resource loads.
- if (info->GetResourceType() == RESOURCE_TYPE_MAIN_FRAME) {
- if (loader->request()->url().SchemeIsCryptographic()) {
- int num_valid_scts = std::count_if(
- loader->request()->ssl_info().signed_certificate_timestamps.begin(),
- loader->request()->ssl_info().signed_certificate_timestamps.end(),
- IsValidatedSCT);
- UMA_HISTOGRAM_COUNTS_100(
- "Net.CertificateTransparency.MainFrameValidSCTCount", num_valid_scts);
- }
- }
-
if (delegate_)
delegate_->RequestComplete(loader->request());
@@ -1078,11 +1060,11 @@ ResourceDispatcherHostImpl::CreateResourceHandler(
requester_info->IsNavigationPreload() ||
requester_info->IsCertificateFetcherForSignedExchange());
// Construct the IPC resource handler.
- std::unique_ptr<ResourceHandler> handler;
- handler = CreateBaseResourceHandler(
- request, url_loader_options, std::move(mojo_request),
- std::move(url_loader_client),
- static_cast<ResourceType>(request_data.resource_type));
+ std::unique_ptr<ResourceHandler> handler =
+ std::make_unique<MojoAsyncResourceHandler>(
+ request, this, std::move(mojo_request), std::move(url_loader_client),
+ static_cast<ResourceType>(request_data.resource_type),
+ url_loader_options);
// Prefetches outlive their child process.
if (request_data.resource_type == RESOURCE_TYPE_PREFETCH) {
@@ -1097,22 +1079,8 @@ ResourceDispatcherHostImpl::CreateResourceHandler(
request, static_cast<ResourceType>(request_data.resource_type),
resource_context, request_data.fetch_request_mode,
static_cast<RequestContextType>(request_data.fetch_request_context_type),
- requester_info->appcache_service(), child_id, route_id,
- std::move(handler));
-}
-
-std::unique_ptr<ResourceHandler>
-ResourceDispatcherHostImpl::CreateBaseResourceHandler(
- net::URLRequest* request,
- uint32_t url_loader_options,
- network::mojom::URLLoaderRequest mojo_request,
- network::mojom::URLLoaderClientPtr url_loader_client,
- ResourceType resource_type) {
- std::unique_ptr<ResourceHandler> handler;
- handler.reset(new MojoAsyncResourceHandler(
- request, this, std::move(mojo_request), std::move(url_loader_client),
- resource_type, url_loader_options));
- return handler;
+ url_loader_options, requester_info->appcache_service(), child_id,
+ route_id, std::move(handler));
}
std::unique_ptr<ResourceHandler>
@@ -1122,6 +1090,7 @@ ResourceDispatcherHostImpl::AddStandardHandlers(
ResourceContext* resource_context,
network::mojom::FetchRequestMode fetch_request_mode,
RequestContextType fetch_request_context_type,
+ uint32_t url_loader_options,
AppCacheService* appcache_service,
int child_id,
int route_id,
@@ -1190,9 +1159,11 @@ ResourceDispatcherHostImpl::AddStandardHandlers(
// Note: all ResourceHandler following the MimeSniffingResourceHandler
// should expect OnWillRead to be called *before* OnResponseStarted as
// part of the mime sniffing process.
- handler.reset(new MimeSniffingResourceHandler(
- std::move(handler), this, plugin_service, intercepting_handler, request,
- fetch_request_context_type));
+ if (url_loader_options & network::mojom::kURLLoadOptionSniffMimeType) {
+ handler.reset(new MimeSniffingResourceHandler(
+ std::move(handler), this, plugin_service, intercepting_handler, request,
+ fetch_request_context_type));
+ }
// Add the pre mime sniffing throttles.
handler.reset(new ThrottlingResourceHandler(
@@ -1644,7 +1615,7 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest(
handler = AddStandardHandlers(
new_request.get(), resource_type, resource_context,
network::mojom::FetchRequestMode::kNoCORS,
- info.begin_params->request_context_type,
+ info.begin_params->request_context_type, url_loader_options,
appcache_handle_core ? appcache_handle_core->GetAppCacheService()
: nullptr,
-1, // child_id
@@ -1927,6 +1898,7 @@ net::URLRequest* ResourceDispatcherHostImpl::GetURLRequest(
}
// static
+// This is duplicated in services/network/network_service.cc.
bool ResourceDispatcherHostImpl::LoadInfoIsMoreInteresting(const LoadInfo& a,
const LoadInfo& b) {
// Set |*_uploading_size| to be the size of the corresponding upload body if
diff --git a/chromium/content/browser/loader/resource_dispatcher_host_impl.h b/chromium/content/browser/loader/resource_dispatcher_host_impl.h
index b8a81809fff..ec89329e361 100644
--- a/chromium/content/browser/loader/resource_dispatcher_host_impl.h
+++ b/chromium/content/browser/loader/resource_dispatcher_host_impl.h
@@ -29,10 +29,10 @@
#include "base/single_thread_task_runner.h"
#include "base/time/time.h"
#include "content/browser/blob_storage/chrome_blob_storage_context.h"
-#include "content/browser/loader/global_routing_id.h"
#include "content/browser/loader/resource_loader_delegate.h"
#include "content/common/content_export.h"
#include "content/public/browser/global_request_id.h"
+#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/resource_dispatcher_host.h"
#include "content/public/browser/resource_request_info.h"
#include "content/public/browser/stream_handle.h"
@@ -330,6 +330,7 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
private:
class ScheduledResourceRequestAdapter;
+ friend class NetworkServiceClient;
friend class ResourceDispatcherHostTest;
FRIEND_TEST_ALL_PREFIXES(ResourceDispatcherHostTest,
@@ -587,14 +588,6 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
network::mojom::URLLoaderRequest mojo_request,
network::mojom::URLLoaderClientPtr url_loader_client);
- // Creates either MojoAsyncResourceHandler or AsyncResourceHandler.
- std::unique_ptr<ResourceHandler> CreateBaseResourceHandler(
- net::URLRequest* request,
- uint32_t url_loader_options,
- network::mojom::URLLoaderRequest mojo_request,
- network::mojom::URLLoaderClientPtr url_loader_client,
- ResourceType resource_type);
-
// Wraps |handler| in the standard resource handlers for normal resource
// loading and navigation requests. This adds MimeTypeResourceHandler and
// ResourceThrottles.
@@ -604,6 +597,7 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
ResourceContext* resource_context,
network::mojom::FetchRequestMode fetch_request_mode,
RequestContextType fetch_request_context_type,
+ uint32_t url_loader_options,
AppCacheService* appcache_service,
int child_id,
int route_id,
diff --git a/chromium/content/browser/loader/resource_dispatcher_host_unittest.cc b/chromium/content/browser/loader/resource_dispatcher_host_unittest.cc
index d8d744e64ff..38053a77162 100644
--- a/chromium/content/browser/loader/resource_dispatcher_host_unittest.cc
+++ b/chromium/content/browser/loader/resource_dispatcher_host_unittest.cc
@@ -17,8 +17,8 @@
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
-#include "base/task_scheduler/post_task.h"
-#include "base/task_scheduler/task_traits.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
#include "base/test/scoped_feature_list.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/unguessable_token.h"
@@ -59,6 +59,7 @@
#include "content/test/test_navigation_url_loader_delegate.h"
#include "mojo/public/cpp/system/data_pipe_utils.h"
#include "net/base/chunked_upload_data_stream.h"
+#include "net/base/completion_once_callback.h"
#include "net/base/elements_upload_data_stream.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
@@ -106,6 +107,7 @@ static network::ResourceRequest CreateResourceRequest(const char* method,
request.resource_type = type;
request.appcache_host_id = kAppCacheNoHostId;
request.should_reset_appcache = false;
+ request.render_frame_id = 0;
request.is_main_frame = true;
request.transition_type = ui::PAGE_TRANSITION_LINK;
request.allow_download = true;
@@ -311,7 +313,7 @@ class URLRequestBigJob : public net::URLRequestSimpleJob {
int GetData(std::string* mime_type,
std::string* charset,
std::string* data,
- const net::CompletionCallback& callback) const override {
+ net::CompletionOnceCallback callback) const override {
*mime_type = "text/plain";
*charset = "UTF-8";
@@ -897,7 +899,7 @@ void ResourceDispatcherHostTest::MakeTestRequestWithRenderFrame(
request.render_frame_id = render_frame_id;
filter_->CreateLoaderAndStart(
std::move(loader_request), render_view_id, request_id,
- network::mojom::kURLLoadOptionNone, request, std::move(client),
+ network::mojom::kURLLoadOptionSniffMimeType, request, std::move(client),
net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
}
@@ -912,7 +914,7 @@ void ResourceDispatcherHostTest::MakeTestRequestWithResourceType(
network::ResourceRequest request = CreateResourceRequest("GET", type, url);
filter->CreateLoaderAndStart(
std::move(loader_request), render_view_id, request_id,
- network::mojom::kURLLoadOptionNone, request, std::move(client),
+ network::mojom::kURLLoadOptionSniffMimeType, request, std::move(client),
net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
}
@@ -1551,9 +1553,9 @@ TEST_F(ResourceDispatcherHostTest, TestProcessCancelDetachedTimesOut) {
// messages.
base::RunLoop run_loop;
base::OneShotTimer timer;
- timer.Start(
- FROM_HERE, base::TimeDelta::FromMilliseconds(210),
- base::Bind(&base::RunLoop::QuitWhenIdle, base::Unretained(&run_loop)));
+ timer.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(210),
+ base::BindOnce(&base::RunLoop::QuitWhenIdle,
+ base::Unretained(&run_loop)));
run_loop.Run();
// The prefetch should be cancelled by now.
@@ -2010,6 +2012,7 @@ TEST_F(ResourceDispatcherHostTest, MimeSniffed) {
client.RunUntilResponseReceived();
EXPECT_EQ("text/html", client.response_head().mime_type);
+ EXPECT_TRUE(client.response_head().did_mime_sniff);
}
// Tests that we don't sniff the mime type when the server provides one.
@@ -2031,6 +2034,7 @@ TEST_F(ResourceDispatcherHostTest, MimeNotSniffed) {
client.RunUntilResponseReceived();
EXPECT_EQ("image/jpeg", client.response_head().mime_type);
+ EXPECT_FALSE(client.response_head().did_mime_sniff);
}
// Tests that we don't sniff the mime type when there is no message body.
diff --git a/chromium/content/browser/loader/resource_hints_impl.cc b/chromium/content/browser/loader/resource_hints_impl.cc
index 3ebe0570196..bdb06548a3a 100644
--- a/chromium/content/browser/loader/resource_hints_impl.cc
+++ b/chromium/content/browser/loader/resource_hints_impl.cc
@@ -102,7 +102,7 @@ int PreresolveUrl(net::URLRequestContextGetter* getter,
resolve_info.set_is_speculative(true);
return resolver->Resolve(
resolve_info, net::IDLE, raw_addresses,
- base::Bind(&OnResolveComplete, base::Passed(&addresses), callback),
+ base::BindOnce(&OnResolveComplete, std::move(addresses), callback),
out_request, net::NetLogWithSource());
}
diff --git a/chromium/content/browser/loader/resource_loader.cc b/chromium/content/browser/loader/resource_loader.cc
index 2435233851b..ff351ba64cf 100644
--- a/chromium/content/browser/loader/resource_loader.cc
+++ b/chromium/content/browser/loader/resource_loader.cc
@@ -87,12 +87,6 @@ void PopulateResourceResponse(
response->head.network_accessed = response_info.network_accessed;
response->head.async_revalidation_requested =
response_info.async_revalidation_requested;
- const content::ResourceRequestInfo* request_info =
- content::ResourceRequestInfo::ForRequest(request);
- if (request_info) {
- response->head.previews_state =
- static_cast<int>(request_info->GetPreviewsState());
- }
if (info->ShouldReportRawHeaders()) {
response->head.raw_request_response_info =
network::BuildRawRequestResponseInfo(*request, raw_request_headers,
diff --git a/chromium/content/browser/loader/resource_request_info_impl.cc b/chromium/content/browser/loader/resource_request_info_impl.cc
index 3db8fd33813..7fe59fe5542 100644
--- a/chromium/content/browser/loader/resource_request_info_impl.cc
+++ b/chromium/content/browser/loader/resource_request_info_impl.cc
@@ -5,13 +5,13 @@
#include "content/browser/loader/resource_request_info_impl.h"
#include "content/browser/frame_host/frame_tree_node.h"
-#include "content/browser/loader/global_routing_id.h"
#include "content/browser/loader/resource_message_filter.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/net/url_request_service_worker_data.h"
#include "content/common/net/url_request_user_data.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/global_request_id.h"
+#include "content/public/browser/global_routing_id.h"
#include "content/public/common/browser_side_navigation_policy.h"
#include "content/public/common/process_type.h"
#include "net/url_request/url_request.h"
@@ -314,6 +314,10 @@ PreviewsState ResourceRequestInfoImpl::GetPreviewsState() const {
return previews_state_;
}
+void ResourceRequestInfoImpl::SetPreviewsState(PreviewsState previews_state) {
+ previews_state_ = previews_state;
+}
+
NavigationUIData* ResourceRequestInfoImpl::GetNavigationUIData() const {
return navigation_ui_data_.get();
}
diff --git a/chromium/content/browser/loader/resource_request_info_impl.h b/chromium/content/browser/loader/resource_request_info_impl.h
index 0bc8ea93804..ec89c14e24b 100644
--- a/chromium/content/browser/loader/resource_request_info_impl.h
+++ b/chromium/content/browser/loader/resource_request_info_impl.h
@@ -96,6 +96,7 @@ class ResourceRequestInfoImpl : public ResourceRequestInfo,
bool IsDownload() const override;
// Returns a bitmask of potentially several Previews optimizations.
PreviewsState GetPreviewsState() const override;
+ void SetPreviewsState(PreviewsState previews_state) override;
NavigationUIData* GetNavigationUIData() const override;
DevToolsStatus GetDevToolsStatus() const override;
void SetResourceRequestBlockedReason(
diff --git a/chromium/content/browser/loader/resource_requester_info.cc b/chromium/content/browser/loader/resource_requester_info.cc
index 862ff7ff379..f692a6fa920 100644
--- a/chromium/content/browser/loader/resource_requester_info.cc
+++ b/chromium/content/browser/loader/resource_requester_info.cc
@@ -4,6 +4,8 @@
#include "content/browser/loader/resource_requester_info.h"
+#include <utility>
+
#include "base/feature_list.h"
#include "base/logging.h"
#include "content/browser/appcache/chrome_appcache_service.h"
@@ -105,23 +107,16 @@ ResourceRequesterInfo::CreateForDownloadOrPageSave(int child_id) {
scoped_refptr<ResourceRequesterInfo>
ResourceRequesterInfo::CreateForNavigationPreload(
ResourceRequesterInfo* original_request_info) {
- GetContextsCallback get_contexts_callback =
- original_request_info->get_contexts_callback_;
- if (IsBrowserSideNavigationEnabled()) {
- DCHECK(original_request_info->IsBrowserSideNavigation());
- DCHECK(!get_contexts_callback);
- DCHECK(original_request_info->service_worker_context());
- // The requester info for browser side navigation doesn't have the
- // get_contexts_callback. So create the callback here which gets the
- // ResourceContext and the URLRequestContext form ServiceWorkerContext.
- get_contexts_callback =
- base::Bind(&GetContextsCallbackForNavigationPreload,
- scoped_refptr<ServiceWorkerContextWrapper>(
- original_request_info->service_worker_context()));
- } else {
- DCHECK(original_request_info->IsRenderer());
- DCHECK(get_contexts_callback);
- }
+ DCHECK(original_request_info->IsBrowserSideNavigation());
+ DCHECK(original_request_info->service_worker_context());
+ DCHECK(!original_request_info->get_contexts_callback_);
+ // The requester info for browser side navigation doesn't have the
+ // get_contexts_callback. So create the callback here which gets the
+ // ResourceContext and the URLRequestContext from ServiceWorkerContext.
+ auto get_contexts_callback =
+ base::BindRepeating(&GetContextsCallbackForNavigationPreload,
+ scoped_refptr<ServiceWorkerContextWrapper>(
+ original_request_info->service_worker_context()));
return scoped_refptr<ResourceRequesterInfo>(new ResourceRequesterInfo(
RequesterType::NAVIGATION_PRELOAD, ChildProcessHost::kInvalidUniqueID,
diff --git a/chromium/content/browser/loader/url_loader_factory_impl_unittest.cc b/chromium/content/browser/loader/url_loader_factory_impl_unittest.cc
index 9385955b5c5..168eed74072 100644
--- a/chromium/content/browser/loader/url_loader_factory_impl_unittest.cc
+++ b/chromium/content/browser/loader/url_loader_factory_impl_unittest.cc
@@ -149,7 +149,8 @@ TEST_P(URLLoaderFactoryImplTest, GetResponse) {
request.request_initiator = url::Origin::Create(request.url);
factory_->CreateLoaderAndStart(
mojo::MakeRequest(&loader), kRoutingId, kRequestId,
- network::mojom::kURLLoadOptionNone, request, client.CreateInterfacePtr(),
+ network::mojom::kURLLoadOptionSniffMimeType, request,
+ client.CreateInterfacePtr(),
net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
ASSERT_FALSE(client.has_received_response());
@@ -224,8 +225,9 @@ TEST_P(URLLoaderFactoryImplTest, GetFailedResponse) {
// Need to set same-site |request_initiator| for non main frame type request.
request.request_initiator = url::Origin::Create(request.url);
factory_->CreateLoaderAndStart(
- mojo::MakeRequest(&loader), 2, 1, network::mojom::kURLLoadOptionNone,
- request, client.CreateInterfacePtr(),
+ mojo::MakeRequest(&loader), 2, 1,
+ network::mojom::kURLLoadOptionSniffMimeType, request,
+ client.CreateInterfacePtr(),
net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
client.RunUntilComplete();
@@ -253,8 +255,9 @@ TEST_P(URLLoaderFactoryImplTest, GetFailedResponse2) {
// Need to set same-site |request_initiator| for non main frame type request.
request.request_initiator = url::Origin::Create(request.url);
factory_->CreateLoaderAndStart(
- mojo::MakeRequest(&loader), 2, 1, network::mojom::kURLLoadOptionNone,
- request, client.CreateInterfacePtr(),
+ mojo::MakeRequest(&loader), 2, 1,
+ network::mojom::kURLLoadOptionSniffMimeType, request,
+ client.CreateInterfacePtr(),
net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
client.RunUntilComplete();
@@ -281,8 +284,9 @@ TEST_P(URLLoaderFactoryImplTest, InvalidURL) {
request.request_initiator = url::Origin::Create(request.url);
ASSERT_FALSE(request.url.is_valid());
factory_->CreateLoaderAndStart(
- mojo::MakeRequest(&loader), 2, 1, network::mojom::kURLLoadOptionNone,
- request, client.CreateInterfacePtr(),
+ mojo::MakeRequest(&loader), 2, 1,
+ network::mojom::kURLLoadOptionSniffMimeType, request,
+ client.CreateInterfacePtr(),
net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
client.RunUntilComplete();
@@ -310,8 +314,9 @@ TEST_P(URLLoaderFactoryImplTest, ShouldNotRequestURL) {
// Need to set same-site |request_initiator| for non main frame type request.
request.request_initiator = url::Origin::Create(request.url);
factory_->CreateLoaderAndStart(
- mojo::MakeRequest(&loader), 2, 1, network::mojom::kURLLoadOptionNone,
- request, client.CreateInterfacePtr(),
+ mojo::MakeRequest(&loader), 2, 1,
+ network::mojom::kURLLoadOptionSniffMimeType, request,
+ client.CreateInterfacePtr(),
net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
client.RunUntilComplete();
@@ -343,7 +348,8 @@ TEST_P(URLLoaderFactoryImplTest, OnTransferSizeUpdated) {
request.report_raw_headers = true;
factory_->CreateLoaderAndStart(
mojo::MakeRequest(&loader), kRoutingId, kRequestId,
- network::mojom::kURLLoadOptionNone, request, client.CreateInterfacePtr(),
+ network::mojom::kURLLoadOptionSniffMimeType, request,
+ client.CreateInterfacePtr(),
net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
client.RunUntilComplete();
@@ -403,7 +409,8 @@ TEST_P(URLLoaderFactoryImplTest, CancelFromRenderer) {
request.request_initiator = url::Origin::Create(request.url);
factory_->CreateLoaderAndStart(
mojo::MakeRequest(&loader), kRoutingId, kRequestId,
- network::mojom::kURLLoadOptionNone, request, client.CreateInterfacePtr(),
+ network::mojom::kURLLoadOptionSniffMimeType, request,
+ client.CreateInterfacePtr(),
net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
base::RunLoop().RunUntilIdle();
diff --git a/chromium/content/browser/locks/lock_manager.cc b/chromium/content/browser/locks/lock_manager.cc
index a7768d01d7b..dc5384dbf53 100644
--- a/chromium/content/browser/locks/lock_manager.cc
+++ b/chromium/content/browser/locks/lock_manager.cc
@@ -287,7 +287,7 @@ void LockManager::RequestLock(const std::string& name,
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (wait == WaitMode::PREEMPT && mode != LockMode::EXCLUSIVE) {
- mojo::ReportBadMessage("Invalid option combinaton");
+ mojo::ReportBadMessage("Invalid option combination");
return;
}
diff --git a/chromium/content/browser/mach_broker_mac.mm b/chromium/content/browser/mach_broker_mac.mm
index 9b0da7da02f..21d1a5caf2f 100644
--- a/chromium/content/browser/mach_broker_mac.mm
+++ b/chromium/content/browser/mach_broker_mac.mm
@@ -8,6 +8,7 @@
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/logging.h"
+#include "content/common/content_constants_internal.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_data.h"
#include "content/public/browser/render_process_host.h"
@@ -15,15 +16,6 @@
namespace content {
-namespace {
-const char kBootstrapName[] = "rohitfork";
-}
-
-// static
-bool MachBroker::ChildSendTaskPortToParent() {
- return base::MachPortBroker::ChildSendTaskPortToParent(kBootstrapName);
-}
-
MachBroker* MachBroker::GetInstance() {
return base::Singleton<MachBroker,
base::LeakySingletonTraits<MachBroker>>::get();
@@ -88,10 +80,10 @@ std::string MachBroker::GetMachPortName() {
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
const bool is_child = command_line->HasSwitch(switches::kProcessType);
- return base::MachPortBroker::GetMachPortName(kBootstrapName, is_child);
+ return base::MachPortBroker::GetMachPortName(kMachBootstrapName, is_child);
}
-MachBroker::MachBroker() : initialized_(false), broker_(kBootstrapName) {
+MachBroker::MachBroker() : initialized_(false), broker_(kMachBootstrapName) {
broker_.AddObserver(this);
}
diff --git a/chromium/content/browser/mach_broker_mac_unittest.cc b/chromium/content/browser/mach_broker_mac_unittest.cc
index 261f500a563..329ae496ff4 100644
--- a/chromium/content/browser/mach_broker_mac_unittest.cc
+++ b/chromium/content/browser/mach_broker_mac_unittest.cc
@@ -5,10 +5,12 @@
#include "content/browser/mach_broker_mac.h"
#include "base/command_line.h"
+#include "base/mac/mach_port_broker.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/multiprocess_test.h"
#include "base/test/test_timeouts.h"
+#include "content/common/content_constants_internal.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"
@@ -77,7 +79,7 @@ class MachBrokerTest : public testing::Test,
};
MULTIPROCESS_TEST_MAIN(MachBrokerTestChild) {
- CHECK(MachBroker::ChildSendTaskPortToParent());
+ CHECK(base::MachPortBroker::ChildSendTaskPortToParent(kMachBootstrapName));
return 0;
}
diff --git a/chromium/content/browser/media/android/browser_media_player_manager.h b/chromium/content/browser/media/android/browser_media_player_manager.h
index aaaf4ccb74f..f942adc545b 100644
--- a/chromium/content/browser/media/android/browser_media_player_manager.h
+++ b/chromium/content/browser/media/android/browser_media_player_manager.h
@@ -24,9 +24,6 @@
struct MediaPlayerHostMsg_Initialize_Params;
namespace content {
-#if !defined(USE_AURA)
-class ContentViewCore;
-#endif
class RenderFrameHost;
class WebContents;
@@ -50,10 +47,6 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
// Returns nullptr if no factory was registered.
static BrowserMediaPlayerManager* Create(RenderFrameHost* rfh);
-#if !defined(USE_AURA)
- ContentViewCore* GetContentViewCore() const;
-#endif
-
~BrowserMediaPlayerManager() override;
// Called when browser player wants the renderer media element to seek.
@@ -164,12 +157,6 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
// will release its resources later.
ActivePlayerMap active_players_;
- // Player ID of the fullscreen media player.
- int fullscreen_player_id_;
-
- // Whether the fullscreen player has been Release()-d.
- bool fullscreen_player_is_released_;
-
WebContents* const web_contents_;
// Object for retrieving resources media players.
diff --git a/chromium/content/browser/media/android/media_player_renderer_web_contents_observer.cc b/chromium/content/browser/media/android/media_player_renderer_web_contents_observer.cc
index e5199578da9..82bd10ea55f 100644
--- a/chromium/content/browser/media/android/media_player_renderer_web_contents_observer.cc
+++ b/chromium/content/browser/media/android/media_player_renderer_web_contents_observer.cc
@@ -6,9 +6,6 @@
#include "content/browser/media/android/media_player_renderer.h"
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(
- content::MediaPlayerRendererWebContentsObserver);
-
namespace content {
MediaPlayerRendererWebContentsObserver::MediaPlayerRendererWebContentsObserver(
diff --git a/chromium/content/browser/media/android/media_resource_getter_impl.cc b/chromium/content/browser/media/android/media_resource_getter_impl.cc
index 2633945e003..74a94dfa97d 100644
--- a/chromium/content/browser/media/android/media_resource_getter_impl.cc
+++ b/chromium/content/browser/media/android/media_resource_getter_impl.cc
@@ -8,7 +8,7 @@
#include "base/macros.h"
#include "base/path_service.h"
#include "base/single_thread_task_runner.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/fileapi/browser_file_system_helper.h"
#include "content/browser/resource_context_impl.h"
diff --git a/chromium/content/browser/media/audio_input_stream_broker.cc b/chromium/content/browser/media/audio_input_stream_broker.cc
index b8cc22b65e5..a93d2ca90f1 100644
--- a/chromium/content/browser/media/audio_input_stream_broker.cc
+++ b/chromium/content/browser/media/audio_input_stream_broker.cc
@@ -35,6 +35,7 @@ AudioInputStreamBroker::AudioInputStreamBroker(
const media::AudioParameters& params,
uint32_t shared_memory_count,
bool enable_agc,
+ audio::mojom::AudioProcessingConfigPtr processing_config,
AudioStreamBroker::DeleterCallback deleter,
mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client)
: AudioStreamBroker(render_process_id, render_frame_id),
@@ -43,6 +44,7 @@ AudioInputStreamBroker::AudioInputStreamBroker(
shared_memory_count_(shared_memory_count),
enable_agc_(enable_agc),
deleter_(std::move(deleter)),
+ processing_config_(std::move(processing_config)),
renderer_factory_client_(std::move(renderer_factory_client)),
observer_binding_(this),
weak_ptr_factory_(this) {
@@ -159,6 +161,7 @@ void AudioInputStreamBroker::CreateStream(
log_component_id, render_process_id(), render_frame_id()),
device_id_, params_, shared_memory_count_, enable_agc_,
mojo::WrapReadOnlySharedMemoryRegion(std::move(key_press_count_buffer)),
+ std::move(processing_config_),
base::BindOnce(&AudioInputStreamBroker::StreamCreated,
weak_ptr_factory_.GetWeakPtr(), std::move(stream)));
}
diff --git a/chromium/content/browser/media/audio_input_stream_broker.h b/chromium/content/browser/media/audio_input_stream_broker.h
index 910453c4977..0ed31a6ee2f 100644
--- a/chromium/content/browser/media/audio_input_stream_broker.h
+++ b/chromium/content/browser/media/audio_input_stream_broker.h
@@ -15,6 +15,7 @@
#include "media/base/audio_parameters.h"
#include "media/mojo/interfaces/audio_input_stream.mojom.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "services/audio/public/mojom/audio_processing.mojom.h"
#include "services/audio/public/mojom/stream_factory.mojom.h"
namespace media {
@@ -36,6 +37,7 @@ class CONTENT_EXPORT AudioInputStreamBroker final
const media::AudioParameters& params,
uint32_t shared_memory_count,
bool enable_agc,
+ audio::mojom::AudioProcessingConfigPtr processing_config,
AudioStreamBroker::DeleterCallback deleter,
mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client);
@@ -68,6 +70,7 @@ class CONTENT_EXPORT AudioInputStreamBroker final
DeleterCallback deleter_;
+ audio::mojom::AudioProcessingConfigPtr processing_config_;
mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client_;
mojo::Binding<AudioInputStreamObserver> observer_binding_;
media::mojom::AudioInputStreamClientRequest client_request_;
diff --git a/chromium/content/browser/media/audio_input_stream_broker_unittest.cc b/chromium/content/browser/media/audio_input_stream_broker_unittest.cc
index 4adcdff9b3c..b68713ab8fc 100644
--- a/chromium/content/browser/media/audio_input_stream_broker_unittest.cc
+++ b/chromium/content/browser/media/audio_input_stream_broker_unittest.cc
@@ -105,16 +105,18 @@ class MockStreamFactory : public audio::FakeStreamFactory {
}
private:
- void CreateInputStream(media::mojom::AudioInputStreamRequest stream_request,
- media::mojom::AudioInputStreamClientPtr client,
- media::mojom::AudioInputStreamObserverPtr observer,
- media::mojom::AudioLogPtr log,
- const std::string& device_id,
- const media::AudioParameters& params,
- uint32_t shared_memory_count,
- bool enable_agc,
- mojo::ScopedSharedBufferHandle key_press_count_buffer,
- CreateInputStreamCallback created_callback) final {
+ void CreateInputStream(
+ media::mojom::AudioInputStreamRequest stream_request,
+ media::mojom::AudioInputStreamClientPtr client,
+ media::mojom::AudioInputStreamObserverPtr observer,
+ media::mojom::AudioLogPtr log,
+ const std::string& device_id,
+ const media::AudioParameters& params,
+ uint32_t shared_memory_count,
+ bool enable_agc,
+ mojo::ScopedSharedBufferHandle key_press_count_buffer,
+ audio::mojom::AudioProcessingConfigPtr processing_config,
+ CreateInputStreamCallback created_callback) final {
// No way to cleanly exit the test here in case of failure, so use CHECK.
CHECK(stream_request_data_);
EXPECT_EQ(stream_request_data_->device_id, device_id);
@@ -144,6 +146,7 @@ struct TestEnvironment {
TestParams(),
kShMemCount,
kEnableAgc,
+ nullptr,
deleter.Get(),
renderer_factory_client.MakePtr())) {}
@@ -166,7 +169,7 @@ TEST(AudioInputStreamBrokerTest, StoresProcessAndFrameId) {
AudioInputStreamBroker broker(
kRenderProcessId, kRenderFrameId, kDeviceId, TestParams(), kShMemCount,
- kEnableAgc, deleter.Get(), renderer_factory_client.MakePtr());
+ kEnableAgc, nullptr, deleter.Get(), renderer_factory_client.MakePtr());
EXPECT_EQ(kRenderProcessId, broker.render_process_id());
EXPECT_EQ(kRenderFrameId, broker.render_frame_id());
diff --git a/chromium/content/browser/media/audio_output_stream_broker.cc b/chromium/content/browser/media/audio_output_stream_broker.cc
index 0d2f3deafe2..1ddd0ad978d 100644
--- a/chromium/content/browser/media/audio_output_stream_broker.cc
+++ b/chromium/content/browser/media/audio_output_stream_broker.cc
@@ -23,12 +23,14 @@ AudioOutputStreamBroker::AudioOutputStreamBroker(
const std::string& output_device_id,
const media::AudioParameters& params,
const base::UnguessableToken& group_id,
+ const base::Optional<base::UnguessableToken>& processing_id,
DeleterCallback deleter,
media::mojom::AudioOutputStreamProviderClientPtr client)
: AudioStreamBroker(render_process_id, render_frame_id),
output_device_id_(output_device_id),
params_(params),
group_id_(group_id),
+ processing_id_(processing_id),
deleter_(std::move(deleter)),
client_(std::move(client)),
observer_(render_process_id, render_frame_id, stream_id),
@@ -94,7 +96,7 @@ void AudioOutputStreamBroker::CreateStream(
MediaInternals::GetInstance()->CreateMojoAudioLog(
media::AudioLogFactory::AudioComponent::AUDIO_OUTPUT_CONTROLLER,
log_component_id, render_process_id(), render_frame_id()),
- output_device_id_, params_, group_id_,
+ output_device_id_, params_, group_id_, processing_id_,
base::BindOnce(&AudioOutputStreamBroker::StreamCreated,
weak_ptr_factory_.GetWeakPtr(), std::move(stream)));
}
diff --git a/chromium/content/browser/media/audio_output_stream_broker.h b/chromium/content/browser/media/audio_output_stream_broker.h
index f2480aa0140..0f044081998 100644
--- a/chromium/content/browser/media/audio_output_stream_broker.h
+++ b/chromium/content/browser/media/audio_output_stream_broker.h
@@ -34,6 +34,7 @@ class CONTENT_EXPORT AudioOutputStreamBroker final : public AudioStreamBroker {
const std::string& output_device_id,
const media::AudioParameters& params,
const base::UnguessableToken& group_id,
+ const base::Optional<base::UnguessableToken>& processing_id,
DeleterCallback deleter,
media::mojom::AudioOutputStreamProviderClientPtr client);
@@ -54,6 +55,7 @@ class CONTENT_EXPORT AudioOutputStreamBroker final : public AudioStreamBroker {
const std::string output_device_id_;
const media::AudioParameters params_;
const base::UnguessableToken group_id_;
+ const base::Optional<base::UnguessableToken> processing_id_;
// Indicates that CreateStream has been called, but not StreamCreated.
bool awaiting_created_ = false;
diff --git a/chromium/content/browser/media/audio_output_stream_broker_unittest.cc b/chromium/content/browser/media/audio_output_stream_broker_unittest.cc
index 7a9d488e322..0d5ea4b4572 100644
--- a/chromium/content/browser/media/audio_output_stream_broker_unittest.cc
+++ b/chromium/content/browser/media/audio_output_stream_broker_unittest.cc
@@ -115,6 +115,7 @@ class MockStreamFactory : public audio::FakeStreamFactory {
const std::string& output_device_id,
const media::AudioParameters& params,
const base::UnguessableToken& group_id,
+ const base::Optional<base::UnguessableToken>& processing_id,
CreateOutputStreamCallback created_callback) final {
// No way to cleanly exit the test here in case of failure, so use CHECK.
CHECK(stream_request_data_);
@@ -143,6 +144,7 @@ struct TestEnvironment {
kDeviceId,
TestParams(),
group,
+ base::nullopt,
deleter.Get(),
provider_client.MakePtr())) {}
@@ -164,10 +166,10 @@ TEST(AudioOutputStreamBrokerTest, StoresProcessAndFrameId) {
MockDeleterCallback deleter;
StrictMock<MockAudioOutputStreamProviderClient> provider_client;
- AudioOutputStreamBroker broker(kRenderProcessId, kRenderFrameId, kStreamId,
- kDeviceId, TestParams(),
- base::UnguessableToken::Create(),
- deleter.Get(), provider_client.MakePtr());
+ AudioOutputStreamBroker broker(
+ kRenderProcessId, kRenderFrameId, kStreamId, kDeviceId, TestParams(),
+ base::UnguessableToken::Create(), base::nullopt, deleter.Get(),
+ provider_client.MakePtr());
EXPECT_EQ(kRenderProcessId, broker.render_process_id());
EXPECT_EQ(kRenderFrameId, broker.render_frame_id());
diff --git a/chromium/content/browser/media/audio_stream_broker.cc b/chromium/content/browser/media/audio_stream_broker.cc
index 6ff668c3b9e..9894ff13d7c 100644
--- a/chromium/content/browser/media/audio_stream_broker.cc
+++ b/chromium/content/browser/media/audio_stream_broker.cc
@@ -26,13 +26,14 @@ class AudioStreamBrokerFactoryImpl final : public AudioStreamBrokerFactory {
const media::AudioParameters& params,
uint32_t shared_memory_count,
bool enable_agc,
+ audio::mojom::AudioProcessingConfigPtr processing_config,
AudioStreamBroker::DeleterCallback deleter,
mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client)
final {
return std::make_unique<AudioInputStreamBroker>(
render_process_id, render_frame_id, device_id, params,
- shared_memory_count, enable_agc, std::move(deleter),
- std::move(renderer_factory_client));
+ shared_memory_count, enable_agc, std::move(processing_config),
+ std::move(deleter), std::move(renderer_factory_client));
}
std::unique_ptr<AudioStreamBroker> CreateAudioLoopbackStreamBroker(
@@ -58,11 +59,12 @@ class AudioStreamBrokerFactoryImpl final : public AudioStreamBrokerFactory {
const std::string& output_device_id,
const media::AudioParameters& params,
const base::UnguessableToken& group_id,
+ const base::Optional<base::UnguessableToken>& processing_id,
AudioStreamBroker::DeleterCallback deleter,
media::mojom::AudioOutputStreamProviderClientPtr client) final {
return std::make_unique<AudioOutputStreamBroker>(
render_process_id, render_frame_id, stream_id, output_device_id, params,
- group_id, std::move(deleter), std::move(client));
+ group_id, processing_id, std::move(deleter), std::move(client));
}
};
diff --git a/chromium/content/browser/media/audio_stream_broker.h b/chromium/content/browser/media/audio_stream_broker.h
index 40af0eac01b..e8deaa11bae 100644
--- a/chromium/content/browser/media/audio_stream_broker.h
+++ b/chromium/content/browser/media/audio_stream_broker.h
@@ -7,6 +7,7 @@
#include <memory>
#include <string>
+#include <utility>
#include "base/callback.h"
#include "base/macros.h"
@@ -15,6 +16,7 @@
#include "content/public/browser/web_contents_observer.h"
#include "media/mojo/interfaces/audio_input_stream.mojom.h"
#include "media/mojo/interfaces/audio_output_stream.mojom.h"
+#include "services/audio/public/mojom/audio_processing.mojom.h"
namespace audio {
namespace mojom {
@@ -103,6 +105,7 @@ class CONTENT_EXPORT AudioStreamBrokerFactory {
const media::AudioParameters& params,
uint32_t shared_memory_count,
bool enable_agc,
+ audio::mojom::AudioProcessingConfigPtr processing_config,
AudioStreamBroker::DeleterCallback deleter,
mojom::RendererAudioInputStreamFactoryClientPtr
renderer_factory_client) = 0;
@@ -125,6 +128,7 @@ class CONTENT_EXPORT AudioStreamBrokerFactory {
const std::string& output_device_id,
const media::AudioParameters& params,
const base::UnguessableToken& group_id,
+ const base::Optional<base::UnguessableToken>& processing_id,
AudioStreamBroker::DeleterCallback deleter,
media::mojom::AudioOutputStreamProviderClientPtr client) = 0;
diff --git a/chromium/content/browser/media/audio_stream_monitor.cc b/chromium/content/browser/media/audio_stream_monitor.cc
index 324f3105a21..17b5cb761c6 100644
--- a/chromium/content/browser/media/audio_stream_monitor.cc
+++ b/chromium/content/browser/media/audio_stream_monitor.cc
@@ -212,10 +212,9 @@ void AudioStreamMonitor::MaybeToggle() {
if (should_stop_timer) {
off_timer_.Stop();
} else if (!off_timer_.IsRunning()) {
- off_timer_.Start(
- FROM_HERE,
- off_time - now,
- base::Bind(&AudioStreamMonitor::MaybeToggle, base::Unretained(this)));
+ off_timer_.Start(FROM_HERE, off_time - now,
+ base::BindOnce(&AudioStreamMonitor::MaybeToggle,
+ base::Unretained(this)));
}
}
diff --git a/chromium/content/browser/media/capture/OWNERS b/chromium/content/browser/media/capture/OWNERS
index 31e7db3290b..e909a05d072 100644
--- a/chromium/content/browser/media/capture/OWNERS
+++ b/chromium/content/browser/media/capture/OWNERS
@@ -3,8 +3,8 @@ sergeyu@chromium.org
wez@chromium.org
# For WebRTC desktop capturer
-per-file desktop_capture_device.*=zijiehe@chromium.org
-per-file desktop_capture_device_unittest.cc=zijiehe@chromium.org
+per-file desktop*=braveyao@chromium.org
+per-file screen_capture*=braveyao@chromium.org
per-file image_capture*=mcasas@chromium.org
diff --git a/chromium/content/browser/media/capture/audio_mirroring_manager.cc b/chromium/content/browser/media/capture/audio_mirroring_manager.cc
index 1daaf6bf4d3..32544941366 100644
--- a/chromium/content/browser/media/capture/audio_mirroring_manager.cc
+++ b/chromium/content/browser/media/capture/audio_mirroring_manager.cc
@@ -36,12 +36,11 @@ void AudioMirroringManager::AddDiverter(
}
#endif
routes_.push_back(StreamRoutingState(
- SourceFrameRef(render_process_id, render_frame_id),
- diverter));
+ GlobalFrameRoutingId(render_process_id, render_frame_id), diverter));
// Query existing destinations to see whether to immediately start diverting
// the stream.
- std::set<SourceFrameRef> candidates;
+ std::set<GlobalFrameRoutingId> candidates;
candidates.insert(routes_.back().source_render_frame);
InitiateQueriesToFindNewDestination(nullptr, candidates);
}
@@ -79,7 +78,7 @@ void AudioMirroringManager::StartMirroring(MirroringDestination* destination) {
sessions_.push_back(destination);
}
- std::set<SourceFrameRef> candidates;
+ std::set<GlobalFrameRoutingId> candidates;
// Query the MirroringDestination to see which of the audio streams should be
// diverted.
@@ -103,7 +102,7 @@ void AudioMirroringManager::StopMirroring(MirroringDestination* destination) {
// Stop diverting each audio stream in the mirroring session being stopped.
// Each stopped stream becomes a candidate to be diverted to another
// destination.
- std::set<SourceFrameRef> redivert_candidates;
+ std::set<GlobalFrameRoutingId> redivert_candidates;
for (StreamRoutes::iterator it = routes_.begin(); it != routes_.end(); ++it) {
if (it->destination == destination) {
RouteDivertedFlow(&(*it), nullptr);
@@ -158,7 +157,7 @@ base::UnguessableToken AudioMirroringManager::ToGroupId(int render_process_id,
void AudioMirroringManager::InitiateQueriesToFindNewDestination(
MirroringDestination* old_destination,
- const std::set<SourceFrameRef>& candidates) {
+ const std::set<GlobalFrameRoutingId>& candidates) {
lock_.AssertAcquired();
for (Destinations::const_iterator it = sessions_.begin();
@@ -176,7 +175,7 @@ void AudioMirroringManager::InitiateQueriesToFindNewDestination(
void AudioMirroringManager::UpdateRoutesToDestination(
MirroringDestination* destination,
bool add_only,
- const std::set<SourceFrameRef>& matches,
+ const std::set<GlobalFrameRoutingId>& matches,
bool is_duplicate) {
base::AutoLock scoped_lock(lock_);
@@ -189,7 +188,7 @@ void AudioMirroringManager::UpdateRoutesToDestination(
void AudioMirroringManager::UpdateRoutesToDivertDestination(
MirroringDestination* destination,
bool add_only,
- const std::set<SourceFrameRef>& matches) {
+ const std::set<GlobalFrameRoutingId>& matches) {
lock_.AssertAcquired();
if (std::find(sessions_.begin(), sessions_.end(), destination) ==
@@ -202,7 +201,7 @@ void AudioMirroringManager::UpdateRoutesToDivertDestination(
// Start/stop diverting based on |matches|. Any stopped stream becomes a
// candidate to be diverted to another destination.
- std::set<SourceFrameRef> redivert_candidates;
+ std::set<GlobalFrameRoutingId> redivert_candidates;
for (StreamRoutes::iterator it = routes_.begin(); it != routes_.end(); ++it) {
if (matches.find(it->source_render_frame) != matches.end()) {
// Only change the route if the stream is not already being diverted.
@@ -223,7 +222,7 @@ void AudioMirroringManager::UpdateRoutesToDivertDestination(
void AudioMirroringManager::UpdateRoutesToDuplicateDestination(
MirroringDestination* destination,
bool add_only,
- const std::set<SourceFrameRef>& matches) {
+ const std::set<GlobalFrameRoutingId>& matches) {
lock_.AssertAcquired();
if (std::find(sessions_.begin(), sessions_.end(), destination) ==
@@ -267,18 +266,18 @@ void AudioMirroringManager::RouteDivertedFlow(
if (route->destination) {
DVLOG(1) << "Stop diverting render_process_id:render_frame_id="
- << route->source_render_frame.first << ':'
- << route->source_render_frame.second
+ << route->source_render_frame.child_id << ':'
+ << route->source_render_frame.frame_routing_id
<< " --> MirroringDestination@" << route->destination;
route->diverter->StopDiverting();
route->destination = nullptr;
}
if (new_destination) {
- DVLOG(1) << "Start diverting of render_process_id:render_frame_id="
- << route->source_render_frame.first << ':'
- << route->source_render_frame.second
- << " --> MirroringDestination@" << new_destination;
+ DVLOG(1) << "Start diverting of render_process_id:render_frame_id="
+ << route->source_render_frame.child_id << ':'
+ << route->source_render_frame.frame_routing_id
+ << " --> MirroringDestination@" << new_destination;
route->diverter->StartDiverting(
new_destination->AddInput(route->diverter->GetAudioParameters()));
route->destination = new_destination;
@@ -286,7 +285,7 @@ void AudioMirroringManager::RouteDivertedFlow(
}
AudioMirroringManager::StreamRoutingState::StreamRoutingState(
- const SourceFrameRef& source_frame,
+ const GlobalFrameRoutingId& source_frame,
Diverter* stream_diverter)
: source_render_frame(source_frame),
diverter(stream_diverter),
diff --git a/chromium/content/browser/media/capture/audio_mirroring_manager.h b/chromium/content/browser/media/capture/audio_mirroring_manager.h
index 67ee6fbdc3c..f2c7739a401 100644
--- a/chromium/content/browser/media/capture/audio_mirroring_manager.h
+++ b/chromium/content/browser/media/capture/audio_mirroring_manager.h
@@ -41,6 +41,7 @@
#include "base/synchronization/lock.h"
#include "base/unguessable_token.h"
#include "content/common/content_export.h"
+#include "content/public/browser/global_routing_id.h"
#include "media/audio/audio_source_diverter.h"
namespace media {
@@ -54,10 +55,6 @@ class CONTENT_EXPORT AudioMirroringManager {
// Interface for diverting audio data to an alternative AudioOutputStream.
typedef media::AudioSourceDiverter Diverter;
- // A SourceFrameRef is a RenderFrameHost identified by a <render_process_id,
- // render_frame_id> pair.
- typedef std::pair<int, int> SourceFrameRef;
-
// Interface to be implemented by audio mirroring destinations. See comments
// for StartMirroring() and StopMirroring() below.
class MirroringDestination {
@@ -70,11 +67,12 @@ class CONTENT_EXPORT AudioMirroringManager {
// access to a diverted audio flow versus 2) a duplicate copy of the audio
// flow. |results_callback| must be run on the same thread as the one that
// called QueryForMatches().
- typedef base::Callback<void(const std::set<SourceFrameRef>&, bool)>
+ typedef base::OnceCallback<void(const std::set<GlobalFrameRoutingId>&,
+ bool)>
MatchesCallback;
virtual void QueryForMatches(
- const std::set<SourceFrameRef>& candidates,
- const MatchesCallback& results_callback) = 0;
+ const std::set<GlobalFrameRoutingId>& candidates,
+ MatchesCallback results_callback) = 0;
// Create a consumer of audio data in the format specified by |params|, and
// connect it as an input to mirroring. This is used to provide
@@ -138,7 +136,7 @@ class CONTENT_EXPORT AudioMirroringManager {
struct StreamRoutingState {
// The source render frame associated with the audio stream.
- SourceFrameRef source_render_frame;
+ GlobalFrameRoutingId source_render_frame;
// The diverter for re-routing the audio stream.
Diverter* diverter;
@@ -152,7 +150,7 @@ class CONTENT_EXPORT AudioMirroringManager {
// StopDuplicating() is called to release them.
std::map<MirroringDestination*, media::AudioPushSink*> duplications;
- StreamRoutingState(const SourceFrameRef& source_frame,
+ StreamRoutingState(const GlobalFrameRoutingId& source_frame,
Diverter* stream_diverter);
StreamRoutingState(const StreamRoutingState& other);
~StreamRoutingState();
@@ -165,7 +163,7 @@ class CONTENT_EXPORT AudioMirroringManager {
// |candidates| to be diverted to.
void InitiateQueriesToFindNewDestination(
MirroringDestination* old_destination,
- const std::set<SourceFrameRef>& candidates);
+ const std::set<GlobalFrameRoutingId>& candidates);
// MirroringDestination query callback. |matches| contains all RenderFrame
// sources that will be diverted or duplicated to |destination|.
@@ -175,15 +173,16 @@ class CONTENT_EXPORT AudioMirroringManager {
// destination instead of diverted.
void UpdateRoutesToDestination(MirroringDestination* destination,
bool add_only,
- const std::set<SourceFrameRef>& matches,
+ const std::set<GlobalFrameRoutingId>& matches,
bool is_duplicate);
// |matches| contains all RenderFrame sources that will be diverted to
// |destination|. If |add_only| is false, then any Diverters currently routed
// to |destination| but not found in |matches| will be stopped.
- void UpdateRoutesToDivertDestination(MirroringDestination* destination,
- bool add_only,
- const std::set<SourceFrameRef>& matches);
+ void UpdateRoutesToDivertDestination(
+ MirroringDestination* destination,
+ bool add_only,
+ const std::set<GlobalFrameRoutingId>& matches);
// |matches| contains all RenderFrame sources that will be duplicated to
// |destination|. If |add_only| is false, then any Diverters currently
@@ -191,7 +190,7 @@ class CONTENT_EXPORT AudioMirroringManager {
void UpdateRoutesToDuplicateDestination(
MirroringDestination* destination,
bool add_only,
- const std::set<SourceFrameRef>& matches);
+ const std::set<GlobalFrameRoutingId>& matches);
// Starts diverting audio to the |new_destination|, if not NULL. Otherwise,
// stops diverting audio.
diff --git a/chromium/content/browser/media/capture/audio_mirroring_manager_unittest.cc b/chromium/content/browser/media/capture/audio_mirroring_manager_unittest.cc
index a485e46bf68..d128405139c 100644
--- a/chromium/content/browser/media/capture/audio_mirroring_manager_unittest.cc
+++ b/chromium/content/browser/media/capture/audio_mirroring_manager_unittest.cc
@@ -5,6 +5,7 @@
#include "content/browser/media/capture/audio_mirroring_manager.h"
#include <map>
+#include <memory>
#include <utility>
#include "base/bind.h"
@@ -44,8 +45,6 @@ class MockDiverter : public AudioMirroringManager::Diverter {
class MockMirroringDestination
: public AudioMirroringManager::MirroringDestination {
public:
- typedef AudioMirroringManager::SourceFrameRef SourceFrameRef;
-
MockMirroringDestination(int render_process_id,
int render_frame_id,
bool is_duplication)
@@ -54,27 +53,34 @@ class MockMirroringDestination
query_count_(0),
is_duplication_(is_duplication) {}
- MOCK_METHOD2(QueryForMatches,
- void(const std::set<SourceFrameRef>& candidates,
- const MatchesCallback& results_callback));
+ void QueryForMatches(const std::set<GlobalFrameRoutingId>& candidates,
+ MatchesCallback results_callback) override {
+ // The indirection is needed, because gmock has trouble with move-only
+ // parameters (like |results_callback|).
+ MockedQueryForMatches(candidates, &results_callback);
+ }
+ MOCK_METHOD2(MockedQueryForMatches,
+ void(const std::set<GlobalFrameRoutingId>& candidates,
+ MatchesCallback* results_callback));
+
MOCK_METHOD1(AddInput,
media::AudioOutputStream*(const media::AudioParameters& params));
MOCK_METHOD1(AddPushInput,
media::AudioPushSink*(const media::AudioParameters& params));
- void SimulateQuery(const std::set<SourceFrameRef>& candidates,
- const MatchesCallback& results_callback) {
+ void SimulateQuery(const std::set<GlobalFrameRoutingId>& candidates,
+ MatchesCallback* results_callback) {
++query_count_;
- std::set<SourceFrameRef> result;
- if (candidates.find(SourceFrameRef(render_process_id_, render_frame_id_)) !=
- candidates.end()) {
- result.insert(SourceFrameRef(render_process_id_, render_frame_id_));
+ std::set<GlobalFrameRoutingId> result;
+ if (candidates.find(GlobalFrameRoutingId(
+ render_process_id_, render_frame_id_)) != candidates.end()) {
+ result.insert(GlobalFrameRoutingId(render_process_id_, render_frame_id_));
}
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(results_callback, std::move(result), is_duplication_));
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::BindOnce(std::move(*results_callback),
+ std::move(result), is_duplication_));
}
media::AudioOutputStream* SimulateAddInput(
@@ -157,9 +163,9 @@ class AudioMirroringManagerTest : public testing::Test {
void StartMirroringTo(const std::unique_ptr<MockMirroringDestination>& dest,
int expected_inputs_added,
int expected_push_inputs_added) {
- EXPECT_CALL(*dest, QueryForMatches(_, _))
- .WillRepeatedly(Invoke(dest.get(),
- &MockMirroringDestination::SimulateQuery));
+ EXPECT_CALL(*dest, MockedQueryForMatches(_, _))
+ .WillRepeatedly(
+ Invoke(dest.get(), &MockMirroringDestination::SimulateQuery));
if (expected_inputs_added > 0) {
EXPECT_CALL(*dest, AddInput(Ref(params_)))
.Times(expected_inputs_added)
diff --git a/chromium/content/browser/media/capture/aura_window_video_capture_device.cc b/chromium/content/browser/media/capture/aura_window_video_capture_device.cc
index 93160c08dcf..72b973e16a8 100644
--- a/chromium/content/browser/media/capture/aura_window_video_capture_device.cc
+++ b/chromium/content/browser/media/capture/aura_window_video_capture_device.cc
@@ -4,12 +4,15 @@
#include "content/browser/media/capture/aura_window_video_capture_device.h"
+#include <utility>
+
#include "base/bind.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "content/browser/media/capture/mouse_cursor_overlay_controller.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/desktop_media_id.h"
#include "media/base/bind_to_current_loop.h"
@@ -31,14 +34,14 @@ class AuraWindowVideoCaptureDevice::WindowTracker
AuraWindowVideoCaptureDevice::WindowTracker> {
public:
WindowTracker(base::WeakPtr<AuraWindowVideoCaptureDevice> device,
- CursorRenderer* cursor_renderer,
+ MouseCursorOverlayController* cursor_controller,
const DesktopMediaID& source_id)
: device_(std::move(device)),
device_task_runner_(base::ThreadTaskRunnerHandle::Get()),
- cursor_renderer_(cursor_renderer),
+ cursor_controller_(cursor_controller),
target_type_(source_id.type) {
DCHECK(device_task_runner_);
- DCHECK(cursor_renderer_);
+ DCHECK(cursor_controller_);
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
@@ -86,10 +89,11 @@ class AuraWindowVideoCaptureDevice::WindowTracker
FROM_HERE,
base::BindOnce(&FrameSinkVideoCaptureDevice::OnTargetChanged, device_,
target_window_->GetFrameSinkId()));
- // Note: CursorRenderer runs on the UI thread. It's also important that
- // SetTargetView() be called in the current stack while |target_window_|
- // is known to be a valid pointer. http://crbug.com/818679
- cursor_renderer_->SetTargetView(target_window_);
+ // Note: The MouseCursorOverlayController runs on the UI thread. It's also
+ // important that SetTargetView() be called in the current stack while
+ // |target_window_| is known to be a valid pointer.
+ // http://crbug.com/818679
+ cursor_controller_->SetTargetView(target_window_);
} else {
device_task_runner_->PostTask(
FROM_HERE,
@@ -110,7 +114,7 @@ class AuraWindowVideoCaptureDevice::WindowTracker
FROM_HERE,
base::BindOnce(&FrameSinkVideoCaptureDevice::OnTargetPermanentlyLost,
device_));
- cursor_renderer_->SetTargetView(nullptr);
+ cursor_controller_->SetTargetView(gfx::NativeView());
}
private:
@@ -120,8 +124,8 @@ class AuraWindowVideoCaptureDevice::WindowTracker
// Owned by FrameSinkVideoCaptureDevice. This will be valid for the life of
// WindowTracker because the WindowTracker deleter task will be posted to the
- // UI thread before the CursorRenderer deleter task.
- CursorRenderer* const cursor_renderer_;
+ // UI thread before the MouseCursorOverlayController deleter task.
+ MouseCursorOverlayController* const cursor_controller_;
const DesktopMediaID::Type target_type_;
@@ -132,7 +136,8 @@ class AuraWindowVideoCaptureDevice::WindowTracker
AuraWindowVideoCaptureDevice::AuraWindowVideoCaptureDevice(
const DesktopMediaID& source_id)
- : tracker_(new WindowTracker(AsWeakPtr(), cursor_renderer(), source_id)) {}
+ : tracker_(new WindowTracker(AsWeakPtr(), cursor_controller(), source_id)) {
+}
AuraWindowVideoCaptureDevice::~AuraWindowVideoCaptureDevice() = default;
diff --git a/chromium/content/browser/media/capture/cursor_renderer.cc b/chromium/content/browser/media/capture/cursor_renderer.cc
deleted file mode 100644
index 6434a15a422..00000000000
--- a/chromium/content/browser/media/capture/cursor_renderer.cc
+++ /dev/null
@@ -1,353 +0,0 @@
-// 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 "content/browser/media/capture/cursor_renderer.h"
-
-#include <algorithm>
-#include <cmath>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/logging.h"
-#include "base/numerics/safe_conversions.h"
-#include "skia/ext/image_operations.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace content {
-
-namespace {
-
-inline int clip_byte(int x) {
- return std::max(0, std::min(x, 255));
-}
-
-inline int alpha_blend(int alpha, int src, int dst) {
- return (src * alpha + dst * (255 - alpha)) / 255;
-}
-
-} // namespace
-
-CursorRenderer::CursorRenderer(CursorDisplaySetting cursor_display_setting)
- : cursor_display_setting_(cursor_display_setting),
- cursor_(gfx::NativeCursor()),
- update_scaled_cursor_bitmap_(false),
- mouse_move_behavior_atomic_(NOT_MOVING),
- weak_factory_(this) {
- // CursorRenderer can be constructed on any thread, but thereafter must be
- // used according to class-level comments.
- DETACH_FROM_SEQUENCE(ui_sequence_checker_);
- DETACH_FROM_SEQUENCE(render_sequence_checker_);
-}
-
-CursorRenderer::~CursorRenderer() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
-}
-
-base::WeakPtr<CursorRenderer> CursorRenderer::GetWeakPtr() {
- return weak_factory_.GetWeakPtr();
-}
-
-void CursorRenderer::SnapshotCursorState() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
-
- base::AutoLock auto_lock(lock_);
-
- // In CURSOR_DISPLAYED_ON_MOUSE_MOVEMENT mode, if the user hasn't recently
- // moved nor clicked the mouse, do not render the mouse cursor.
- if (cursor_display_setting_ == CURSOR_DISPLAYED_ON_MOUSE_MOVEMENT &&
- mouse_move_behavior() != RECENTLY_MOVED_OR_CLICKED) {
- view_size_ = gfx::Size();
- return;
- }
-
- // Do not render the mouse cursor if the view is not in the foreground window
- // on the user's desktop.
- if (!IsCapturedViewActive()) {
- view_size_ = gfx::Size();
- return;
- }
-
- // Collect current view size and mouse cursor state.
- view_size_ = GetCapturedViewSize();
- if (view_size_.IsEmpty()) {
- return;
- }
- cursor_position_ = GetCursorPositionInView();
- if (!gfx::Rect(view_size_).Contains(cursor_position_)) {
- view_size_ = gfx::Size();
- return;
- }
- const gfx::NativeCursor cursor = GetLastKnownCursor();
- if (cursor != cursor_ || !cursor_image_.readyToDraw()) {
- cursor_ = cursor;
- cursor_image_ = GetLastKnownCursorImage(&cursor_hot_point_);
- // Force RenderOnVideoFrame() to re-generate its scaled cursor bitmap.
- update_scaled_cursor_bitmap_ = true;
- }
-}
-
-bool CursorRenderer::RenderOnVideoFrame(media::VideoFrame* frame,
- const gfx::Rect& region_in_frame,
- CursorRendererUndoer* undoer) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(render_sequence_checker_);
- DCHECK(frame);
-
- // Grab the |lock_| to read from shared mouse cursor state, and maybe
- // re-render the scaled cursor bitmap.
- gfx::Size view_size;
- gfx::Point cursor_position;
- {
- base::AutoLock auto_lock(lock_);
-
- if (view_size_.IsEmpty() || !cursor_image_.readyToDraw()) {
- return false;
- }
-
- view_size = view_size_;
-
- cursor_position = cursor_position_;
- cursor_position.Offset(-cursor_hot_point_.x(), -cursor_hot_point_.y());
- // |cursor_position| is further modified, below; but the |lock_| need not be
- // held for that.
-
- const int scaled_width =
- base::saturated_cast<int>((static_cast<int64_t>(cursor_image_.width()) *
- region_in_frame.width()) /
- view_size.width());
- const int scaled_height = base::saturated_cast<int>(
- (static_cast<int64_t>(cursor_image_.height()) *
- region_in_frame.height()) /
- view_size.height());
- if (scaled_width <= 0 || scaled_height <= 0) {
- return false;
- }
- if (update_scaled_cursor_bitmap_) {
- scaled_cursor_bitmap_ = SkBitmap();
- update_scaled_cursor_bitmap_ = false;
- }
- if (!scaled_cursor_bitmap_.readyToDraw() ||
- scaled_width != scaled_cursor_bitmap_.width() ||
- scaled_height != scaled_cursor_bitmap_.height()) {
- scaled_cursor_bitmap_ = skia::ImageOperations::Resize(
- cursor_image_, skia::ImageOperations::RESIZE_BEST, scaled_width,
- scaled_height);
- }
- }
-
- // Translate cursor position from view coordinates to video frame content
- // coordinates.
- cursor_position.set_x(base::saturated_cast<int>(
- region_in_frame.x() +
- (static_cast<int64_t>(cursor_position.x()) * region_in_frame.width()) /
- view_size.width()));
- cursor_position.set_y(base::saturated_cast<int>(
- region_in_frame.y() +
- (static_cast<int64_t>(cursor_position.y()) * region_in_frame.height()) /
- view_size.height()));
-
- // Determine the region of the video frame to be modified.
- gfx::Rect rect = gfx::IntersectRects(
- gfx::Rect(cursor_position, gfx::Size(scaled_cursor_bitmap_.width(),
- scaled_cursor_bitmap_.height())),
- frame->visible_rect());
- if (rect.IsEmpty())
- return false;
-
- if (undoer)
- undoer->TakeSnapshot(*frame, rect);
-
- // Render the cursor in the video frame. This loop also performs a simple
- // RGB→YUV color space conversion, with alpha-blended compositing.
- for (int y = rect.y(); y < rect.bottom(); ++y) {
- int cursor_y = y - cursor_position.y();
- uint8_t* yplane = frame->visible_data(media::VideoFrame::kYPlane) +
- y * frame->stride(media::VideoFrame::kYPlane);
- uint8_t* uplane = frame->visible_data(media::VideoFrame::kUPlane) +
- (y / 2) * frame->stride(media::VideoFrame::kUPlane);
- uint8_t* vplane = frame->visible_data(media::VideoFrame::kVPlane) +
- (y / 2) * frame->stride(media::VideoFrame::kVPlane);
- for (int x = rect.x(); x < rect.right(); ++x) {
- int cursor_x = x - cursor_position.x();
- SkColor color = scaled_cursor_bitmap_.getColor(cursor_x, cursor_y);
- int alpha = SkColorGetA(color);
- int color_r = SkColorGetR(color);
- int color_g = SkColorGetG(color);
- int color_b = SkColorGetB(color);
- int color_y = clip_byte(
- ((color_r * 66 + color_g * 129 + color_b * 25 + 128) >> 8) + 16);
- yplane[x] = alpha_blend(alpha, color_y, yplane[x]);
-
- // Only sample U and V at even coordinates.
- // TODO(miu): This isn't right. We should be blending four cursor pixels
- // into each U or V output pixel.
- if ((x % 2 == 0) && (y % 2 == 0)) {
- int color_u = clip_byte(
- ((color_r * -38 + color_g * -74 + color_b * 112 + 128) >> 8) + 128);
- int color_v = clip_byte(
- ((color_r * 112 + color_g * -94 + color_b * -18 + 128) >> 8) + 128);
- uplane[x / 2] = alpha_blend(alpha, color_u, uplane[x / 2]);
- vplane[x / 2] = alpha_blend(alpha, color_v, vplane[x / 2]);
- }
- }
- }
-
- return true;
-}
-
-void CursorRenderer::SetNeedsRedrawCallback(base::RepeatingClosure callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
-
- needs_redraw_callback_ = std::move(callback);
-}
-
-bool CursorRenderer::IsUserInteractingWithView() const {
- return mouse_move_behavior() == RECENTLY_MOVED_OR_CLICKED;
-}
-
-void CursorRenderer::OnMouseMoved(const gfx::Point& location) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
-
- switch (mouse_move_behavior()) {
- case NOT_MOVING:
- set_mouse_move_behavior(STARTING_TO_MOVE);
- mouse_move_start_location_ = location;
- mouse_activity_ended_timer_.Start(
- FROM_HERE, base::TimeDelta::FromSeconds(IDLE_TIMEOUT_SECONDS),
- base::BindRepeating(&CursorRenderer::OnMouseHasGoneIdle,
- base::Unretained(this)));
- break;
- case STARTING_TO_MOVE:
- if (std::abs(location.x() - mouse_move_start_location_.x()) >
- MIN_MOVEMENT_PIXELS ||
- std::abs(location.y() - mouse_move_start_location_.y()) >
- MIN_MOVEMENT_PIXELS) {
- set_mouse_move_behavior(RECENTLY_MOVED_OR_CLICKED);
- mouse_activity_ended_timer_.Reset();
- }
- break;
- case RECENTLY_MOVED_OR_CLICKED:
- mouse_activity_ended_timer_.Reset();
- break;
- }
-
- // If there is sufficient mouse activity, or the cursor should always be
- // displayed, snapshot the cursor state and run the redraw callback to show it
- // at its new location in the video.
- if (mouse_move_behavior() == RECENTLY_MOVED_OR_CLICKED ||
- cursor_display_setting_ == CURSOR_DISPLAYED_ALWAYS) {
- SnapshotCursorState();
- if (!needs_redraw_callback_.is_null()) {
- needs_redraw_callback_.Run();
- }
- }
-}
-
-void CursorRenderer::OnMouseClicked(const gfx::Point& location) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
-
- if (mouse_activity_ended_timer_.IsRunning()) {
- mouse_activity_ended_timer_.Reset();
- } else {
- mouse_activity_ended_timer_.Start(
- FROM_HERE, base::TimeDelta::FromSeconds(IDLE_TIMEOUT_SECONDS),
- base::BindRepeating(&CursorRenderer::OnMouseHasGoneIdle,
- base::Unretained(this)));
- }
- set_mouse_move_behavior(RECENTLY_MOVED_OR_CLICKED);
-
- // Regardless of the |cursor_display_setting_|, snapshot the cursor and run
- // the redraw callback to show it at its current location in the video.
- SnapshotCursorState();
- if (!needs_redraw_callback_.is_null()) {
- needs_redraw_callback_.Run();
- }
-}
-
-void CursorRenderer::OnMouseHasGoneIdle() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
-
- set_mouse_move_behavior(NOT_MOVING);
-
- // The timer has fired to indicate no further mouse activity. It's a good idea
- // to snapshot the cursor and run the redraw callback to ensure it is being
- // presented in the video correctly, whether showing its final location or to
- // remove it from the video.
- SnapshotCursorState();
- if (!needs_redraw_callback_.is_null()) {
- needs_redraw_callback_.Run();
- }
-}
-
-CursorRendererUndoer::CursorRendererUndoer() = default;
-
-CursorRendererUndoer::~CursorRendererUndoer() = default;
-
-CursorRendererUndoer::CursorRendererUndoer(
- CursorRendererUndoer&& other) noexcept = default;
-
-CursorRendererUndoer& CursorRendererUndoer::operator=(
- CursorRendererUndoer&& other) noexcept = default;
-
-namespace {
-
-// Returns the rect of pixels in a Chroma plane affected by the given |rect| in
-// the Luma plane.
-gfx::Rect ToEncompassingChromaRect(const gfx::Rect& rect) {
- const int left = rect.x() / 2;
- const int top = rect.y() / 2;
- const int right = (rect.right() + 1) / 2;
- const int bottom = (rect.bottom() + 1) / 2;
- return gfx::Rect(left, top, right - left, bottom - top);
-}
-
-constexpr size_t kYuvPlanes[] = {media::VideoFrame::kYPlane,
- media::VideoFrame::kUPlane,
- media::VideoFrame::kVPlane};
-
-} // namespace
-
-void CursorRendererUndoer::TakeSnapshot(const media::VideoFrame& frame,
- const gfx::Rect& rect) {
- DCHECK(frame.visible_rect().Contains(rect));
-
- rect_ = rect;
- const gfx::Rect chroma_rect = ToEncompassingChromaRect(rect_);
- snapshot_.resize(rect_.size().GetArea() + 2 * chroma_rect.size().GetArea());
-
- uint8_t* dst = snapshot_.data();
- for (auto plane : kYuvPlanes) {
- const gfx::Rect& plane_rect =
- (plane == media::VideoFrame::kYPlane) ? rect_ : chroma_rect;
- const int stride = frame.stride(plane);
- const uint8_t* src =
- frame.visible_data(plane) + plane_rect.y() * stride + plane_rect.x();
- for (int row = 0; row < plane_rect.height(); ++row) {
- memcpy(dst, src, plane_rect.width());
- src += stride;
- dst += plane_rect.width();
- }
- }
-}
-
-void CursorRendererUndoer::Undo(media::VideoFrame* frame) const {
- DCHECK(frame->visible_rect().Contains(rect_));
-
- const gfx::Rect chroma_rect = ToEncompassingChromaRect(rect_);
-
- const uint8_t* src = snapshot_.data();
- for (auto plane : kYuvPlanes) {
- const gfx::Rect& plane_rect =
- (plane == media::VideoFrame::kYPlane) ? rect_ : chroma_rect;
- const int stride = frame->stride(plane);
- uint8_t* dst =
- frame->visible_data(plane) + plane_rect.y() * stride + plane_rect.x();
- for (int row = 0; row < plane_rect.height(); ++row) {
- memcpy(dst, src, plane_rect.width());
- src += plane_rect.width();
- dst += stride;
- }
- }
-}
-
-} // namespace content
diff --git a/chromium/content/browser/media/capture/cursor_renderer.h b/chromium/content/browser/media/capture/cursor_renderer.h
deleted file mode 100644
index 64409bd5b01..00000000000
--- a/chromium/content/browser/media/capture/cursor_renderer.h
+++ /dev/null
@@ -1,204 +0,0 @@
-// Copyright (c) 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 CONTENT_BROWSER_MEDIA_CAPTURE_CURSOR_RENDERER_H_
-#define CONTENT_BROWSER_MEDIA_CAPTURE_CURSOR_RENDERER_H_
-
-#include <atomic>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/sequence_checker.h"
-#include "base/synchronization/lock.h"
-#include "base/timer/timer.h"
-#include "content/common/content_export.h"
-#include "media/base/video_frame.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/cursor/cursor.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/native_widget_types.h"
-
-namespace content {
-
-class CursorRendererUndoer;
-
-// CursorRenderer is an abstract base class that handles all the
-// non-platform-specific common cursor rendering functionality. In order to
-// track the cursor, the platform-specific implementation will listen to
-// mouse events and this base class will process them.
-//
-// All parts of this class are meant to run on the UI BrowserThread, except for
-// RenderOnVideoFrame() and IsUserInteractingWithView(), which may be called
-// from any thread. It is up to the client code to ensure the CursorRenderer's
-// lifetime while in use across multiple threads.
-class CONTENT_EXPORT CursorRenderer {
- public:
- // Setting to control cursor display based on either mouse movement or always
- // forced to be enabled.
- enum CursorDisplaySetting {
- CURSOR_DISPLAYED_ALWAYS,
- CURSOR_DISPLAYED_ON_MOUSE_MOVEMENT,
- };
-
- static std::unique_ptr<CursorRenderer> Create(CursorDisplaySetting display);
-
- virtual ~CursorRenderer();
-
- // Sets a new target view to monitor for mouse cursor updates.
- virtual void SetTargetView(gfx::NativeView view) = 0;
-
- // Renders cursor on the given video frame within the content region,
- // returning true if |frame| was modified. |undoer| is optional: If provided,
- // it will be updated with state necessary for later undoing the cursor
- // rendering.
- bool RenderOnVideoFrame(media::VideoFrame* frame,
- const gfx::Rect& region_in_frame,
- CursorRendererUndoer* undoer);
-
- // Sets a callback that will be run whenever RenderOnVideoFrame() should be
- // called soon, to update the mouse cursor location or image in the video.
- void SetNeedsRedrawCallback(base::RepeatingClosure callback);
-
- // Returns true if the user has recently interacted with the view.
- bool IsUserInteractingWithView() const;
-
- // Returns a weak pointer.
- base::WeakPtr<CursorRenderer> GetWeakPtr();
-
- protected:
- enum {
- // Minium movement before cursor has been considered intentionally moved by
- // the user.
- MIN_MOVEMENT_PIXELS = 15,
- // Amount of time to elapse with no mouse activity before the cursor should
- // stop showing in the video. Does not apply to CURSOR_DISPLAYED_ALWAYS
- // mode, of course.
- IDLE_TIMEOUT_SECONDS = 2
- };
-
- explicit CursorRenderer(CursorDisplaySetting display);
-
- // Returns true if the captured view is a part of an active application
- // window.
- virtual bool IsCapturedViewActive() = 0;
-
- // Returns the size of the captured view (view coordinates).
- virtual gfx::Size GetCapturedViewSize() = 0;
-
- // Returns the cursor's position within the captured view (view coordinates).
- virtual gfx::Point GetCursorPositionInView() = 0;
-
- // Returns the last-known mouse cursor.
- virtual gfx::NativeCursor GetLastKnownCursor() = 0;
-
- // Returns the image of the last-known mouse cursor and its hotspot.
- virtual SkBitmap GetLastKnownCursorImage(gfx::Point* hot_point) = 0;
-
- // Called by subclasses to report mouse events within the captured view.
- void OnMouseMoved(const gfx::Point& location);
- void OnMouseClicked(const gfx::Point& location);
-
- // Called by the |mouse_activity_ended_timer_| once no mouse events have
- // occurred for IDLE_TIMEOUT_SECONDS. Also, called by subclasses when changing
- // the target view.
- void OnMouseHasGoneIdle();
-
- private:
- friend class CursorRendererAuraTest;
- friend class CursorRendererMacTest;
-
- enum MouseMoveBehavior {
- NOT_MOVING, // Mouse has not moved recently.
- STARTING_TO_MOVE, // Mouse has moved, but not significantly.
- RECENTLY_MOVED_OR_CLICKED, // Sufficient mouse activity present.
- };
-
- // Accessors for |mouse_move_behavior_atomic_|. See comments below.
- MouseMoveBehavior mouse_move_behavior() const {
- return mouse_move_behavior_atomic_.load(std::memory_order_relaxed);
- }
- void set_mouse_move_behavior(MouseMoveBehavior behavior) {
- mouse_move_behavior_atomic_.store(behavior, std::memory_order_relaxed);
- }
-
- // Takes a snapshot of the current mouse cursor state, for use by
- // RenderOnVideoFrame().
- void SnapshotCursorState();
-
- // Controls whether cursor is displayed based on active mouse movement.
- const CursorDisplaySetting cursor_display_setting_;
-
- // Protects members shared by RenderOnVideoFrame() and the rest of the class.
- base::Lock lock_;
-
- // These are updated by SnapshotCursorState(), then later read within
- // RenderOnVideoFrame(). Access is protected by |lock_|.
- gfx::Size view_size_; // Empty means "do not show mouse cursor."
- gfx::Point cursor_position_;
- gfx::NativeCursor cursor_;
- gfx::Point cursor_hot_point_;
- SkBitmap cursor_image_;
- // Flag set to invalidate |scaled_cursor_bitmap_|.
- bool update_scaled_cursor_bitmap_;
-
- // A cache of the current scaled cursor bitmap. This is only accessed by the
- // thread calling RenderOnVideoFrame().
- SkBitmap scaled_cursor_bitmap_;
-
- // Updated in the mouse event handlers and used to decide whether the user is
- // interacting with the view and whether to run the |needs_redraw_callback_|.
- // These do not need to be protected by |lock_| since they are only accessed
- // on the UI BrowserThread.
- gfx::Point mouse_move_start_location_;
- base::OneShotTimer mouse_activity_ended_timer_;
-
- // Updated in the mouse event handlers (on the UI BrowserThread) and read from
- // by IsUserInteractingWithView() (on any thread). This is not protected by
- // |lock_| since strict memory ordering semantics are not necessary, just
- // atomicity between threads. All code should use the accessors to read or set
- // this value.
- std::atomic<MouseMoveBehavior> mouse_move_behavior_atomic_;
-
- // Run whenever the mouse cursor would be rendered differently than when it
- // was rendered in the last video frame.
- base::RepeatingClosure needs_redraw_callback_;
-
- // Everything except the constructor and RenderOnVideoFrame() must be called
- // on the UI BrowserThread.
- SEQUENCE_CHECKER(ui_sequence_checker_);
-
- // RenderOnVideoFrame() must be called on the same thread each time.
- SEQUENCE_CHECKER(render_sequence_checker_);
-
- base::WeakPtrFactory<CursorRenderer> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(CursorRenderer);
-};
-
-// Restores the original content of a VideoFrame, to the point before cursor
-// rendering modified it. See CursorRenderer::RenderOnVideoFrame().
-class CONTENT_EXPORT CursorRendererUndoer {
- public:
- CursorRendererUndoer();
- ~CursorRendererUndoer();
-
- CursorRendererUndoer(CursorRendererUndoer&& other) noexcept;
- CursorRendererUndoer& operator=(CursorRendererUndoer&& other) noexcept;
-
- void TakeSnapshot(const media::VideoFrame& frame, const gfx::Rect& rect);
-
- // Restores the frame content to the point where TakeSnapshot() was last
- // called.
- void Undo(media::VideoFrame* frame) const;
-
- private:
- gfx::Rect rect_;
- std::vector<uint8_t> snapshot_;
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_MEDIA_CAPTURE_CURSOR_RENDERER_H_
diff --git a/chromium/content/browser/media/capture/cursor_renderer_aura.cc b/chromium/content/browser/media/capture/cursor_renderer_aura.cc
deleted file mode 100644
index ec13d0da468..00000000000
--- a/chromium/content/browser/media/capture/cursor_renderer_aura.cc
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright (c) 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 "content/browser/media/capture/cursor_renderer_aura.h"
-
-#include "ui/aura/client/screen_position_client.h"
-#include "ui/aura/env.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/base/cursor/cursors_aura.h"
-#include "ui/events/event_utils.h"
-#include "ui/wm/public/activation_client.h"
-
-namespace content {
-
-// static
-std::unique_ptr<CursorRenderer> CursorRenderer::Create(
- CursorRenderer::CursorDisplaySetting display) {
- return std::make_unique<CursorRendererAura>(display);
-}
-
-CursorRendererAura::CursorRendererAura(CursorDisplaySetting display)
- : CursorRenderer(display) {}
-
-CursorRendererAura::~CursorRendererAura() {
- SetTargetView(nullptr);
-}
-
-void CursorRendererAura::SetTargetView(aura::Window* window) {
- if (window_) {
- window_->RemoveObserver(this);
- window_->RemovePreTargetHandler(this);
- }
- window_ = window;
- OnMouseHasGoneIdle();
- if (window_) {
- window_->AddObserver(this);
- window_->AddPreTargetHandler(this);
- }
-}
-
-bool CursorRendererAura::IsCapturedViewActive() {
- if (!window_) {
- DVLOG(2) << "Skipping update with no window being tracked";
- return false;
- }
-
- // If we are sharing the root window, or namely the whole screen, we will
- // render the mouse cursor. For ordinary window, we only render the mouse
- // cursor when the window is active.
- if (!window_->IsRootWindow()) {
- wm::ActivationClient* activation_client =
- wm::GetActivationClient(window_->GetRootWindow());
- if (!activation_client) {
- DVLOG(2) << "Assume window inactive with invalid activation_client";
- return false;
- }
- aura::Window* active_window = activation_client->GetActiveWindow();
- if (!active_window) {
- DVLOG(2) << "Skipping update as there is no active window";
- return false;
- }
- if (!active_window->Contains(window_)) {
- // Return early if the target window is not active.
- DVLOG(2) << "Skipping update on an inactive window";
- return false;
- }
- }
- return true;
-}
-
-gfx::Size CursorRendererAura::GetCapturedViewSize() {
- if (!window_) {
- return gfx::Size();
- }
-
- const gfx::Rect window_bounds = window_->GetBoundsInScreen();
- const gfx::Size view_size(window_bounds.width(), window_bounds.height());
- return view_size;
-}
-
-gfx::Point CursorRendererAura::GetCursorPositionInView() {
- if (!window_) {
- return gfx::Point(-1, -1);
- }
-
- // Convert from screen coordinates to view coordinates.
- aura::Window* const root_window = window_->GetRootWindow();
- if (!root_window)
- return gfx::Point(-1, -1);
- aura::client::ScreenPositionClient* const client =
- aura::client::GetScreenPositionClient(root_window);
- if (!client)
- return gfx::Point(-1, -1);
- gfx::Point cursor_position = aura::Env::GetInstance()->last_mouse_location();
- client->ConvertPointFromScreen(window_, &cursor_position);
- return cursor_position;
-}
-
-gfx::NativeCursor CursorRendererAura::GetLastKnownCursor() {
- if (!window_) {
- return gfx::NativeCursor();
- }
-
- return window_->GetHost()->last_cursor();
-}
-
-SkBitmap CursorRendererAura::GetLastKnownCursorImage(gfx::Point* hot_point) {
- if (!window_) {
- return SkBitmap();
- }
-
- gfx::NativeCursor cursor = window_->GetHost()->last_cursor();
- *hot_point = cursor.GetHotspot();
- return cursor.GetBitmap();
-}
-
-void CursorRendererAura::OnMouseEvent(ui::MouseEvent* event) {
- gfx::Point mouse_location(event->x(), event->y());
- switch (event->type()) {
- case ui::ET_MOUSE_MOVED:
- OnMouseMoved(mouse_location);
- break;
- case ui::ET_MOUSE_PRESSED:
- case ui::ET_MOUSE_RELEASED:
- case ui::ET_MOUSEWHEEL:
- OnMouseClicked(mouse_location);
- break;
- default:
- return;
- }
-}
-
-void CursorRendererAura::OnWindowDestroying(aura::Window* window) {
- DCHECK_EQ(window_, window);
- window_->RemovePreTargetHandler(this);
- window_->RemoveObserver(this);
- window_ = nullptr;
-}
-
-} // namespace content
diff --git a/chromium/content/browser/media/capture/cursor_renderer_aura.h b/chromium/content/browser/media/capture/cursor_renderer_aura.h
deleted file mode 100644
index 8d825fa8756..00000000000
--- a/chromium/content/browser/media/capture/cursor_renderer_aura.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 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 CONTENT_BROWSER_MEDIA_CAPTURE_CURSOR_RENDERER_AURA_H_
-#define CONTENT_BROWSER_MEDIA_CAPTURE_CURSOR_RENDERER_AURA_H_
-
-#include "content/browser/media/capture/cursor_renderer.h"
-#include "ui/aura/window.h"
-#include "ui/events/event_handler.h"
-
-namespace content {
-
-class CONTENT_EXPORT CursorRendererAura : public CursorRenderer,
- public ui::EventHandler,
- public aura::WindowObserver {
- public:
- explicit CursorRendererAura(CursorDisplaySetting cursor_display);
- ~CursorRendererAura() final;
-
- // CursorRenderer implementation.
- void SetTargetView(gfx::NativeView window) final;
- bool IsCapturedViewActive() final;
- gfx::Size GetCapturedViewSize() final;
- gfx::Point GetCursorPositionInView() final;
- gfx::NativeCursor GetLastKnownCursor() final;
- SkBitmap GetLastKnownCursorImage(gfx::Point* hot_point) final;
-
- // ui::EventHandler overrides.
- void OnMouseEvent(ui::MouseEvent* event) final;
-
- // aura::WindowObserver overrides.
- void OnWindowDestroying(aura::Window* window) final;
-
- private:
- aura::Window* window_ = nullptr;
-
- DISALLOW_COPY_AND_ASSIGN(CursorRendererAura);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_MEDIA_CAPTURE_CURSOR_RENDERER_AURA_H_
diff --git a/chromium/content/browser/media/capture/cursor_renderer_aura_unittest.cc b/chromium/content/browser/media/capture/cursor_renderer_aura_unittest.cc
deleted file mode 100644
index 4a5209e9985..00000000000
--- a/chromium/content/browser/media/capture/cursor_renderer_aura_unittest.cc
+++ /dev/null
@@ -1,261 +0,0 @@
-// Copyright (c) 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 "content/browser/media/capture/cursor_renderer_aura.h"
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/files/file_path.h"
-#include "base/path_service.h"
-#include "base/time/time.h"
-#include "media/base/video_frame.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/aura/env.h"
-#include "ui/aura/test/aura_test_base.h"
-#include "ui/aura/test/test_windows.h"
-#include "ui/aura/window.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/events/event.h"
-#include "ui/events/event_utils.h"
-#include "ui/wm/core/default_activation_client.h"
-#include "ui/wm/core/default_screen_position_client.h"
-#include "ui/wm/core/window_util.h"
-
-namespace content {
-
-using aura::test::AuraTestBase;
-
-class CursorRendererAuraTest : public AuraTestBase {
- public:
- CursorRendererAuraTest() {}
- ~CursorRendererAuraTest() override {}
-
- void SetUp() override {
- AuraTestBase::SetUp();
- // This is needed to avoid duplicate initialization across tests that leads
- // to a failure.
- if (!ui::ResourceBundle::HasSharedInstance()) {
- // Initialize the shared global resource bundle that has bitmap
- // resources needed by CursorRenderer
- base::FilePath pak_file;
- bool r = base::PathService::Get(base::DIR_MODULE, &pak_file);
- DCHECK(r);
- pak_file = pak_file.Append(FILE_PATH_LITERAL("content_shell.pak"));
- ui::ResourceBundle::InitSharedInstanceWithPakPath(pak_file);
- }
-
- window_.reset(aura::test::CreateTestWindowWithBounds(
- gfx::Rect(0, 0, 800, 600), root_window()));
- cursor_renderer_.reset(new CursorRendererAura(
- CursorRenderer::CURSOR_DISPLAYED_ON_MOUSE_MOVEMENT));
- cursor_renderer_->SetTargetView(window_.get());
- new wm::DefaultActivationClient(root_window());
- aura::client::SetScreenPositionClient(root_window(),
- &screen_position_client_);
- wm::ActivateWindow(window_.get());
- }
-
- void TearDown() override {
- aura::client::SetScreenPositionClient(root_window(), nullptr);
- cursor_renderer_.reset();
- window_.reset();
- AuraTestBase::TearDown();
- }
-
- base::TimeTicks Now() { return base::TimeTicks::Now(); }
-
- bool CursorDisplayed() {
- // Request rendering into a dummy video frame. If RenderCursorOnVideoFrame()
- // returns true, then the cursor is being displayed.
- if (!dummy_frame_) {
- constexpr gfx::Size dummy_frame_size = gfx::Size(320, 200);
- dummy_frame_ = media::VideoFrame::CreateZeroInitializedFrame(
- media::PIXEL_FORMAT_I420, dummy_frame_size,
- gfx::Rect(dummy_frame_size), dummy_frame_size, base::TimeDelta());
- }
- return RenderCursorOnVideoFrame(dummy_frame_.get(), nullptr);
- }
-
- bool RenderCursorOnVideoFrame(media::VideoFrame* frame,
- CursorRendererUndoer* undoer) {
- return cursor_renderer_->RenderOnVideoFrame(frame, frame->visible_rect(),
- undoer);
- }
-
- bool IsUserInteractingWithView() {
- return cursor_renderer_->IsUserInteractingWithView();
- }
-
- void MoveMouseCursorWithinWindow() {
- gfx::Point point1(20, 20);
- ui::MouseEvent event1(ui::ET_MOUSE_MOVED, point1, point1, Now(), 0, 0);
- aura::Env::GetInstance()->SetLastMouseLocation(point1);
- cursor_renderer_->OnMouseEvent(&event1);
- gfx::Point point2(60, 60);
- ui::MouseEvent event2(ui::ET_MOUSE_MOVED, point2, point2, Now(), 0, 0);
- aura::Env::GetInstance()->SetLastMouseLocation(point2);
- cursor_renderer_->OnMouseEvent(&event2);
- }
-
- void MoveMouseCursorOutsideWindow() {
- gfx::Point point(1000, 1000);
- ui::MouseEvent event1(ui::ET_MOUSE_MOVED, point, point, Now(), 0, 0);
- aura::Env::GetInstance()->SetLastMouseLocation(point);
- cursor_renderer_->OnMouseEvent(&event1);
- }
-
- void SimulateMouseWentIdle() {
- EXPECT_TRUE(cursor_renderer_->mouse_activity_ended_timer_.IsRunning());
- cursor_renderer_->mouse_activity_ended_timer_.Stop();
- cursor_renderer_->OnMouseHasGoneIdle();
- }
-
- // A very simple test of whether there are any non-zero pixels
- // in the region |rect| within |frame|.
- bool NonZeroPixelsInRegion(scoped_refptr<media::VideoFrame> frame,
- gfx::Rect rect) {
- bool y_found = false, u_found = false, v_found = false;
- for (int y = rect.y(); y < rect.bottom(); ++y) {
- uint8_t* yplane = frame->visible_data(media::VideoFrame::kYPlane) +
- y * frame->stride(media::VideoFrame::kYPlane);
- uint8_t* uplane = frame->visible_data(media::VideoFrame::kUPlane) +
- (y / 2) * frame->stride(media::VideoFrame::kUPlane);
- uint8_t* vplane = frame->visible_data(media::VideoFrame::kVPlane) +
- (y / 2) * frame->stride(media::VideoFrame::kVPlane);
- for (int x = rect.x(); x < rect.right(); ++x) {
- if (yplane[x] != 0)
- y_found = true;
- if (uplane[x / 2])
- u_found = true;
- if (vplane[x / 2])
- v_found = true;
- }
- }
- return (y_found && u_found && v_found);
- }
-
- protected:
- wm::DefaultScreenPositionClient screen_position_client_;
- std::unique_ptr<aura::Window> window_;
- std::unique_ptr<CursorRendererAura> cursor_renderer_;
-
- scoped_refptr<media::VideoFrame> dummy_frame_;
-};
-
-TEST_F(CursorRendererAuraTest, CursorAlwaysDisplayed) {
- // Set up cursor renderer to always display cursor.
- cursor_renderer_.reset(
- new CursorRendererAura(CursorRenderer::CURSOR_DISPLAYED_ALWAYS));
- cursor_renderer_->SetTargetView(window_.get());
-
- // Cursor displayed at start.
- EXPECT_TRUE(CursorDisplayed());
- EXPECT_FALSE(IsUserInteractingWithView());
-
- // Cursor displayed after mouse movement.
- MoveMouseCursorWithinWindow();
- EXPECT_TRUE(CursorDisplayed());
- EXPECT_TRUE(IsUserInteractingWithView());
-
- // Cursor displayed after idle period.
- SimulateMouseWentIdle();
- EXPECT_TRUE(CursorDisplayed());
- EXPECT_FALSE(IsUserInteractingWithView());
-
- // Cursor not displayed with mouse outside the window.
- MoveMouseCursorOutsideWindow();
- EXPECT_FALSE(CursorDisplayed());
-}
-
-TEST_F(CursorRendererAuraTest, CursorDuringMouseMovement) {
- // Cursor not displayed at start.
- EXPECT_FALSE(CursorDisplayed());
- EXPECT_FALSE(IsUserInteractingWithView());
-
- // Cursor displayed after mouse movement.
- MoveMouseCursorWithinWindow();
- EXPECT_TRUE(CursorDisplayed());
- EXPECT_TRUE(IsUserInteractingWithView());
-
- // Cursor not displayed after idle period.
- SimulateMouseWentIdle();
- EXPECT_FALSE(CursorDisplayed());
- EXPECT_FALSE(IsUserInteractingWithView());
-
- // Cursor displayed with mouse movement following idle period.
- MoveMouseCursorWithinWindow();
- EXPECT_TRUE(CursorDisplayed());
- EXPECT_TRUE(IsUserInteractingWithView());
-
- // Cursor not displayed if mouse outside the window
- MoveMouseCursorOutsideWindow();
- EXPECT_FALSE(CursorDisplayed());
-}
-
-TEST_F(CursorRendererAuraTest, CursorOnActiveWindow) {
- // Cursor not displayed at start.
- EXPECT_FALSE(CursorDisplayed());
- EXPECT_FALSE(IsUserInteractingWithView());
-
- // Cursor displayed after mouse movement.
- MoveMouseCursorWithinWindow();
- EXPECT_TRUE(CursorDisplayed());
- EXPECT_TRUE(IsUserInteractingWithView());
-
- // Cursor not be displayed if a second window is activated.
- std::unique_ptr<aura::Window> window2(aura::test::CreateTestWindowWithBounds(
- gfx::Rect(0, 0, 800, 600), root_window()));
- wm::ActivateWindow(window2.get());
- MoveMouseCursorWithinWindow();
- EXPECT_FALSE(CursorDisplayed());
- EXPECT_TRUE(IsUserInteractingWithView());
-
- // Cursor displayed if window activated again.
- wm::ActivateWindow(window_.get());
- MoveMouseCursorWithinWindow();
- EXPECT_TRUE(CursorDisplayed());
- EXPECT_TRUE(IsUserInteractingWithView());
-}
-
-TEST_F(CursorRendererAuraTest, CursorRenderedOnFrame) {
- // Cursor not displayed at start.
- EXPECT_FALSE(CursorDisplayed());
-
- gfx::Size size(800, 600);
- scoped_refptr<media::VideoFrame> frame =
- media::VideoFrame::CreateZeroInitializedFrame(media::PIXEL_FORMAT_I420,
- size, gfx::Rect(size), size,
- base::TimeDelta());
-
- MoveMouseCursorWithinWindow();
- EXPECT_TRUE(CursorDisplayed());
-
- EXPECT_FALSE(NonZeroPixelsInRegion(frame, frame->visible_rect()));
- CursorRendererUndoer undoer;
- EXPECT_TRUE(RenderCursorOnVideoFrame(frame.get(), &undoer));
- EXPECT_TRUE(NonZeroPixelsInRegion(frame, gfx::Rect(50, 50, 70, 70)));
- undoer.Undo(frame.get());
- EXPECT_FALSE(NonZeroPixelsInRegion(frame, frame->visible_rect()));
-}
-
-TEST_F(CursorRendererAuraTest, CursorRenderedOnRootWindow) {
- cursor_renderer_->SetTargetView(root_window());
-
- // Cursor not displayed at start.
- EXPECT_FALSE(CursorDisplayed());
-
- // Cursor displayed after mouse movement.
- MoveMouseCursorWithinWindow();
- EXPECT_TRUE(CursorDisplayed());
-
- // Cursor being displayed even if another window is activated.
- std::unique_ptr<aura::Window> window2(aura::test::CreateTestWindowWithBounds(
- gfx::Rect(0, 0, 800, 600), root_window()));
- wm::ActivateWindow(window2.get());
- EXPECT_TRUE(CursorDisplayed());
-}
-
-} // namespace content
diff --git a/chromium/content/browser/media/capture/cursor_renderer_mac.h b/chromium/content/browser/media/capture/cursor_renderer_mac.h
deleted file mode 100644
index cdf77a03090..00000000000
--- a/chromium/content/browser/media/capture/cursor_renderer_mac.h
+++ /dev/null
@@ -1,63 +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 CONTENT_BROWSER_MEDIA_CAPTURE_CURSOR_RENDERER_MAC_H_
-#define CONTENT_BROWSER_MEDIA_CAPTURE_CURSOR_RENDERER_MAC_H_
-
-#import <AppKit/AppKit.h>
-
-#include "base/mac/scoped_nsobject.h"
-#include "content/browser/media/capture/cursor_renderer.h"
-#import "ui/base/cocoa/tracking_area.h"
-
-@interface CursorRendererMouseTracker : NSObject {
- @private
- ui::ScopedCrTrackingArea trackingArea_;
-
- // The view on which mouse movement is detected.
- base::scoped_nsobject<NSView> capturedView_;
-
- // Runs on any mouse interaction from user.
- base::RepeatingClosure mouseInteractionObserver_;
-}
-
-- (instancetype)initWithView:(NSView*)nsView;
-
-// Register an observer for mouse interaction.
-- (void)registerMouseInteractionObserver:
- (const base::RepeatingClosure&)observer;
-
-@end
-
-namespace content {
-
-class CONTENT_EXPORT CursorRendererMac : public CursorRenderer {
- public:
- explicit CursorRendererMac(CursorDisplaySetting cursor_display);
- ~CursorRendererMac() final;
-
- // CursorRenderer implementation.
- void SetTargetView(gfx::NativeView window) final;
- bool IsCapturedViewActive() final;
- gfx::Size GetCapturedViewSize() final;
- gfx::Point GetCursorPositionInView() final;
- gfx::NativeCursor GetLastKnownCursor() final;
- SkBitmap GetLastKnownCursorImage(gfx::Point* hot_point) final;
-
- private:
- friend class CursorRendererMacTest;
-
- // Called for mouse activity events.
- void OnMouseEvent();
-
- NSView* view_ = nil;
-
- base::scoped_nsobject<CursorRendererMouseTracker> mouse_tracker_;
-
- DISALLOW_COPY_AND_ASSIGN(CursorRendererMac);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_MEDIA_CAPTURE_CURSOR_RENDERER_MAC_H_
diff --git a/chromium/content/browser/media/capture/cursor_renderer_mac.mm b/chromium/content/browser/media/capture/cursor_renderer_mac.mm
deleted file mode 100644
index 800bef2619d..00000000000
--- a/chromium/content/browser/media/capture/cursor_renderer_mac.mm
+++ /dev/null
@@ -1,140 +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 "content/browser/media/capture/cursor_renderer_mac.h"
-
-#include <Cocoa/Cocoa.h>
-#include <CoreFoundation/CoreFoundation.h>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/mac/mac_util.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "ui/gfx/image/image.h"
-
-@implementation CursorRendererMouseTracker
-
-- (instancetype)initWithView:(NSView*)nsView {
- if ((self = [super init])) {
- NSTrackingAreaOptions trackingOptions =
- NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited |
- NSTrackingActiveInKeyWindow | NSTrackingInVisibleRect;
- trackingArea_.reset([[CrTrackingArea alloc] initWithRect:NSZeroRect
- options:trackingOptions
- owner:self
- userInfo:nil]);
- [nsView addTrackingArea:trackingArea_.get()];
- capturedView_.reset([nsView retain]);
- }
- return self;
-}
-
-- (void)stopTracking {
- if (trackingArea_.get()) {
- [capturedView_ removeTrackingArea:trackingArea_.get()];
- trackingArea_.reset();
- capturedView_.reset();
- }
-}
-
-- (void)registerMouseInteractionObserver:
- (const base::RepeatingClosure&)observer {
- mouseInteractionObserver_ = observer;
-}
-
-- (void)mouseMoved:(NSEvent*)theEvent {
- mouseInteractionObserver_.Run();
-}
-
-- (void)mouseEntered:(NSEvent*)theEvent {
- mouseInteractionObserver_.Run();
-}
-
-- (void)mouseExited:(NSEvent*)theEvent {
-}
-
-@end
-
-namespace content {
-
-// static
-std::unique_ptr<CursorRenderer> CursorRenderer::Create(
- CursorRenderer::CursorDisplaySetting display) {
- return std::make_unique<CursorRendererMac>(display);
-}
-
-CursorRendererMac::CursorRendererMac(CursorDisplaySetting display)
- : CursorRenderer(display) {}
-
-CursorRendererMac::~CursorRendererMac() {
- SetTargetView(nil);
-}
-
-void CursorRendererMac::SetTargetView(NSView* view) {
- if (view_) {
- [mouse_tracker_ stopTracking];
- mouse_tracker_.reset();
- }
- view_ = view;
- OnMouseHasGoneIdle();
- if (view_) {
- mouse_tracker_.reset(
- [[CursorRendererMouseTracker alloc] initWithView:view_]);
- [mouse_tracker_
- registerMouseInteractionObserver:base::BindRepeating(
- &CursorRendererMac::OnMouseEvent,
- base::Unretained(this))];
- }
-}
-
-bool CursorRendererMac::IsCapturedViewActive() {
- if (![[view_ window] isKeyWindow]) {
- return false;
- }
- return true;
-}
-
-gfx::Size CursorRendererMac::GetCapturedViewSize() {
- NSRect frame_rect = [view_ bounds];
- return gfx::Size(frame_rect.size.width, frame_rect.size.height);
-}
-
-gfx::Point CursorRendererMac::GetCursorPositionInView() {
- // Mouse location in window co-ordinates.
- NSPoint mouse_window_location =
- [view_ window].mouseLocationOutsideOfEventStream;
- // Mouse location with respect to the view within the window.
- NSPoint mouse_view_location =
- [view_ convertPoint:mouse_window_location fromView:nil];
-
- // Invert y coordinate to unify with Aura.
- gfx::Point cursor_position_in_view(
- mouse_view_location.x,
- GetCapturedViewSize().height() - mouse_view_location.y);
-
- return cursor_position_in_view;
-}
-
-gfx::NativeCursor CursorRendererMac::GetLastKnownCursor() {
- // Grab system cursor.
- return [NSCursor currentSystemCursor];
-}
-
-SkBitmap CursorRendererMac::GetLastKnownCursorImage(gfx::Point* hot_point) {
- // Grab system cursor.
- NSCursor* nscursor = [NSCursor currentSystemCursor];
- NSImage* nsimage = [nscursor image];
- NSPoint nshotspot = [nscursor hotSpot];
-
- *hot_point = gfx::Point(nshotspot.x, nshotspot.y);
- return skia::NSImageToSkBitmapWithColorSpace(
- nsimage, /*is_opaque=*/false, base::mac::GetSystemColorSpace());
-}
-
-void CursorRendererMac::OnMouseEvent() {
- // Update cursor movement info to CursorRenderer.
- OnMouseMoved(GetCursorPositionInView());
-}
-
-} // namespace content
diff --git a/chromium/content/browser/media/capture/cursor_renderer_mac_unittest.mm b/chromium/content/browser/media/capture/cursor_renderer_mac_unittest.mm
deleted file mode 100644
index 68f70d37be6..00000000000
--- a/chromium/content/browser/media/capture/cursor_renderer_mac_unittest.mm
+++ /dev/null
@@ -1,227 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/media/capture/cursor_renderer_mac.h"
-
-#include <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/test/scoped_task_environment.h"
-#include "base/time/time.h"
-#include "media/base/video_frame.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/test/cocoa_helper.h"
-#include "ui/gfx/mac/coordinate_conversion.h"
-
-namespace content {
-
-const int kTestViewWidth = 320;
-const int kTestViewHeight = 240;
-
-CGEventRef myCGEventCallback(CGEventTapProxy proxy,
- CGEventType type,
- CGEventRef event,
- void* refcon) {
- // Paranoid sanity check.
- if (type != kCGEventMouseMoved)
- return event;
- // Discard mouse-moved event.
- return NULL;
-}
-
-class CursorRendererMacTest : public ui::CocoaTest {
- public:
- CursorRendererMacTest() {}
- ~CursorRendererMacTest() override {}
-
- void SetUp() override {
- ui::CocoaTest::SetUp();
- base::scoped_nsobject<NSView> view([[NSView alloc]
- initWithFrame:NSMakeRect(0, 0, kTestViewWidth, kTestViewHeight)]);
- view_ = view.get();
- [[test_window() contentView] addSubview:view_];
- cursor_renderer_.reset(new CursorRendererMac(
- CursorRenderer::CURSOR_DISPLAYED_ON_MOUSE_MOVEMENT));
- cursor_renderer_->SetTargetView(view_);
- // Dis-associate mouse and cursor.
- StartEventTap();
- [test_window() setPretendIsKeyWindow:YES];
- }
-
- void TearDown() override {
- StopEventTap();
- cursor_renderer_.reset();
- ui::CocoaTest::TearDown();
- }
-
- bool CursorDisplayed() {
- // Request rendering into a dummy video frame. If RenderCursorOnVideoFrame()
- // returns true, then the cursor is being displayed.
- if (!dummy_frame_) {
- constexpr gfx::Size dummy_frame_size = gfx::Size(320, 200);
- dummy_frame_ = media::VideoFrame::CreateZeroInitializedFrame(
- media::PIXEL_FORMAT_I420, dummy_frame_size,
- gfx::Rect(dummy_frame_size), dummy_frame_size, base::TimeDelta());
- }
- return RenderCursorOnVideoFrame(dummy_frame_.get(), nullptr);
- }
-
- bool RenderCursorOnVideoFrame(media::VideoFrame* frame,
- CursorRendererUndoer* undoer) {
- return cursor_renderer_->RenderOnVideoFrame(frame, frame->visible_rect(),
- undoer);
- }
-
- bool IsUserInteractingWithView() {
- return cursor_renderer_->IsUserInteractingWithView();
- }
-
- // Here the |point| is in Aura coordinates (the origin (0, 0) is at top-left
- // of the view). To move the cursor to that point by Quartz Display service,
- // it needs to be converted into Cocoa coordinates (the origin is at
- // bottom-left of the main screen) first, and then info Quartz coordinates
- // (the origin is at top-left of the main display).
- void MoveMouseCursorWithinWindow() {
- CGWarpMouseCursorPosition(
- gfx::ScreenPointToNSPoint(gfx::Point(50, kTestViewHeight - 50)));
- cursor_renderer_->OnMouseEvent();
-
- CGWarpMouseCursorPosition(
- gfx::ScreenPointToNSPoint(gfx::Point(100, kTestViewHeight - 100)));
- cursor_renderer_->OnMouseEvent();
- }
-
- void MoveMouseCursorOutsideWindow() {
- CGWarpMouseCursorPosition(CGPointMake(1000, 200));
- cursor_renderer_->OnMouseEvent();
- }
-
- void SimulateMouseWentIdle() {
- EXPECT_TRUE(cursor_renderer_->mouse_activity_ended_timer_.IsRunning());
- cursor_renderer_->mouse_activity_ended_timer_.Stop();
- cursor_renderer_->OnMouseHasGoneIdle();
- }
-
- // A very simple test of whether there are any non-zero pixels
- // in the region |rect| within |frame|.
- bool NonZeroPixelsInRegion(scoped_refptr<media::VideoFrame> frame,
- gfx::Rect rect) {
- bool y_found = false, u_found = false, v_found = false;
- for (int y = rect.y(); y < rect.bottom(); ++y) {
- uint8_t* yplane = frame->visible_data(media::VideoFrame::kYPlane) +
- y * frame->stride(media::VideoFrame::kYPlane);
- uint8_t* uplane = frame->visible_data(media::VideoFrame::kUPlane) +
- (y / 2) * frame->stride(media::VideoFrame::kUPlane);
- uint8_t* vplane = frame->visible_data(media::VideoFrame::kVPlane) +
- (y / 2) * frame->stride(media::VideoFrame::kVPlane);
- for (int x = rect.x(); x < rect.right(); ++x) {
- if (yplane[x] != 0)
- y_found = true;
- if (uplane[x / 2])
- u_found = true;
- if (vplane[x / 2])
- v_found = true;
- }
- }
- return (y_found && u_found && v_found);
- }
-
- // The test cases here need to move the actual cursor. If the mouse moves the
- // cursor at same time, the cursor position might be unexpected and test cases
- // will fail. So dis-associate mouse and cursor by enabling event tap for
- // mouse-moved event during tests runnning.
- void StartEventTap() {
- // Create an event tap. We are interested in mouse moved.
- CGEventMask eventMask = 1 << kCGEventMouseMoved;
- event_tap_ = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap,
- kCGEventTapOptionDefault, eventMask,
- myCGEventCallback, NULL);
- if (event_tap_) {
- // Enable the event tap.
- CGEventTapEnable(event_tap_, true);
- }
- }
-
- void StopEventTap() { CGEventTapEnable(event_tap_, false); }
-
- protected:
- base::test::ScopedTaskEnvironment scoped_task_environment_;
- NSView* view_;
- std::unique_ptr<CursorRendererMac> cursor_renderer_;
-
- CFMachPortRef event_tap_;
-
- scoped_refptr<media::VideoFrame> dummy_frame_;
-};
-
-TEST_F(CursorRendererMacTest, CursorDuringMouseMovement) {
- // Cursor not displayed at start.
- EXPECT_FALSE(CursorDisplayed());
- EXPECT_FALSE(IsUserInteractingWithView());
-
- // Cursor displayed after mouse movement.
- MoveMouseCursorWithinWindow();
- EXPECT_TRUE(CursorDisplayed());
- EXPECT_TRUE(IsUserInteractingWithView());
-
- // Cursor not displayed after idle period.
- SimulateMouseWentIdle();
- EXPECT_FALSE(CursorDisplayed());
- EXPECT_FALSE(IsUserInteractingWithView());
-
- // Cursor displayed with mouse movement following idle period.
- MoveMouseCursorWithinWindow();
- EXPECT_TRUE(CursorDisplayed());
- EXPECT_TRUE(IsUserInteractingWithView());
-
- // Cursor not displayed if mouse outside the window
- MoveMouseCursorOutsideWindow();
- EXPECT_FALSE(CursorDisplayed());
-}
-
-TEST_F(CursorRendererMacTest, CursorOnActiveWindow) {
- // Cursor not displayed at start.
- EXPECT_FALSE(CursorDisplayed());
- EXPECT_FALSE(IsUserInteractingWithView());
-
- // Cursor displayed after mouse movement.
- MoveMouseCursorWithinWindow();
- EXPECT_TRUE(CursorDisplayed());
- EXPECT_TRUE(IsUserInteractingWithView());
-
- // Cursor not displayed if window is not activated.
- [test_window() setPretendIsKeyWindow:NO];
- MoveMouseCursorWithinWindow();
- EXPECT_FALSE(CursorDisplayed());
- EXPECT_TRUE(IsUserInteractingWithView());
-
- // Cursor is displayed again if window is activated again.
- [test_window() setPretendIsKeyWindow:YES];
- MoveMouseCursorWithinWindow();
- EXPECT_TRUE(CursorDisplayed());
- EXPECT_TRUE(IsUserInteractingWithView());
-}
-
-TEST_F(CursorRendererMacTest, CursorRenderedOnFrame) {
- // Cursor not displayed at start.
- EXPECT_FALSE(CursorDisplayed());
-
- gfx::Size size(kTestViewWidth, kTestViewHeight);
- scoped_refptr<media::VideoFrame> frame =
- media::VideoFrame::CreateZeroInitializedFrame(media::PIXEL_FORMAT_I420,
- size, gfx::Rect(size), size,
- base::TimeDelta());
-
- MoveMouseCursorWithinWindow();
- EXPECT_TRUE(CursorDisplayed());
-
- EXPECT_FALSE(NonZeroPixelsInRegion(frame, frame->visible_rect()));
- CursorRendererUndoer undoer;
- EXPECT_TRUE(RenderCursorOnVideoFrame(frame.get(), &undoer));
- EXPECT_TRUE(NonZeroPixelsInRegion(frame, gfx::Rect(50, 50, 70, 70)));
- undoer.Undo(frame.get());
- EXPECT_FALSE(NonZeroPixelsInRegion(frame, frame->visible_rect()));
-}
-
-} // namespace content
diff --git a/chromium/content/browser/media/capture/desktop_capture_device.cc b/chromium/content/browser/media/capture/desktop_capture_device.cc
index 01954292117..50510bdefb7 100644
--- a/chromium/content/browser/media/capture/desktop_capture_device.cc
+++ b/chromium/content/browser/media/capture/desktop_capture_device.cc
@@ -313,7 +313,9 @@ void DesktopCaptureDevice::Core::OnCaptureResult(
IncrementDesktopCaptureCounter(WINDOW_CAPTURER_PERMANENT_ERROR);
}
}
- client_->OnError(FROM_HERE, "The desktop capturer has failed.");
+ client_->OnError(media::VideoCaptureError::
+ kDesktopCaptureDeviceWebrtcDesktopCapturerHasFailed,
+ FROM_HERE, "The desktop capturer has failed.");
}
return;
}
diff --git a/chromium/content/browser/media/capture/desktop_capture_device_unittest.cc b/chromium/content/browser/media/capture/desktop_capture_device_unittest.cc
index 96e5f8c1e81..636f20a88bd 100644
--- a/chromium/content/browser/media/capture/desktop_capture_device_unittest.cc
+++ b/chromium/content/browser/media/capture/desktop_capture_device_unittest.cc
@@ -20,6 +20,7 @@
#include "base/test/test_timeouts.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
+#include "media/capture/video/mock_video_capture_device_client.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h"
@@ -63,65 +64,6 @@ const uint8_t kFakePixelValue = 1;
// frame test.
const uint8_t kFakePixelValueFirst = 2;
-class MockDeviceClient : public media::VideoCaptureDevice::Client {
- public:
- MOCK_METHOD7(OnIncomingCapturedData,
- void(const uint8_t* data,
- int length,
- const media::VideoCaptureFormat& frame_format,
- int rotation,
- base::TimeTicks reference_time,
- base::TimeDelta timestamp,
- int frame_feedback_id));
- MOCK_METHOD6(OnIncomingCapturedGfxBuffer,
- void(gfx::GpuMemoryBuffer* buffer,
- const media::VideoCaptureFormat& frame_format,
- int clockwise_rotation,
- base::TimeTicks reference_time,
- base::TimeDelta timestamp,
- int frame_feedback_id));
- MOCK_METHOD0(DoReserveOutputBuffer, void(void));
- MOCK_METHOD0(DoOnIncomingCapturedBuffer, void(void));
- MOCK_METHOD0(DoOnIncomingCapturedVideoFrame, void(void));
- MOCK_METHOD0(DoResurrectLastOutputBuffer, void(void));
- MOCK_METHOD2(OnError,
- void(const base::Location& from_here,
- const std::string& reason));
- MOCK_METHOD0(OnStarted, void(void));
-
- // Trampoline methods to workaround GMOCK problems with std::unique_ptr<>.
- Buffer ReserveOutputBuffer(const gfx::Size& dimensions,
- media::VideoPixelFormat format,
- int frame_feedback_id) override {
- EXPECT_TRUE(format == media::PIXEL_FORMAT_I420);
- DoReserveOutputBuffer();
- return Buffer();
- }
- void OnIncomingCapturedBuffer(Buffer buffer,
- const media::VideoCaptureFormat& format,
- base::TimeTicks reference_time,
- base::TimeDelta timestamp) override {
- DoOnIncomingCapturedBuffer();
- }
- void OnIncomingCapturedBufferExt(
- Buffer buffer,
- const media::VideoCaptureFormat& format,
- base::TimeTicks reference_time,
- base::TimeDelta timestamp,
- gfx::Rect visible_rect,
- const media::VideoFrameMetadata& additional_metadata) override {
- DoOnIncomingCapturedVideoFrame();
- }
- Buffer ResurrectLastOutputBuffer(const gfx::Size& dimensions,
- media::VideoPixelFormat format,
- int frame_feedback_id) override {
- EXPECT_TRUE(format == media::PIXEL_FORMAT_I420);
- DoResurrectLastOutputBuffer();
- return Buffer();
- }
- double GetBufferPoolUtilization() const override { return 0.0; }
-};
-
// Creates a DesktopFrame that has the first pixel bytes set to
// kFakePixelValueFirst, and the rest of the bytes set to kFakePixelValue, for
// UnpackedFrame and InvertedFrame verification.
@@ -285,6 +227,24 @@ class DesktopCaptureDeviceTest : public testing::Test {
}
protected:
+ std::unique_ptr<media::MockVideoCaptureDeviceClient>
+ CreateMockVideoCaptureDeviceClient() {
+ auto result = std::make_unique<media::MockVideoCaptureDeviceClient>();
+ ON_CALL(*result, ReserveOutputBuffer(_, _, _))
+ .WillByDefault(
+ Invoke([](const gfx::Size&, media::VideoPixelFormat format, int) {
+ EXPECT_TRUE(format == media::PIXEL_FORMAT_I420);
+ return media::VideoCaptureDevice::Client::Buffer();
+ }));
+ ON_CALL(*result, ResurrectLastOutputBuffer(_, _, _))
+ .WillByDefault(
+ Invoke([](const gfx::Size&, media::VideoPixelFormat format, int) {
+ EXPECT_TRUE(format == media::PIXEL_FORMAT_I420);
+ return media::VideoCaptureDevice::Client::Buffer();
+ }));
+ return result;
+ }
+
std::unique_ptr<DesktopCaptureDevice> capture_device_;
std::unique_ptr<webrtc::DesktopFrame> output_frame_;
};
@@ -309,8 +269,9 @@ TEST_F(DesktopCaptureDeviceTest, MAYBE_Capture) {
base::WaitableEvent::InitialState::NOT_SIGNALED);
int frame_size;
- std::unique_ptr<MockDeviceClient> client(new MockDeviceClient());
- EXPECT_CALL(*client, OnError(_, _)).Times(0);
+ std::unique_ptr<media::MockVideoCaptureDeviceClient> client(
+ CreateMockVideoCaptureDeviceClient());
+ EXPECT_CALL(*client, OnError(_, _, _)).Times(0);
EXPECT_CALL(*client, OnStarted());
EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _, _, _))
.WillRepeatedly(
@@ -347,8 +308,9 @@ TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeConstantResolution) {
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
- std::unique_ptr<MockDeviceClient> client(new MockDeviceClient());
- EXPECT_CALL(*client, OnError(_, _)).Times(0);
+ std::unique_ptr<media::MockVideoCaptureDeviceClient> client(
+ CreateMockVideoCaptureDeviceClient());
+ EXPECT_CALL(*client, OnError(_, _, _)).Times(0);
EXPECT_CALL(*client, OnStarted());
EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _, _, _))
.WillRepeatedly(
@@ -392,8 +354,9 @@ TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeFixedAspectRatio) {
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
- std::unique_ptr<MockDeviceClient> client(new MockDeviceClient());
- EXPECT_CALL(*client, OnError(_,_)).Times(0);
+ std::unique_ptr<media::MockVideoCaptureDeviceClient> client(
+ CreateMockVideoCaptureDeviceClient());
+ EXPECT_CALL(*client, OnError(_, _, _)).Times(0);
EXPECT_CALL(*client, OnStarted());
EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _, _, _))
.WillRepeatedly(
@@ -441,8 +404,9 @@ TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeVariableResolution) {
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
- std::unique_ptr<MockDeviceClient> client(new MockDeviceClient());
- EXPECT_CALL(*client, OnError(_,_)).Times(0);
+ std::unique_ptr<media::MockVideoCaptureDeviceClient> client(
+ CreateMockVideoCaptureDeviceClient());
+ EXPECT_CALL(*client, OnError(_, _, _)).Times(0);
EXPECT_CALL(*client, OnStarted());
EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _, _, _))
.WillRepeatedly(
@@ -492,8 +456,9 @@ TEST_F(DesktopCaptureDeviceTest, UnpackedFrame) {
output_frame_.reset(new webrtc::BasicDesktopFrame(
webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1)));
- std::unique_ptr<MockDeviceClient> client(new MockDeviceClient());
- EXPECT_CALL(*client, OnError(_,_)).Times(0);
+ std::unique_ptr<media::MockVideoCaptureDeviceClient> client(
+ CreateMockVideoCaptureDeviceClient());
+ EXPECT_CALL(*client, OnError(_, _, _)).Times(0);
EXPECT_CALL(*client, OnStarted());
EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _, _, _))
.WillRepeatedly(
@@ -540,8 +505,9 @@ TEST_F(DesktopCaptureDeviceTest, InvertedFrame) {
output_frame_.reset(new webrtc::BasicDesktopFrame(
webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1)));
- std::unique_ptr<MockDeviceClient> client(new MockDeviceClient());
- EXPECT_CALL(*client, OnError(_,_)).Times(0);
+ std::unique_ptr<media::MockVideoCaptureDeviceClient> client(
+ CreateMockVideoCaptureDeviceClient());
+ EXPECT_CALL(*client, OnError(_, _, _)).Times(0);
EXPECT_CALL(*client, OnStarted());
EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _, _, _))
.WillRepeatedly(
@@ -595,8 +561,9 @@ class DesktopCaptureDeviceThrottledTest : public DesktopCaptureDeviceTest {
scoped_refptr<base::TestMockTimeTaskRunner> task_runner;
int nb_frames = 0;
- std::unique_ptr<MockDeviceClient> client(new MockDeviceClient());
- EXPECT_CALL(*client, OnError(_, _)).Times(0);
+ std::unique_ptr<media::MockVideoCaptureDeviceClient> client(
+ CreateMockVideoCaptureDeviceClient());
+ EXPECT_CALL(*client, OnError(_, _, _)).Times(0);
// On started is called from the capture thread.
EXPECT_CALL(*client, OnStarted())
.WillOnce(InvokeWithoutArgs([this, &task_runner] {
diff --git a/chromium/content/browser/media/capture/desktop_streams_registry_impl.cc b/chromium/content/browser/media/capture/desktop_streams_registry_impl.cc
new file mode 100644
index 00000000000..347e00ab4d1
--- /dev/null
+++ b/chromium/content/browser/media/capture/desktop_streams_registry_impl.cc
@@ -0,0 +1,113 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/capture/desktop_streams_registry_impl.h"
+
+#include "base/base64.h"
+#include "base/location.h"
+#include "base/macros.h"
+#include "base/no_destructor.h"
+#include "base/stl_util.h"
+#include "base/time/time.h"
+#include "content/public/browser/browser_thread.h"
+#include "crypto/random.h"
+
+namespace {
+
+const int kStreamIdLengthBytes = 16;
+
+const int kApprovedStreamTimeToLiveSeconds = 10;
+
+std::string GenerateRandomStreamId() {
+ char buffer[kStreamIdLengthBytes];
+ crypto::RandBytes(buffer, base::size(buffer));
+ std::string result;
+ base::Base64Encode(base::StringPiece(buffer, base::size(buffer)), &result);
+ return result;
+}
+
+} // namespace
+
+namespace content {
+
+// static
+DesktopStreamsRegistry* DesktopStreamsRegistry::GetInstance() {
+ return DesktopStreamsRegistryImpl::GetInstance();
+}
+
+// static
+DesktopStreamsRegistryImpl* DesktopStreamsRegistryImpl::GetInstance() {
+ static base::NoDestructor<DesktopStreamsRegistryImpl> instance;
+ return instance.get();
+}
+
+DesktopStreamsRegistryImpl::DesktopStreamsRegistryImpl() {}
+DesktopStreamsRegistryImpl::~DesktopStreamsRegistryImpl() {}
+
+std::string DesktopStreamsRegistryImpl::RegisterStream(
+ int render_process_id,
+ int render_frame_id,
+ const GURL& origin,
+ const DesktopMediaID& source,
+ const std::string& extension_name,
+ const DesktopStreamRegistryType type) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ std::string id = GenerateRandomStreamId();
+ DCHECK(approved_streams_.find(id) == approved_streams_.end());
+ ApprovedDesktopMediaStream& stream = approved_streams_[id];
+ stream.render_process_id = render_process_id;
+ stream.render_frame_id = render_frame_id;
+ stream.origin = origin;
+ stream.source = source;
+ stream.extension_name = extension_name;
+ stream.type = type;
+
+ BrowserThread::PostDelayedTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&DesktopStreamsRegistryImpl::CleanupStream,
+ base::Unretained(this), id),
+ base::TimeDelta::FromSeconds(kApprovedStreamTimeToLiveSeconds));
+
+ return id;
+}
+
+DesktopMediaID DesktopStreamsRegistryImpl::RequestMediaForStreamId(
+ const std::string& id,
+ int render_process_id,
+ int render_frame_id,
+ const GURL& origin,
+ std::string* extension_name,
+ const DesktopStreamRegistryType type) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ StreamsMap::iterator it = approved_streams_.find(id);
+
+ // Verify that if there is a request with the specified ID it was created for
+ // the same origin and the same renderer.
+ if (it == approved_streams_.end() ||
+ render_process_id != it->second.render_process_id ||
+ render_frame_id != it->second.render_frame_id ||
+ origin != it->second.origin || type != it->second.type) {
+ return DesktopMediaID();
+ }
+
+ DesktopMediaID result = it->second.source;
+ if (extension_name) {
+ *extension_name = it->second.extension_name;
+ }
+ approved_streams_.erase(it);
+ return result;
+}
+
+void DesktopStreamsRegistryImpl::CleanupStream(const std::string& id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ approved_streams_.erase(id);
+}
+
+DesktopStreamsRegistryImpl::ApprovedDesktopMediaStream::
+ ApprovedDesktopMediaStream()
+ : render_process_id(-1), render_frame_id(-1) {}
+
+} // namespace content \ No newline at end of file
diff --git a/chromium/content/browser/media/capture/desktop_streams_registry_impl.h b/chromium/content/browser/media/capture/desktop_streams_registry_impl.h
new file mode 100644
index 00000000000..baa45e15439
--- /dev/null
+++ b/chromium/content/browser/media/capture/desktop_streams_registry_impl.h
@@ -0,0 +1,66 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_DESKTOP_STREAMS_REGISTRY_IMPL_H_
+#define CONTENT_BROWSER_MEDIA_CAPTURE_DESKTOP_STREAMS_REGISTRY_IMPL_H_
+
+#include <map>
+#include <string>
+
+#include "content/common/content_export.h"
+#include "content/public/browser/desktop_media_id.h"
+#include "content/public/browser/desktop_streams_registry.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class CONTENT_EXPORT DesktopStreamsRegistryImpl
+ : public DesktopStreamsRegistry {
+ public:
+ DesktopStreamsRegistryImpl();
+ ~DesktopStreamsRegistryImpl() override;
+
+ // Returns the DesktopStreamRegistryImpl singleton.
+ static DesktopStreamsRegistryImpl* GetInstance();
+
+ std::string RegisterStream(int render_process_id,
+ int render_frame_id,
+ const GURL& origin,
+ const DesktopMediaID& source,
+ const std::string& extension_name,
+ const DesktopStreamRegistryType type) override;
+
+ DesktopMediaID RequestMediaForStreamId(
+ const std::string& id,
+ int render_process_id,
+ int render_frame_id,
+ const GURL& origin,
+ std::string* extension_name,
+ const DesktopStreamRegistryType type) override;
+
+ private:
+ // Type used to store list of accepted desktop media streams.
+ struct ApprovedDesktopMediaStream {
+ ApprovedDesktopMediaStream();
+
+ int render_process_id;
+ int render_frame_id;
+ GURL origin;
+ DesktopMediaID source;
+ std::string extension_name;
+ DesktopStreamRegistryType type;
+ };
+ typedef std::map<std::string, ApprovedDesktopMediaStream> StreamsMap;
+
+ // Helper function that removes an expired stream from the registry.
+ void CleanupStream(const std::string& id);
+
+ StreamsMap approved_streams_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopStreamsRegistryImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_CAPTURE_DESKTOP_STREAMS_REGISTRY_IMPL_H_
diff --git a/chromium/content/browser/media/capture/fake_video_capture_stack.cc b/chromium/content/browser/media/capture/fake_video_capture_stack.cc
index 8bd1c9c1540..11429d03374 100644
--- a/chromium/content/browser/media/capture/fake_video_capture_stack.cc
+++ b/chromium/content/browser/media/capture/fake_video_capture_stack.cc
@@ -48,29 +48,28 @@ class FakeVideoCaptureStack::Receiver : public media::VideoFrameReceiver {
media::mojom::VideoFrameInfoPtr frame_info) final {
const auto it = buffers_.find(buffer_id);
CHECK(it != buffers_.end());
- CHECK(it->second->is_shared_buffer_handle());
- mojo::ScopedSharedBufferHandle& buffer =
- it->second->get_shared_buffer_handle();
- const size_t mapped_size =
- media::VideoCaptureFormat(frame_info->coded_size, 0.0f,
- frame_info->pixel_format)
- .ImageAllocationSize();
- mojo::ScopedSharedBufferMapping mapping = buffer->Map(mapped_size);
- CHECK(mapping.get());
+ CHECK(it->second->is_read_only_shmem_region());
+ base::ReadOnlySharedMemoryMapping mapping =
+ it->second->get_read_only_shmem_region().Map();
+ CHECK(mapping.IsValid());
+ CHECK_LE(media::VideoCaptureFormat(frame_info->coded_size, 0.0f,
+ frame_info->pixel_format)
+ .ImageAllocationSize(),
+ mapping.size());
auto frame = media::VideoFrame::WrapExternalData(
frame_info->pixel_format, frame_info->coded_size,
frame_info->visible_rect, frame_info->visible_rect.size(),
- reinterpret_cast<uint8_t*>(mapping.get()), mapped_size,
- frame_info->timestamp);
+ const_cast<uint8_t*>(static_cast<const uint8_t*>(mapping.memory())),
+ mapping.size(), frame_info->timestamp);
CHECK(frame);
frame->metadata()->MergeInternalValuesFrom(frame_info->metadata);
// This destruction observer will unmap the shared memory when the
// VideoFrame goes out-of-scope.
- frame->AddDestructionObserver(
- base::BindOnce(base::DoNothing::Once<mojo::ScopedSharedBufferMapping>(),
- std::move(mapping)));
+ frame->AddDestructionObserver(base::BindOnce(
+ base::DoNothing::Once<base::ReadOnlySharedMemoryMapping>(),
+ std::move(mapping)));
// This destruction observer will notify the video capture device once all
// downstream code is done using the VideoFrame.
frame->AddDestructionObserver(base::BindOnce(
@@ -86,7 +85,11 @@ class FakeVideoCaptureStack::Receiver : public media::VideoFrameReceiver {
buffers_.erase(it);
}
- void OnError() final { capture_stack_->error_occurred_ = true; }
+ void OnError(media::VideoCaptureError) final {
+ capture_stack_->error_occurred_ = true;
+ }
+
+ void OnFrameDropped(media::VideoCaptureFrameDropReason) final {}
void OnLog(const std::string& message) final {
capture_stack_->log_messages_.push_back(message);
diff --git a/chromium/content/browser/media/capture/frame_sink_video_capture_device.cc b/chromium/content/browser/media/capture/frame_sink_video_capture_device.cc
index e096bf8cc5b..cded50f3122 100644
--- a/chromium/content/browser/media/capture/frame_sink_video_capture_device.cc
+++ b/chromium/content/browser/media/capture/frame_sink_video_capture_device.cc
@@ -14,17 +14,20 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/numerics/safe_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "content/browser/compositor/surface_utils.h"
+#include "content/browser/media/capture/mouse_cursor_overlay_controller.h"
#include "media/base/bind_to_current_loop.h"
#include "media/capture/mojom/video_capture_types.mojom.h"
-#include "mojo/public/cpp/system/buffer.h"
namespace content {
namespace {
+constexpr int32_t kMouseCursorStackingIndex = 1;
+
// Transfers ownership of an object to a std::unique_ptr with a custom deleter
// that ensures the object is destroyed on the UI BrowserThread.
template <typename T>
@@ -49,10 +52,10 @@ class ScopedFrameDoneHelper
} // namespace
FrameSinkVideoCaptureDevice::FrameSinkVideoCaptureDevice()
- : cursor_renderer_(RescopeToUIThread(CursorRenderer::Create(
- CursorRenderer::CURSOR_DISPLAYED_ON_MOUSE_MOVEMENT))),
+ : cursor_controller_(
+ RescopeToUIThread(std::make_unique<MouseCursorOverlayController>())),
weak_factory_(this) {
- DCHECK(cursor_renderer_);
+ DCHECK(cursor_controller_);
}
FrameSinkVideoCaptureDevice::~FrameSinkVideoCaptureDevice() {
@@ -70,7 +73,8 @@ void FrameSinkVideoCaptureDevice::AllocateAndStartWithReceiver(
// If the device has already ended on a fatal error, abort immediately.
if (fatal_error_message_) {
receiver->OnLog(*fatal_error_message_);
- receiver->OnError();
+ receiver->OnError(media::VideoCaptureError::
+ kFrameSinkVideoCaptureDeviceAleradyEndedOnFatalError);
return;
}
@@ -79,17 +83,6 @@ void FrameSinkVideoCaptureDevice::AllocateAndStartWithReceiver(
DCHECK(!receiver_);
receiver_ = std::move(receiver);
- // Set a callback that will be run whenever the mouse moves, to trampoline
- // back to the device thread and request a refresh frame so that the new mouse
- // cursor location can be drawn in a new video frame.
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::BindOnce(&CursorRenderer::SetNeedsRedrawCallback,
- cursor_renderer_->GetWeakPtr(),
- media::BindToCurrentLoop(base::BindRepeating(
- &FrameSinkVideoCaptureDevice::RequestRefreshFrame,
- weak_factory_.GetWeakPtr()))));
-
// Shutdown the prior capturer, if any.
MaybeStopConsuming();
@@ -112,6 +105,13 @@ void FrameSinkVideoCaptureDevice::AllocateAndStartWithReceiver(
capturer_->ChangeTarget(target_);
}
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&MouseCursorOverlayController::Start,
+ cursor_controller_->GetWeakPtr(),
+ capturer_->CreateOverlay(kMouseCursorStackingIndex),
+ base::ThreadTaskRunnerHandle::Get()));
+
receiver_->OnStarted();
if (!suspend_requested_) {
@@ -153,11 +153,9 @@ void FrameSinkVideoCaptureDevice::Resume() {
void FrameSinkVideoCaptureDevice::StopAndDeAllocate() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- // Discontinue requesting extra video frames to render mouse cursor changes.
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::BindOnce(&CursorRenderer::SetNeedsRedrawCallback,
- cursor_renderer_->GetWeakPtr(), base::RepeatingClosure()));
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&MouseCursorOverlayController::Stop,
+ cursor_controller_->GetWeakPtr()));
MaybeStopConsuming();
capturer_.reset();
@@ -171,17 +169,16 @@ void FrameSinkVideoCaptureDevice::OnUtilizationReport(int frame_feedback_id,
double utilization) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- // Assumption: The "slot" should be valid at this point because this method
- // will always be called before the VideoFrameReceiver signals it is done
- // consuming the frame.
- const auto slot_index = static_cast<size_t>(frame_feedback_id);
- DCHECK_LT(slot_index, slots_.size());
- slots_[slot_index].callbacks->ProvideFeedback(utilization);
+ // Assumption: The mojo InterfacePtr in |frame_callbacks_| should be valid at
+ // this point because this method will always be called before the
+ // VideoFrameReceiver signals it is done consuming the frame.
+ const auto index = static_cast<size_t>(frame_feedback_id);
+ DCHECK_LT(index, frame_callbacks_.size());
+ frame_callbacks_[index]->ProvideFeedback(utilization);
}
void FrameSinkVideoCaptureDevice::OnFrameCaptured(
- mojo::ScopedSharedBufferHandle buffer,
- uint32_t buffer_size,
+ base::ReadOnlySharedMemoryRegion data,
media::mojom::VideoFrameInfoPtr info,
const gfx::Rect& update_rect,
const gfx::Rect& content_rect,
@@ -189,72 +186,50 @@ void FrameSinkVideoCaptureDevice::OnFrameCaptured(
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(callbacks);
- if (!receiver_ || !buffer.is_valid()) {
+ if (!receiver_ || !data.IsValid()) {
callbacks->Done();
return;
}
- // Search for the next available ConsumptionState slot and bind |callbacks|
- // there.
- size_t slot_index = 0;
- for (;; ++slot_index) {
- if (slot_index == slots_.size()) {
- // The growth of |slots_| should be bounded because the
+ // Search for the next available element in |frame_callbacks_| and bind
+ // |callbacks| there.
+ size_t index = 0;
+ for (;; ++index) {
+ if (index == frame_callbacks_.size()) {
+ // The growth of |frame_callbacks_| should be bounded because the
// viz::mojom::FrameSinkVideoCapturer should enforce an upper-bound on the
// number of frames in-flight.
constexpr size_t kMaxInFlightFrames = 32; // Arbitrarily-chosen limit.
- DCHECK_LT(slots_.size(), kMaxInFlightFrames);
- slots_.emplace_back();
+ DCHECK_LT(frame_callbacks_.size(), kMaxInFlightFrames);
+ frame_callbacks_.emplace_back(std::move(callbacks));
break;
}
- if (!slots_[slot_index].callbacks.is_bound()) {
+ if (!frame_callbacks_[index].is_bound()) {
+ frame_callbacks_[index] = std::move(callbacks);
break;
}
}
- ConsumptionState& slot = slots_[slot_index];
- slot.callbacks = std::move(callbacks);
-
- // Render the mouse cursor on the video frame, but first map the shared memory
- // into the current process in order to render the cursor.
- mojo::ScopedSharedBufferMapping mapping = buffer->Map(buffer_size);
- scoped_refptr<media::VideoFrame> frame;
- if (mapping) {
- frame = media::VideoFrame::WrapExternalData(
- info->pixel_format, info->coded_size, info->visible_rect,
- info->visible_rect.size(), static_cast<uint8_t*>(mapping.get()),
- buffer_size, info->timestamp);
- if (frame) {
- frame->AddDestructionObserver(base::BindOnce(
- [](mojo::ScopedSharedBufferMapping mapping) {}, std::move(mapping)));
- if (!cursor_renderer_->RenderOnVideoFrame(frame.get(), content_rect,
- &slot.undoer)) {
- // Release |frame| now, since no "undo cursor rendering" will be needed.
- frame = nullptr;
- }
- }
- }
+ const BufferId buffer_id = static_cast<BufferId>(index);
// Set the INTERACTIVE_CONTENT frame metadata.
media::VideoFrameMetadata modified_metadata;
modified_metadata.MergeInternalValuesFrom(info->metadata);
modified_metadata.SetBoolean(media::VideoFrameMetadata::INTERACTIVE_CONTENT,
- cursor_renderer_->IsUserInteractingWithView());
+ cursor_controller_->IsUserInteractingWithView());
info->metadata = modified_metadata.GetInternalValues().Clone();
// Pass the video frame to the VideoFrameReceiver. This is done by first
// passing the shared memory buffer handle and then notifying it that a new
// frame is ready to be read from the buffer.
- media::mojom::VideoBufferHandlePtr buffer_handle =
- media::mojom::VideoBufferHandle::New();
- buffer_handle->set_shared_buffer_handle(std::move(buffer));
- receiver_->OnNewBuffer(static_cast<BufferId>(slot_index),
- std::move(buffer_handle));
+ receiver_->OnNewBuffer(
+ buffer_id,
+ media::mojom::VideoBufferHandle::NewReadOnlyShmemRegion(std::move(data)));
receiver_->OnFrameReadyInBuffer(
- static_cast<BufferId>(slot_index), slot_index,
+ buffer_id, buffer_id,
std::make_unique<ScopedFrameDoneHelper>(
media::BindToCurrentLoop(base::BindOnce(
&FrameSinkVideoCaptureDevice::OnFramePropagationComplete,
- weak_factory_.GetWeakPtr(), slot_index, std::move(frame)))),
+ weak_factory_.GetWeakPtr(), buffer_id))),
std::move(info));
}
@@ -333,26 +308,20 @@ void FrameSinkVideoCaptureDevice::MaybeStopConsuming() {
}
void FrameSinkVideoCaptureDevice::OnFramePropagationComplete(
- size_t slot_index,
- scoped_refptr<media::VideoFrame> frame) {
+ BufferId buffer_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK_LT(slot_index, slots_.size());
// Notify the VideoFrameReceiver that the buffer is no longer valid.
if (receiver_) {
- receiver_->OnBufferRetired(static_cast<BufferId>(slot_index));
- }
-
- // Undo the mouse cursor rendering, if any.
- ConsumptionState& slot = slots_[slot_index];
- if (frame) {
- slot.undoer.Undo(frame.get());
- frame = nullptr;
+ receiver_->OnBufferRetired(buffer_id);
}
// Notify the capturer that consumption of the frame is complete.
- slot.callbacks->Done();
- slot.callbacks.reset();
+ const size_t index = static_cast<size_t>(buffer_id);
+ DCHECK_LT(index, frame_callbacks_.size());
+ auto& callbacks_ptr = frame_callbacks_[index];
+ callbacks_ptr->Done();
+ callbacks_ptr.reset();
}
void FrameSinkVideoCaptureDevice::OnFatalError(std::string message) {
@@ -361,18 +330,11 @@ void FrameSinkVideoCaptureDevice::OnFatalError(std::string message) {
fatal_error_message_ = std::move(message);
if (receiver_) {
receiver_->OnLog(*fatal_error_message_);
- receiver_->OnError();
+ receiver_->OnError(media::VideoCaptureError::
+ kFrameSinkVideoCaptureDeviceEncounteredFatalError);
}
StopAndDeAllocate();
}
-FrameSinkVideoCaptureDevice::ConsumptionState::ConsumptionState() = default;
-FrameSinkVideoCaptureDevice::ConsumptionState::~ConsumptionState() = default;
-FrameSinkVideoCaptureDevice::ConsumptionState::ConsumptionState(
- FrameSinkVideoCaptureDevice::ConsumptionState&& other) noexcept = default;
-FrameSinkVideoCaptureDevice::ConsumptionState&
-FrameSinkVideoCaptureDevice::ConsumptionState::operator=(
- FrameSinkVideoCaptureDevice::ConsumptionState&& other) noexcept = default;
-
} // namespace content
diff --git a/chromium/content/browser/media/capture/frame_sink_video_capture_device.h b/chromium/content/browser/media/capture/frame_sink_video_capture_device.h
index 341248435ea..7a58699fbb2 100644
--- a/chromium/content/browser/media/capture/frame_sink_video_capture_device.h
+++ b/chromium/content/browser/media/capture/frame_sink_video_capture_device.h
@@ -16,7 +16,6 @@
#include "base/sequence_checker.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/host/client_frame_sink_video_capturer.h"
-#include "content/browser/media/capture/cursor_renderer.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_thread.h"
#include "media/base/video_frame.h"
@@ -27,6 +26,8 @@
namespace content {
+class MouseCursorOverlayController;
+
// A virtualized VideoCaptureDevice that captures the displayed contents of a
// frame sink (see viz::CompositorFrameSink), such as the composited main view
// of a WebContents instance, producing a stream of video frames.
@@ -72,8 +73,7 @@ class CONTENT_EXPORT FrameSinkVideoCaptureDevice
// FrameSinkVideoConsumer implementation.
void OnFrameCaptured(
- mojo::ScopedSharedBufferHandle buffer,
- uint32_t buffer_size,
+ base::ReadOnlySharedMemoryRegion data,
media::mojom::VideoFrameInfoPtr info,
const gfx::Rect& update_rect,
const gfx::Rect& content_rect,
@@ -86,7 +86,9 @@ class CONTENT_EXPORT FrameSinkVideoCaptureDevice
void OnTargetPermanentlyLost();
protected:
- CursorRenderer* cursor_renderer() const { return cursor_renderer_.get(); }
+ MouseCursorOverlayController* cursor_controller() const {
+ return cursor_controller_.get();
+ }
// Subclasses override these to perform additional start/stop tasks.
virtual void WillStart();
@@ -112,10 +114,8 @@ class CONTENT_EXPORT FrameSinkVideoCaptureDevice
// If consuming, shut it down.
void MaybeStopConsuming();
- // Undoes mouse cursor rendering and notifies the capturer that consumption of
- // the frame is complete.
- void OnFramePropagationComplete(size_t slot_index,
- scoped_refptr<media::VideoFrame> frame);
+ // Notifies the capturer that consumption of the frame is complete.
+ void OnFramePropagationComplete(BufferId buffer_id);
// Helper that logs the given error |message| to the |receiver_| and then
// stops capture and this VideoCaptureDevice.
@@ -140,18 +140,13 @@ class CONTENT_EXPORT FrameSinkVideoCaptureDevice
std::unique_ptr<viz::ClientFrameSinkVideoCapturer> capturer_;
- // A pool of structs that hold state relevant to frames currently being
- // processed by VideoFrameReceiver. Each "slot" is re-used by later frames.
- struct ConsumptionState {
- viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks;
- CursorRendererUndoer undoer;
-
- ConsumptionState();
- ~ConsumptionState();
- ConsumptionState(ConsumptionState&& other) noexcept;
- ConsumptionState& operator=(ConsumptionState&& other) noexcept;
- };
- std::vector<ConsumptionState> slots_;
+ // A vector that holds the "callbacks" mojo InterfacePtr for each frame while
+ // the frame is being processed by VideoFrameReceiver. The index corresponding
+ // to a particular frame is used as the BufferId passed to VideoFrameReceiver.
+ // Therefore, non-null pointers in this vector must never move to a different
+ // position.
+ std::vector<viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr>
+ frame_callbacks_;
// Set when OnFatalError() is called. This prevents any future
// AllocateAndStartWithReceiver() calls from succeeding.
@@ -159,9 +154,10 @@ class CONTENT_EXPORT FrameSinkVideoCaptureDevice
SEQUENCE_CHECKER(sequence_checker_);
- // Renders the mouse cursor on each video frame.
- const std::unique_ptr<CursorRenderer, BrowserThread::DeleteOnUIThread>
- cursor_renderer_;
+ // Controls the overlay that renders the mouse cursor onto each video frame.
+ const std::unique_ptr<MouseCursorOverlayController,
+ BrowserThread::DeleteOnUIThread>
+ cursor_controller_;
// Creates WeakPtrs for use on the device thread.
base::WeakPtrFactory<FrameSinkVideoCaptureDevice> weak_factory_;
diff --git a/chromium/content/browser/media/capture/frame_sink_video_capture_device_unittest.cc b/chromium/content/browser/media/capture/frame_sink_video_capture_device_unittest.cc
index d8de88d4e46..341c3a04df6 100644
--- a/chromium/content/browser/media/capture/frame_sink_video_capture_device_unittest.cc
+++ b/chromium/content/browser/media/capture/frame_sink_video_capture_device_unittest.cc
@@ -9,11 +9,14 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/containers/flat_map.h"
+#include "base/memory/read_only_shared_memory_region.h"
+#include "base/memory/shared_memory_mapping.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_utils.h"
#include "media/base/video_frame.h"
#include "media/capture/video/video_frame_receiver.h"
#include "media/capture/video_capture_types.h"
+#include "mojo/public/cpp/base/shared_memory_utils.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/viz/privileged/interfaces/compositing/frame_sink_video_capture.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -110,6 +113,9 @@ class MockFrameSinkVideoCapturer : public viz::mojom::FrameSinkVideoCapturer {
}
MOCK_METHOD0(MockStop, void());
MOCK_METHOD0(RequestRefreshFrame, void());
+ MOCK_METHOD2(CreateOverlay,
+ void(int32_t stacking_index,
+ viz::mojom::FrameSinkVideoCaptureOverlayRequest request));
private:
mojo::Binding<viz::mojom::FrameSinkVideoCapturer> binding_;
@@ -181,20 +187,21 @@ class MockVideoFrameReceiver : public media::VideoFrameReceiver {
Buffer::ScopedAccessPermission* buffer_read_permission,
const media::mojom::VideoFrameInfo* frame_info));
MOCK_METHOD1(OnBufferRetired, void(int buffer_id));
- MOCK_METHOD0(OnError, void());
+ MOCK_METHOD1(OnError, void(media::VideoCaptureError error));
+ MOCK_METHOD1(OnFrameDropped, void(media::VideoCaptureFrameDropReason reason));
MOCK_METHOD1(OnLog, void(const std::string& message));
MOCK_METHOD0(OnStarted, void());
void OnStartedUsingGpuDecode() final { NOTREACHED(); }
- mojo::ScopedSharedBufferHandle TakeBufferHandle(int buffer_id) {
+ base::ReadOnlySharedMemoryRegion TakeBufferHandle(int buffer_id) {
DCHECK_NOT_ON_DEVICE_THREAD();
const auto it = buffer_handles_.find(buffer_id);
if (it == buffer_handles_.end()) {
ADD_FAILURE() << "Missing entry for buffer_id=" << buffer_id;
- return mojo::ScopedSharedBufferHandle();
+ return base::ReadOnlySharedMemoryRegion();
}
- CHECK(it->second->is_shared_buffer_handle());
- auto buffer = std::move(it->second->get_shared_buffer_handle());
+ CHECK(it->second->is_read_only_shmem_region());
+ auto buffer = std::move(it->second->get_read_only_shmem_region());
buffer_handles_.erase(it);
return buffer;
}
@@ -343,12 +350,11 @@ class FrameSinkVideoCaptureDeviceTest : public testing::Test {
int frame_number,
MockFrameSinkVideoConsumerFrameCallbacks* callbacks) {
// Allocate a buffer and fill it with values based on |frame_number|.
- const size_t buffer_size =
- media::VideoFrame::AllocationSize(kFormat, kResolution);
- mojo::ScopedSharedBufferHandle buffer =
- mojo::SharedBufferHandle::Create(buffer_size);
- memset(buffer->Map(buffer_size).get(), GetFrameFillValue(frame_number),
- buffer_size);
+ base::MappedReadOnlyRegion region = mojo::CreateReadOnlySharedMemoryRegion(
+ media::VideoFrame::AllocationSize(kFormat, kResolution));
+ CHECK(region.IsValid());
+ memset(region.mapping.memory(), GetFrameFillValue(frame_number),
+ region.mapping.size());
viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks_ptr;
callbacks->Bind(mojo::MakeRequest(&callbacks_ptr));
@@ -356,13 +362,12 @@ class FrameSinkVideoCaptureDeviceTest : public testing::Test {
// to the device thread before calling OnFrameCaptured().
POST_DEVICE_TASK(base::BindOnce(
[](FrameSinkVideoCaptureDevice* device,
- mojo::ScopedSharedBufferHandle buffer, size_t buffer_size,
- int frame_number,
+ base::ReadOnlySharedMemoryRegion data, int frame_number,
mojo::InterfacePtrInfo<
viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks_info) {
device->OnFrameCaptured(
- std::move(buffer), buffer_size,
+ std::move(data),
media::mojom::VideoFrameInfo::New(
kMinCapturePeriod * frame_number,
base::Value(base::Value::Type::DICTIONARY), kFormat,
@@ -371,8 +376,8 @@ class FrameSinkVideoCaptureDeviceTest : public testing::Test {
viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr(
std::move(callbacks_info)));
},
- base::Unretained(device_.get()), std::move(buffer), buffer_size,
- frame_number, callbacks_ptr.PassInterface()));
+ base::Unretained(device_.get()), std::move(region.region), frame_number,
+ callbacks_ptr.PassInterface()));
}
// Returns a byte value based on the given |frame_number|.
@@ -384,13 +389,14 @@ class FrameSinkVideoCaptureDeviceTest : public testing::Test {
// given |frame_number|.
static bool IsExpectedBufferContentForFrame(
int frame_number,
- mojo::ScopedSharedBufferHandle buffer) {
- const size_t buffer_size =
+ base::ReadOnlySharedMemoryRegion buffer) {
+ const auto mapping = buffer.Map();
+ const size_t frame_allocation_size =
media::VideoFrame::AllocationSize(kFormat, kResolution);
- const auto mapping = buffer->Map(buffer_size);
- const uint8_t* src = static_cast<uint8_t*>(mapping.get());
+ CHECK_LE(frame_allocation_size, mapping.size());
+ const uint8_t* src = mapping.GetMemoryAs<const uint8_t>();
const uint8_t expected_value = GetFrameFillValue(frame_number);
- for (size_t i = 0; i < buffer_size; ++i) {
+ for (size_t i = 0; i < frame_allocation_size; ++i) {
if (src[i] != expected_value) {
return false;
}
@@ -413,7 +419,7 @@ TEST_F(FrameSinkVideoCaptureDeviceTest, CapturesAndDeliversFrames) {
auto receiver_ptr = std::make_unique<MockVideoFrameReceiver>();
auto* const receiver = receiver_ptr.get();
EXPECT_CALL(*receiver, OnStarted());
- EXPECT_CALL(*receiver, OnError()).Times(0);
+ EXPECT_CALL(*receiver, OnError(_)).Times(0);
AllocateAndStartSynchronouslyWithExpectations(std::move(receiver_ptr));
// From this point, there is no reason the capturer should be re-started.
@@ -454,7 +460,7 @@ TEST_F(FrameSinkVideoCaptureDeviceTest, CapturesAndDeliversFrames) {
const int buffer_id = buffer_ids[frame_number - first_frame_number];
auto buffer = receiver->TakeBufferHandle(buffer_id);
- ASSERT_TRUE(buffer.is_valid());
+ ASSERT_TRUE(buffer.IsValid());
EXPECT_TRUE(
IsExpectedBufferContentForFrame(frame_number, std::move(buffer)));
@@ -552,7 +558,7 @@ TEST_F(FrameSinkVideoCaptureDeviceTest, ShutsDownOnFatalError) {
Sequence sequence;
EXPECT_CALL(*receiver, OnStarted()).InSequence(sequence);
EXPECT_CALL(*receiver, OnLog(StrNe(""))).InSequence(sequence);
- EXPECT_CALL(*receiver, OnError()).InSequence(sequence);
+ EXPECT_CALL(*receiver, OnError(_)).InSequence(sequence);
AllocateAndStartSynchronouslyWithExpectations(std::move(receiver_ptr));
@@ -578,7 +584,7 @@ TEST_F(FrameSinkVideoCaptureDeviceTest, ShutsDownOnFatalError) {
{
EXPECT_CALL(*receiver, OnStarted()).Times(0);
EXPECT_CALL(*receiver, OnLog(StrNe("")));
- EXPECT_CALL(*receiver, OnError());
+ EXPECT_CALL(*receiver, OnError(_));
EXPECT_CALL(capturer_, MockStart(_)).Times(0);
POST_DEVICE_METHOD_CALL(AllocateAndStartWithReceiver, GetCaptureParams(),
diff --git a/chromium/content/browser/media/capture/lame_capture_overlay_chromeos.cc b/chromium/content/browser/media/capture/lame_capture_overlay_chromeos.cc
new file mode 100644
index 00000000000..1c6f0aff99f
--- /dev/null
+++ b/chromium/content/browser/media/capture/lame_capture_overlay_chromeos.cc
@@ -0,0 +1,178 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/capture/lame_capture_overlay_chromeos.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "base/numerics/safe_conversions.h"
+#include "content/browser/media/capture/lame_window_capturer_chromeos.h"
+#include "media/base/video_frame.h"
+#include "skia/ext/image_operations.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace content {
+
+LameCaptureOverlayChromeOS::Owner::~Owner() = default;
+
+LameCaptureOverlayChromeOS::LameCaptureOverlayChromeOS(
+ Owner* owner,
+ viz::mojom::FrameSinkVideoCaptureOverlayRequest request)
+ : binding_(this, std::move(request)) {
+ if (owner) {
+ binding_.set_connection_error_handler(base::BindOnce(
+ &Owner::OnOverlayConnectionLost, base::Unretained(owner), this));
+ }
+}
+
+LameCaptureOverlayChromeOS::~LameCaptureOverlayChromeOS() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void LameCaptureOverlayChromeOS::SetImageAndBounds(const SkBitmap& image,
+ const gfx::RectF& bounds) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ image_ = image;
+ bounds_ = bounds;
+ cached_scaled_image_.reset();
+}
+
+void LameCaptureOverlayChromeOS::SetBounds(const gfx::RectF& bounds) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (bounds != bounds_) {
+ bounds_ = bounds;
+ cached_scaled_image_.reset();
+ }
+}
+
+namespace {
+
+// Scales a |relative| rect having coordinates in the range [0.0,1.0) by the
+// given |span|, snapping all coordinates to even numbers.
+gfx::Rect ToAbsoluteBoundsForI420(const gfx::RectF& relative,
+ const gfx::Rect& span) {
+ const float absolute_left = std::fma(relative.x(), span.width(), span.x());
+ const float absolute_top = std::fma(relative.y(), span.height(), span.y());
+ const float absolute_right =
+ std::fma(relative.right(), span.width(), span.x());
+ const float absolute_bottom =
+ std::fma(relative.bottom(), span.height(), span.y());
+
+ // Compute the largest I420-friendly Rect that is fully-enclosed by the
+ // absolute rect. Use saturated_cast<> to restrict all extreme results [and
+ // Inf and NaN] to a safe range of integers.
+ const int snapped_left =
+ base::saturated_cast<int16_t>(std::ceil(absolute_left / 2.0f)) * 2;
+ const int snapped_top =
+ base::saturated_cast<int16_t>(std::ceil(absolute_top / 2.0f)) * 2;
+ const int snapped_right =
+ base::saturated_cast<int16_t>(std::floor(absolute_right / 2.0f)) * 2;
+ const int snapped_bottom =
+ base::saturated_cast<int16_t>(std::floor(absolute_bottom / 2.0f)) * 2;
+ return gfx::Rect(snapped_left, snapped_top,
+ std::max(0, snapped_right - snapped_left),
+ std::max(0, snapped_bottom - snapped_top));
+}
+
+inline int clip_byte(int x) {
+ return std::max(0, std::min(x, 255));
+}
+
+inline int alpha_blend(int alpha, int src, int dst) {
+ return (src * alpha + dst * (255 - alpha)) / 255;
+}
+
+} // namespace
+
+LameCaptureOverlayChromeOS::OnceRenderer
+LameCaptureOverlayChromeOS::MakeRenderer(const gfx::Rect& region_in_frame) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (bounds_.IsEmpty() || image_.drawsNothing()) {
+ return OnceRenderer();
+ }
+
+ // Determine the bounds of the overlay inside the video frame. The
+ // calculations here align to the 2x2 pixel-quads to simplify later
+ // implementation.
+ const gfx::Rect bounds_in_frame =
+ ToAbsoluteBoundsForI420(bounds_, region_in_frame);
+
+ // Compute the region of the frame to be modified.
+ gfx::Rect blit_rect = region_in_frame;
+ blit_rect.Intersect(bounds_in_frame);
+ // If the two rects didn't intersect at all (i.e., everything has been
+ // clipped), punt.
+ if (blit_rect.IsEmpty()) {
+ return OnceRenderer();
+ }
+
+ if (cached_scaled_image_.drawsNothing() ||
+ cached_scaled_image_.width() != bounds_in_frame.width() ||
+ cached_scaled_image_.height() != bounds_in_frame.height()) {
+ cached_scaled_image_ = skia::ImageOperations::Resize(
+ image_, skia::ImageOperations::RESIZE_BETTER, bounds_in_frame.width(),
+ bounds_in_frame.height());
+ }
+
+ // The following binds all state required to render the overlay on a
+ // VideoFrame at a later time. This callback does not require
+ // LameCaptureOverlayChromeOS to outlive it.
+ return base::BindOnce(
+ [](const SkBitmap& image, const gfx::Point& position,
+ const gfx::Rect& rect, media::VideoFrame* frame) {
+ DCHECK(frame);
+ DCHECK_EQ(frame->format(), media::PIXEL_FORMAT_I420);
+ DCHECK(frame->visible_rect().Contains(rect));
+
+ // Render the overlay in the video frame. This loop also performs a
+ // simple RGB→YUV color space conversion, with alpha-blended
+ // compositing.
+ for (int y = rect.y(); y < rect.bottom(); ++y) {
+ const int source_row = y - position.y();
+ uint8_t* const yplane =
+ frame->visible_data(media::VideoFrame::kYPlane) +
+ y * frame->stride(media::VideoFrame::kYPlane);
+ uint8_t* const uplane =
+ frame->visible_data(media::VideoFrame::kUPlane) +
+ (y / 2) * frame->stride(media::VideoFrame::kUPlane);
+ uint8_t* const vplane =
+ frame->visible_data(media::VideoFrame::kVPlane) +
+ (y / 2) * frame->stride(media::VideoFrame::kVPlane);
+ for (int x = rect.x(); x < rect.right(); ++x) {
+ const int source_col = x - position.x();
+ const SkColor color = image.getColor(source_col, source_row);
+ const int alpha = SkColorGetA(color);
+ const int color_r = SkColorGetR(color);
+ const int color_g = SkColorGetG(color);
+ const int color_b = SkColorGetB(color);
+ const int color_y =
+ ((color_r * 66 + color_g * 129 + color_b * 25 + 128) >> 8) + 16;
+ yplane[x] = clip_byte(alpha_blend(alpha, color_y, yplane[x]));
+
+ // Only sample U and V at even coordinates.
+ if ((x % 2 == 0) && (y % 2 == 0)) {
+ const int color_u =
+ ((color_r * -38 + color_g * -74 + color_b * 112 + 128) >> 8) +
+ 128;
+ const int color_v =
+ ((color_r * 112 + color_g * -94 + color_b * -18 + 128) >> 8) +
+ 128;
+ uplane[x / 2] =
+ clip_byte(alpha_blend(alpha, color_u, uplane[x / 2]));
+ vplane[x / 2] =
+ clip_byte(alpha_blend(alpha, color_v, vplane[x / 2]));
+ }
+ }
+ }
+ },
+ cached_scaled_image_, bounds_in_frame.origin(), blit_rect);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/capture/lame_capture_overlay_chromeos.h b/chromium/content/browser/media/capture/lame_capture_overlay_chromeos.h
new file mode 100644
index 00000000000..b153728c987
--- /dev/null
+++ b/chromium/content/browser/media/capture/lame_capture_overlay_chromeos.h
@@ -0,0 +1,88 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_LAME_CAPTURE_OVERLAY_CHROMEOS_H_
+#define CONTENT_BROWSER_MEDIA_CAPTURE_LAME_CAPTURE_OVERLAY_CHROMEOS_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/sequence_checker.h"
+#include "content/common/content_export.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/viz/privileged/interfaces/compositing/frame_sink_video_capture.mojom.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace media {
+class VideoFrame;
+}
+
+namespace content {
+
+// A minimal FrameSinkVideoCaptureOverlay implementation for aura::Window video
+// capture on ChromeOS (i.e., not desktop capture, and not WebContents capture).
+// See class comments for LameWindowCapturerChromeOS for further details on why
+// this exists and why this placeholder is needed for now.
+//
+// The implementation here is a hodgepodge of code borrowed from
+// viz::VideoCaptureOverlay and the legacy content::CursorRenderer. Like its
+// full-featured VIZ cousin, it will cache the scaled version of the bitmap, and
+// re-use it across multiple frames. However, the rest of the rendering impl is
+// overly-simplified, sufferring from color accuracy and image sampling issues.
+// However, its quality is sufficient for its main use as a mouse cursor
+// renderer.
+//
+// TODO(crbug/806366): The goal is to remove this code by 2019.
+class CONTENT_EXPORT LameCaptureOverlayChromeOS
+ : public viz::mojom::FrameSinkVideoCaptureOverlay {
+ public:
+ // Implemented by LameWindowCapturerChromeOS.
+ class CONTENT_EXPORT Owner {
+ public:
+ // Called to notify that the |overlay| has lost its mojo binding. The owner
+ // will usually delete it during this method call.
+ virtual void OnOverlayConnectionLost(
+ LameCaptureOverlayChromeOS* overlay) = 0;
+
+ protected:
+ virtual ~Owner();
+ };
+
+ // A OnceCallback that, when run, renders the overlay on a VideoFrame.
+ using OnceRenderer = base::OnceCallback<void(media::VideoFrame*)>;
+
+ LameCaptureOverlayChromeOS(
+ Owner* owner,
+ viz::mojom::FrameSinkVideoCaptureOverlayRequest request);
+ ~LameCaptureOverlayChromeOS() final;
+
+ // viz::mojom::FrameSinkVideoCaptureOverlay implementation.
+ void SetImageAndBounds(const SkBitmap& image, const gfx::RectF& bounds) final;
+ void SetBounds(const gfx::RectF& bounds) final;
+
+ // Returns a OnceCallback that, when run, renders this overlay on an
+ // I420-format VideoFrame. The overlay's position and size are computed based
+ // on the given content |region_in_frame|. Returns a null OnceCallback if
+ // there is nothing to render at this time.
+ OnceRenderer MakeRenderer(const gfx::Rect& region_in_frame);
+
+ private:
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ mojo::Binding<viz::mojom::FrameSinkVideoCaptureOverlay> binding_;
+
+ SkBitmap image_;
+ gfx::RectF bounds_;
+
+ // The scaled |image_| used in the last call to MakeRenderer(). This is reset
+ // and re-generated whenever: a) the |image_| changes, or b) the required
+ // bitmap size changes.
+ SkBitmap cached_scaled_image_;
+
+ DISALLOW_COPY_AND_ASSIGN(LameCaptureOverlayChromeOS);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_CAPTURE_LAME_CAPTURE_OVERLAY_CHROMEOS_H_
diff --git a/chromium/content/browser/media/capture/lame_capture_overlay_chromeos_unittest.cc b/chromium/content/browser/media/capture/lame_capture_overlay_chromeos_unittest.cc
new file mode 100644
index 00000000000..4af85e5e38a
--- /dev/null
+++ b/chromium/content/browser/media/capture/lame_capture_overlay_chromeos_unittest.cc
@@ -0,0 +1,174 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/capture/lame_capture_overlay_chromeos.h"
+
+#include <stdint.h>
+
+#include <memory>
+#include <utility>
+
+#include "base/test/scoped_task_environment.h"
+#include "base/time/time.h"
+#include "media/base/video_frame.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace content {
+namespace {
+
+constexpr gfx::Size kFrameSize = gfx::Size(320, 200);
+constexpr gfx::Rect kContentRegion = gfx::Rect(kFrameSize);
+constexpr gfx::RectF kSpanOfEntireFrame = gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f);
+
+class LameCaptureOverlayChromeOSTest : public testing::Test {
+ public:
+ void RunUntilIdle() { env_.RunUntilIdle(); }
+
+ // Returns a 32x32 bitmap filled with red.
+ static SkBitmap CreateTestBitmap() {
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(32, 32);
+ CHECK(!bitmap.isNull());
+ bitmap.eraseColor(SK_ColorRED);
+ return bitmap;
+ }
+
+ // Returns true if there are any non-zero pixels in the region |rect| within
+ // |frame|.
+ static bool NonZeroPixelsInRegion(const media::VideoFrame* frame,
+ const gfx::Rect& rect) {
+ bool y_found = false, u_found = false, v_found = false;
+ for (int y = rect.y(); y < rect.bottom(); ++y) {
+ auto* const yplane = frame->visible_data(media::VideoFrame::kYPlane) +
+ y * frame->stride(media::VideoFrame::kYPlane);
+ auto* const uplane = frame->visible_data(media::VideoFrame::kUPlane) +
+ (y / 2) * frame->stride(media::VideoFrame::kUPlane);
+ auto* const vplane = frame->visible_data(media::VideoFrame::kVPlane) +
+ (y / 2) * frame->stride(media::VideoFrame::kVPlane);
+ for (int x = rect.x(); x < rect.right(); ++x) {
+ if (yplane[x] != 0)
+ y_found = true;
+ if (uplane[x / 2])
+ u_found = true;
+ if (vplane[x / 2])
+ v_found = true;
+ }
+ }
+ return (y_found && u_found && v_found);
+ }
+
+ private:
+ base::test::ScopedTaskEnvironment env_;
+};
+
+TEST_F(LameCaptureOverlayChromeOSTest, UnsetImageNotRenderedOnFrame) {
+ LameCaptureOverlayChromeOS overlay(
+ nullptr, viz::mojom::FrameSinkVideoCaptureOverlayRequest());
+
+ // Bounds set, but no image. → Should not render anything.
+ overlay.SetBounds(kSpanOfEntireFrame);
+ EXPECT_FALSE(overlay.MakeRenderer(kContentRegion));
+
+ // Both image and bounds set. → Should render something.
+ overlay.SetImageAndBounds(CreateTestBitmap(), kSpanOfEntireFrame);
+ EXPECT_TRUE(overlay.MakeRenderer(kContentRegion));
+}
+
+TEST_F(LameCaptureOverlayChromeOSTest, HiddenImageNotRenderedOnFrame) {
+ LameCaptureOverlayChromeOS overlay(
+ nullptr, viz::mojom::FrameSinkVideoCaptureOverlayRequest());
+
+ // Both image and bounds set. → Should render something.
+ overlay.SetImageAndBounds(CreateTestBitmap(), kSpanOfEntireFrame);
+ EXPECT_TRUE(overlay.MakeRenderer(kContentRegion));
+
+ // Bounds set to empty. → Should render nothing.
+ overlay.SetBounds(gfx::RectF());
+ EXPECT_FALSE(overlay.MakeRenderer(kContentRegion));
+}
+
+TEST_F(LameCaptureOverlayChromeOSTest, OutOfBoundsOverlayNotRenderedOnFrame) {
+ LameCaptureOverlayChromeOS overlay(
+ nullptr, viz::mojom::FrameSinkVideoCaptureOverlayRequest());
+
+ // Both image and bounds set. → Should render something.
+ overlay.SetImageAndBounds(CreateTestBitmap(), kSpanOfEntireFrame);
+ EXPECT_TRUE(overlay.MakeRenderer(kContentRegion));
+
+ // Move overlay to above and left of content area. → Should render nothing.
+ overlay.SetBounds(gfx::RectF(-0.5f, -0.5f, 0.25f, 0.25f));
+ EXPECT_FALSE(overlay.MakeRenderer(kContentRegion));
+}
+
+TEST_F(LameCaptureOverlayChromeOSTest, ImageRenderedOnFrame) {
+ LameCaptureOverlayChromeOS overlay(
+ nullptr, viz::mojom::FrameSinkVideoCaptureOverlayRequest());
+
+ // Create blank black frame. No non-zero pixels should be present.
+ const auto frame = media::VideoFrame::CreateZeroInitializedFrame(
+ media::PIXEL_FORMAT_I420, kFrameSize, gfx::Rect(kFrameSize), kFrameSize,
+ base::TimeDelta());
+ ASSERT_FALSE(NonZeroPixelsInRegion(frame.get(), frame->visible_rect()));
+
+ // Set image and bounds to a location in the lower-right quadrant of the
+ // frame.
+ const gfx::RectF bounds(0.8f, 0.8f, 0.1f, 0.1f);
+ overlay.SetImageAndBounds(CreateTestBitmap(), bounds);
+
+ // Render the overlay in the VideoFrame.
+ auto renderer = overlay.MakeRenderer(kContentRegion);
+ ASSERT_TRUE(renderer);
+ std::move(renderer).Run(frame.get());
+
+ // Check that there are non-zero pixels present in the modified region.
+ const gfx::Rect mutated_region = gfx::ToEnclosingRect(
+ gfx::ScaleRect(bounds, kContentRegion.width(), kContentRegion.height()));
+ EXPECT_TRUE(NonZeroPixelsInRegion(frame.get(), mutated_region));
+
+ // Check that there are no non-zero pixels present in the rest of the frame.
+ const struct BlankRegion {
+ const char* const description;
+ gfx::Rect rect;
+ } regions_around_mutation[] = {
+ {"above", gfx::Rect(0, 0, kContentRegion.width(), mutated_region.y())},
+ {"left", gfx::Rect(0, mutated_region.y(), mutated_region.x(),
+ mutated_region.height())},
+ {"right", gfx::Rect(mutated_region.right(), mutated_region.y(),
+ kContentRegion.width() - mutated_region.right(),
+ mutated_region.height())},
+ {"below", gfx::Rect(0, mutated_region.bottom(), kContentRegion.width(),
+ kContentRegion.height() - mutated_region.bottom())},
+ };
+ for (const BlankRegion& region : regions_around_mutation) {
+ SCOPED_TRACE(testing::Message() << region.description);
+ EXPECT_FALSE(NonZeroPixelsInRegion(frame.get(), region.rect));
+ }
+}
+
+TEST_F(LameCaptureOverlayChromeOSTest, ReportsLostMojoConnection) {
+ class MockOwner : public LameCaptureOverlayChromeOS::Owner {
+ public:
+ ~MockOwner() final = default;
+ MOCK_METHOD1(OnOverlayConnectionLost,
+ void(LameCaptureOverlayChromeOS* overlay));
+ } mock_owner;
+
+ viz::mojom::FrameSinkVideoCaptureOverlayPtr overlay_ptr;
+ LameCaptureOverlayChromeOS overlay(&mock_owner,
+ mojo::MakeRequest(&overlay_ptr));
+ ASSERT_TRUE(overlay_ptr);
+ RunUntilIdle(); // Propagate mojo tasks.
+
+ EXPECT_CALL(mock_owner, OnOverlayConnectionLost(&overlay));
+ overlay_ptr.reset();
+ RunUntilIdle(); // Propagate mojo tasks.
+}
+
+} // namespace
+} // namespace content
diff --git a/chromium/content/browser/media/capture/lame_window_capturer_chromeos.cc b/chromium/content/browser/media/capture/lame_window_capturer_chromeos.cc
index 1086b27f68f..2a9275ecb73 100644
--- a/chromium/content/browser/media/capture/lame_window_capturer_chromeos.cc
+++ b/chromium/content/browser/media/capture/lame_window_capturer_chromeos.cc
@@ -13,6 +13,7 @@
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "media/base/limits.h"
#include "media/base/video_util.h"
+#include "mojo/public/cpp/base/shared_memory_utils.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "ui/gfx/geometry/rect.h"
@@ -140,22 +141,28 @@ void LameWindowCapturerChromeOS::RequestRefreshFrame() {
// continuously.
}
+void LameWindowCapturerChromeOS::CreateOverlay(
+ int32_t stacking_index,
+ viz::mojom::FrameSinkVideoCaptureOverlayRequest request) {
+ // LameWindowCapturerChromeOS only supports one overlay at a time. If one
+ // already exists, the following will cause it to be dropped.
+ overlay_ =
+ std::make_unique<LameCaptureOverlayChromeOS>(this, std::move(request));
+}
+
class LameWindowCapturerChromeOS::InFlightFrame
: public viz::mojom::FrameSinkVideoConsumerFrameCallbacks {
public:
InFlightFrame(base::WeakPtr<LameWindowCapturerChromeOS> capturer,
- BufferAndSize buffer)
+ base::MappedReadOnlyRegion buffer)
: capturer_(std::move(capturer)), buffer_(std::move(buffer)) {}
~InFlightFrame() final { Done(); }
- mojo::ScopedSharedBufferHandle CloneBufferHandle() {
- return buffer_.first->Clone(
- mojo::SharedBufferHandle::AccessMode::READ_WRITE);
+ base::ReadOnlySharedMemoryRegion CloneBufferHandle() {
+ return buffer_.region.Duplicate();
}
- size_t buffer_size() const { return buffer_.second; }
-
VideoFrame* video_frame() const { return video_frame_.get(); }
void set_video_frame(scoped_refptr<VideoFrame> frame) {
video_frame_ = std::move(frame);
@@ -164,12 +171,23 @@ class LameWindowCapturerChromeOS::InFlightFrame
const gfx::Rect& content_rect() const { return content_rect_; }
void set_content_rect(const gfx::Rect& rect) { content_rect_ = rect; }
+ void set_overlay_renderer(LameCaptureOverlayChromeOS::OnceRenderer renderer) {
+ overlay_renderer_ = std::move(renderer);
+ }
+ void RenderOptionalOverlay() {
+ if (overlay_renderer_) {
+ std::move(overlay_renderer_).Run(video_frame_.get());
+ }
+ }
+
void Done() final {
+ video_frame_ = nullptr;
+
if (auto* capturer = capturer_.get()) {
DCHECK_GT(capturer->in_flight_count_, 0);
--capturer->in_flight_count_;
// If the capture size hasn't changed, return the buffer to the pool.
- if (buffer_.second ==
+ if (buffer_.mapping.size() ==
VideoFrame::AllocationSize(media::PIXEL_FORMAT_I420,
capturer->capture_size_)) {
capturer->buffer_pool_.emplace_back(std::move(buffer_));
@@ -177,21 +195,28 @@ class LameWindowCapturerChromeOS::InFlightFrame
capturer_ = nullptr;
}
- buffer_.first.reset();
- buffer_.second = 0;
+ buffer_ = base::MappedReadOnlyRegion();
}
void ProvideFeedback(double utilization) final {}
private:
base::WeakPtr<LameWindowCapturerChromeOS> capturer_;
- BufferAndSize buffer_;
+ base::MappedReadOnlyRegion buffer_;
scoped_refptr<VideoFrame> video_frame_;
gfx::Rect content_rect_;
+ LameCaptureOverlayChromeOS::OnceRenderer overlay_renderer_;
DISALLOW_COPY_AND_ASSIGN(InFlightFrame);
};
+void LameWindowCapturerChromeOS::OnOverlayConnectionLost(
+ LameCaptureOverlayChromeOS* overlay) {
+ if (overlay_.get() == overlay) {
+ overlay_.reset();
+ }
+}
+
void LameWindowCapturerChromeOS::CaptureNextFrame() {
// If the maximum frame in-flight count has been reached, skip this frame.
if (in_flight_count_ >= kMaxFramesInFlight) {
@@ -201,30 +226,22 @@ void LameWindowCapturerChromeOS::CaptureNextFrame() {
// Attempt to re-use a buffer from the pool. Otherwise, create a new one.
const size_t allocation_size =
VideoFrame::AllocationSize(media::PIXEL_FORMAT_I420, capture_size_);
- BufferAndSize buffer;
+ base::MappedReadOnlyRegion buffer;
if (buffer_pool_.empty()) {
- buffer.first = mojo::SharedBufferHandle::Create(allocation_size);
- if (!buffer.first.is_valid()) {
- // If creating the shared memory failed, abort the frame, and hope this
- // is a transient problem.
+ buffer = mojo::CreateReadOnlySharedMemoryRegion(allocation_size);
+ if (!buffer.IsValid()) {
+ // If the shared memory region creation failed, just abort this frame,
+ // hoping the issue is a transient one (e.g., lack of an available region
+ // in the address space).
return;
}
- buffer.second = allocation_size;
} else {
buffer = std::move(buffer_pool_.back());
buffer_pool_.pop_back();
- DCHECK(buffer.first.is_valid());
- DCHECK_EQ(buffer.second, allocation_size);
- }
-
- // Map the shared memory buffer, to populate its data.
- mojo::ScopedSharedBufferMapping mapping = buffer.first->Map(buffer.second);
- if (!mapping) {
- // If the shared memory mapping failed, just abort this frame, hoping the
- // issue is a transient one (e.g., lack of an available region in address
- // space).
- return;
+ DCHECK(buffer.IsValid());
+ DCHECK_EQ(buffer.mapping.size(), allocation_size);
}
+ void* const backing_memory = buffer.mapping.memory();
// At this point, frame capture will proceed. Create an InFlightFrame to track
// population and consumption of the frame, and to eventually return the
@@ -240,13 +257,10 @@ void LameWindowCapturerChromeOS::CaptureNextFrame() {
}
in_flight_frame->set_video_frame(VideoFrame::WrapExternalData(
media::PIXEL_FORMAT_I420, capture_size_, gfx::Rect(capture_size_),
- capture_size_, static_cast<uint8_t*>(mapping.get()), allocation_size,
+ capture_size_, static_cast<uint8_t*>(backing_memory), allocation_size,
begin_time - first_frame_reference_time_));
auto* const frame = in_flight_frame->video_frame();
DCHECK(frame);
- frame->AddDestructionObserver(
- base::BindOnce(base::DoNothing::Once<mojo::ScopedSharedBufferMapping>(),
- std::move(mapping)));
VideoFrameMetadata* const metadata = frame->metadata();
metadata->SetTimeTicks(VideoFrameMetadata::CAPTURE_BEGIN_TIME, begin_time);
metadata->SetInteger(VideoFrameMetadata::COLOR_SPACE,
@@ -273,6 +287,10 @@ void LameWindowCapturerChromeOS::CaptureNextFrame() {
}
DCHECK(target_);
+ if (overlay_) {
+ in_flight_frame->set_overlay_renderer(overlay_->MakeRenderer(content_rect));
+ }
+
// Request a copy of the Layer associated with the |target_| aura::Window.
auto request = std::make_unique<viz::CopyOutputRequest>(
// Note: As of this writing, I420_PLANES is not supported external to VIZ.
@@ -308,6 +326,8 @@ void LameWindowCapturerChromeOS::DidCopyFrame(
return; // Copy request failed, punt.
}
+ in_flight_frame->RenderOptionalOverlay();
+
// The result may be smaller than what was requested, if unforeseen clamping
// to the source boundaries occurred by the executor of the copy request.
// However, the result should never contain more than what was requested.
@@ -328,12 +348,11 @@ void LameWindowCapturerChromeOS::DeliverFrame(
base::TimeTicks::Now());
// Clone the buffer handle for the consumer.
- mojo::ScopedSharedBufferHandle buffer_for_consumer =
+ base::ReadOnlySharedMemoryRegion handle =
in_flight_frame->CloneBufferHandle();
- if (!buffer_for_consumer.is_valid()) {
+ if (!handle.IsValid()) {
return; // This should only fail if the OS is exhausted of handles.
}
- const size_t buffer_allocation_size = in_flight_frame->buffer_size();
// Assemble frame layout, format, and metadata into a mojo struct to send to
// the consumer.
@@ -346,10 +365,6 @@ void LameWindowCapturerChromeOS::DeliverFrame(
const gfx::Rect update_rect = frame->visible_rect();
const gfx::Rect content_rect = in_flight_frame->content_rect();
- // Drop the VideoFrame wrapper, which will unmap the shared memory from this
- // process.
- in_flight_frame->set_video_frame(nullptr);
-
// Create a mojo message pipe and bind to the InFlightFrame to wait for the
// Done() signal from the consumer. The mojo::StrongBinding takes ownership of
// the InFlightFrame.
@@ -358,9 +373,8 @@ void LameWindowCapturerChromeOS::DeliverFrame(
mojo::MakeRequest(&callbacks));
// Send the frame to the consumer.
- consumer_->OnFrameCaptured(std::move(buffer_for_consumer),
- buffer_allocation_size, std::move(info),
- update_rect, content_rect, std::move(callbacks));
+ consumer_->OnFrameCaptured(std::move(handle), std::move(info), update_rect,
+ content_rect, std::move(callbacks));
}
void LameWindowCapturerChromeOS::OnWindowDestroying(aura::Window* window) {
diff --git a/chromium/content/browser/media/capture/lame_window_capturer_chromeos.h b/chromium/content/browser/media/capture/lame_window_capturer_chromeos.h
index 2a467ecc20b..6af4c60068e 100644
--- a/chromium/content/browser/media/capture/lame_window_capturer_chromeos.h
+++ b/chromium/content/browser/media/capture/lame_window_capturer_chromeos.h
@@ -10,12 +10,13 @@
#include <vector>
#include "base/macros.h"
+#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/unguessable_token.h"
+#include "content/browser/media/capture/lame_capture_overlay_chromeos.h"
#include "media/base/video_frame.h"
-#include "mojo/public/cpp/system/buffer.h"
#include "services/viz/privileged/interfaces/compositing/frame_sink_video_capture.mojom.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
@@ -47,6 +48,7 @@ namespace content {
//
// TODO(crbug/806366): The goal is to remove this code by 2019.
class LameWindowCapturerChromeOS : public viz::mojom::FrameSinkVideoCapturer,
+ public LameCaptureOverlayChromeOS::Owner,
public aura::WindowObserver {
public:
explicit LameWindowCapturerChromeOS(aura::Window* target);
@@ -66,6 +68,9 @@ class LameWindowCapturerChromeOS : public viz::mojom::FrameSinkVideoCapturer,
void Start(viz::mojom::FrameSinkVideoConsumerPtr consumer) final;
void Stop() final;
void RequestRefreshFrame() final;
+ void CreateOverlay(
+ int32_t stacking_index,
+ viz::mojom::FrameSinkVideoCaptureOverlayRequest request) final;
private:
// Represents an in-flight frame, being populated by this capturer and then
@@ -73,6 +78,9 @@ class LameWindowCapturerChromeOS : public viz::mojom::FrameSinkVideoCapturer,
// returns the buffer back to the pool.
class InFlightFrame;
+ // LameWindowCapturerChromeOS::Owner implementation.
+ void OnOverlayConnectionLost(LameCaptureOverlayChromeOS* overlay) final;
+
// Initiates capture of the next frame. This is called periodically by the
// |timer_|.
void CaptureNextFrame();
@@ -106,8 +114,7 @@ class LameWindowCapturerChromeOS : public viz::mojom::FrameSinkVideoCapturer,
base::RepeatingTimer timer_;
// A pool of shared memory buffers for re-use.
- using BufferAndSize = std::pair<mojo::ScopedSharedBufferHandle, size_t>;
- std::vector<BufferAndSize> buffer_pool_;
+ std::vector<base::MappedReadOnlyRegion> buffer_pool_;
// The current number of frames in-flight. If incrementing this would be
// exceed kMaxInFlightFrames, frame capture is not attempted.
@@ -121,6 +128,9 @@ class LameWindowCapturerChromeOS : public viz::mojom::FrameSinkVideoCapturer,
// video capture.
const base::UnguessableToken copy_request_source_;
+ // An optional overlay to be rendered over each captured video frame.
+ std::unique_ptr<LameCaptureOverlayChromeOS> overlay_;
+
// Used for cancelling any outstanding activities' results, once Stop() is
// called and there is no longer a consumer to receive another frame.
base::WeakPtrFactory<LameWindowCapturerChromeOS> weak_factory_;
diff --git a/chromium/content/browser/media/capture/mouse_cursor_overlay_controller.cc b/chromium/content/browser/media/capture/mouse_cursor_overlay_controller.cc
new file mode 100644
index 00000000000..0bc6700725b
--- /dev/null
+++ b/chromium/content/browser/media/capture/mouse_cursor_overlay_controller.cc
@@ -0,0 +1,166 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/capture/mouse_cursor_overlay_controller.h"
+
+#include <cmath>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+
+namespace content {
+
+// static
+constexpr base::TimeDelta MouseCursorOverlayController::kIdleTimeout;
+
+void MouseCursorOverlayController::Start(
+ std::unique_ptr<Overlay> overlay,
+ scoped_refptr<base::SequencedTaskRunner> task_runner) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
+ DCHECK(overlay);
+ DCHECK(task_runner);
+
+ Stop();
+ overlay_ = std::move(overlay);
+ overlay_task_runner_ = std::move(task_runner);
+}
+
+void MouseCursorOverlayController::Stop() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
+
+ if (overlay_) {
+ overlay_task_runner_->DeleteSoon(FROM_HERE, overlay_.release());
+ overlay_task_runner_ = nullptr;
+ }
+}
+
+bool MouseCursorOverlayController::IsUserInteractingWithView() const {
+ return mouse_move_behavior() == kRecentlyMovedOrClicked;
+}
+
+base::WeakPtr<MouseCursorOverlayController>
+MouseCursorOverlayController::GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+}
+
+void MouseCursorOverlayController::OnMouseMoved(const gfx::PointF& location) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
+
+ switch (mouse_move_behavior()) {
+ case kNotMoving:
+ set_mouse_move_behavior(kStartingToMove);
+ mouse_move_start_location_ = location;
+ mouse_activity_ended_timer_.Start(
+ FROM_HERE, kIdleTimeout,
+ base::BindRepeating(&MouseCursorOverlayController::OnMouseHasGoneIdle,
+ base::Unretained(this)));
+ break;
+ case kStartingToMove:
+ if (std::abs(location.x() - mouse_move_start_location_.x()) >
+ kMinMovementPixels ||
+ std::abs(location.y() - mouse_move_start_location_.y()) >
+ kMinMovementPixels) {
+ set_mouse_move_behavior(kRecentlyMovedOrClicked);
+ mouse_activity_ended_timer_.Reset();
+ }
+ break;
+ case kRecentlyMovedOrClicked:
+ mouse_activity_ended_timer_.Reset();
+ break;
+ }
+
+ if (mouse_move_behavior() == kRecentlyMovedOrClicked) {
+ UpdateOverlay(location);
+ }
+}
+
+void MouseCursorOverlayController::OnMouseClicked(const gfx::PointF& location) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
+
+ if (mouse_activity_ended_timer_.IsRunning()) {
+ mouse_activity_ended_timer_.Reset();
+ } else {
+ mouse_activity_ended_timer_.Start(
+ FROM_HERE, kIdleTimeout,
+ base::BindRepeating(&MouseCursorOverlayController::OnMouseHasGoneIdle,
+ base::Unretained(this)));
+ }
+ set_mouse_move_behavior(kRecentlyMovedOrClicked);
+
+ UpdateOverlay(location);
+}
+
+void MouseCursorOverlayController::OnMouseHasGoneIdle() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
+
+ // Note that the following is not redundant since callers other than the timer
+ // may have invoked this method.
+ mouse_activity_ended_timer_.Stop();
+
+ set_mouse_move_behavior(kNotMoving);
+
+ UpdateOverlay(gfx::PointF());
+}
+
+void MouseCursorOverlayController::UpdateOverlay(const gfx::PointF& location) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
+
+ if (!overlay_) {
+ return;
+ }
+
+ // Breaking out of the following do-block indicates one or more prerequisites
+ // are not met and the cursor should be(come) hidden.
+ do {
+ // If the mouse has not recently moved, hide the overlay.
+ if (mouse_move_behavior() != kRecentlyMovedOrClicked) {
+ break;
+ }
+
+ const gfx::NativeCursor cursor = GetCurrentCursorOrDefault();
+ const gfx::RectF relative_bounds =
+ ComputeRelativeBoundsForOverlay(cursor, location);
+
+ // If the cursor (and, by implication, the cursor image) has not changed,
+ // just move the overlay to its new position, if any.
+ if (cursor == last_cursor_) {
+ if (bounds_ != relative_bounds) {
+ bounds_ = relative_bounds;
+ overlay_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&Overlay::SetBounds,
+ base::Unretained(overlay_.get()), bounds_));
+ }
+ return;
+ }
+
+ // The cursor image has changed. Edge-case: If the platform does not provide
+ // a cursor image (e.g., this can occur at browser shutdown), just hide the
+ // overlay.
+ const SkBitmap cursor_image = GetCursorImage(cursor);
+ if (cursor_image.drawsNothing()) {
+ last_cursor_ = gfx::NativeCursor();
+ break;
+ }
+ last_cursor_ = cursor;
+ bounds_ = relative_bounds;
+ overlay_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&Overlay::SetImageAndBounds,
+ base::Unretained(overlay_.get()),
+ cursor_image, bounds_));
+ return;
+ } while (false);
+
+ // If this point has been reached, then the overlay should be hidden.
+ if (!bounds_.IsEmpty()) {
+ bounds_ = gfx::RectF();
+ overlay_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&Overlay::SetBounds,
+ base::Unretained(overlay_.get()), bounds_));
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/capture/mouse_cursor_overlay_controller.h b/chromium/content/browser/media/capture/mouse_cursor_overlay_controller.h
new file mode 100644
index 00000000000..5902ac6db24
--- /dev/null
+++ b/chromium/content/browser/media/capture/mouse_cursor_overlay_controller.h
@@ -0,0 +1,164 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_MOUSE_CURSOR_OVERLAY_CONTROLLER_H_
+#define CONTENT_BROWSER_MEDIA_CAPTURE_MOUSE_CURSOR_OVERLAY_CONTROLLER_H_
+
+#include <atomic>
+#include <memory>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "base/sequenced_task_runner.h"
+#include "base/timer/timer.h"
+#include "content/common/content_export.h"
+#include "services/viz/privileged/interfaces/compositing/frame_sink_video_capture.mojom.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace content {
+
+// MouseCursorOverlayController is used by FrameSinkVideoCaptureDevice to manage
+// the mouse cursor overlay in the viz::FrameSinkVideoCapturer session based on
+// the behavior of the mouse cursor reported by the windowing system.
+//
+// All parts of this class are meant to run on the UI BrowserThread, except for
+// IsUserInteractingWithView(), which may be called from any thread. It is up to
+// the client code to ensure the controller's lifetime while in use across
+// multiple threads.
+class CONTENT_EXPORT MouseCursorOverlayController {
+ public:
+ using Overlay = viz::mojom::FrameSinkVideoCaptureOverlay;
+
+ MouseCursorOverlayController();
+ ~MouseCursorOverlayController();
+
+ // Sets a new target view to monitor for mouse cursor updates.
+ void SetTargetView(gfx::NativeView view);
+
+ // Takes ownership of and starts controlling the given |overlay|, invoking its
+ // methods (and destruction) via the given |task_runner|.
+ void Start(std::unique_ptr<Overlay> overlay,
+ scoped_refptr<base::SequencedTaskRunner> task_runner);
+
+ // Stops controlling the Overlay (passed to Start()) and schedules its
+ // destruction.
+ void Stop();
+
+ // Returns true if the user has recently interacted with the view.
+ bool IsUserInteractingWithView() const;
+
+ // Returns a weak pointer.
+ base::WeakPtr<MouseCursorOverlayController> GetWeakPtr();
+
+ private:
+ friend class MouseCursorOverlayControllerBrowserTest;
+
+ // Observes mouse events from the windowing system and reports them via
+ // OnMouseMoved(), OnMouseClicked(), and OnMouseHasGoneIdle().
+ class Observer;
+
+ enum MouseMoveBehavior {
+ kNotMoving, // Mouse has not moved recently.
+ kStartingToMove, // Mouse has moved, but not significantly.
+ kRecentlyMovedOrClicked, // Sufficient mouse activity present.
+ };
+
+ // Called from platform-specific code to report on mouse events within the
+ // captured view.
+ void OnMouseMoved(const gfx::PointF& location);
+ void OnMouseClicked(const gfx::PointF& location);
+
+ // Called by the |mouse_activity_ended_timer_| once no mouse events have
+ // occurred for kIdleTimeout. Also, called by platform-specific code when
+ // changing the target view.
+ void OnMouseHasGoneIdle();
+
+ // Accessors for |mouse_move_behavior_atomic_|. See comments below.
+ MouseMoveBehavior mouse_move_behavior() const {
+ return mouse_move_behavior_atomic_.load(std::memory_order_relaxed);
+ }
+ void set_mouse_move_behavior(MouseMoveBehavior behavior) {
+ mouse_move_behavior_atomic_.store(behavior, std::memory_order_relaxed);
+ }
+
+ // Examines the current mouse movement behavior, view properties, and cursor
+ // changes to determine whether to show or hide the overlay. |location| is the
+ // current mouse cursor location.
+ void UpdateOverlay(const gfx::PointF& location);
+
+ // Returns the current mouse cursor. The default "arrow pointer" cursor will
+ // be returned in lieu of a null cursor.
+ gfx::NativeCursor GetCurrentCursorOrDefault() const;
+
+ // Computes where the overlay should be shown, in terms of relative
+ // coordinates. This takes the view size, coordinate systems of the view and
+ // cursor bitmap, and cursor hotspot offset; all into account.
+ gfx::RectF ComputeRelativeBoundsForOverlay(const gfx::NativeCursor& cursor,
+ const gfx::PointF& location) const;
+
+ // Called after SetTargetView() to ignore mouse events from the
+ // platform/toolkit and set a default mouse cursor. This is used by the
+ // browser tests to prevent actual mouse movement from interfering with the
+ // testing of the control logic.
+ void DisconnectFromToolkitForTesting();
+
+ // Returns the image of the mouse cursor.
+ static SkBitmap GetCursorImage(const gfx::NativeCursor&);
+
+ // Platform-specific mouse event observer. Updated by SetTargetView().
+ std::unique_ptr<Observer> observer_;
+
+ // Updated in the mouse event handlers and used to decide whether the user is
+ // interacting with the view and whether to update the overlay.
+ gfx::PointF mouse_move_start_location_;
+ base::OneShotTimer mouse_activity_ended_timer_;
+
+ // Updated in the mouse event handlers and read by IsUserInteractingWithView()
+ // (on any thread). This is not protected by a mutex since strict memory
+ // ordering semantics are not necessary, just atomicity between threads. All
+ // code should use the accessors to read or set this value.
+ std::atomic<MouseMoveBehavior> mouse_move_behavior_atomic_;
+
+ // The overlay being controlled, and the task runner to use to invoke its
+ // methods and destruction.
+ std::unique_ptr<Overlay> overlay_;
+ scoped_refptr<base::SequencedTaskRunner> overlay_task_runner_;
+
+ // The last-shown mouse cursor. UpdateOverlay() uses this to determine whether
+ // to update the cursor image, or just the overlay position.
+ gfx::NativeCursor last_cursor_ = gfx::NativeCursor();
+
+ // This is empty if the overlay should be hidden. Otherwise, it represents a
+ // shown overlay with a relative position within the view in terms of the
+ // range [0.0,1.0). It can sometimes be a little bit outside of that range,
+ // depending on the cursor's hotspot.
+ gfx::RectF bounds_;
+
+ // Everything except the constructor and IsUserInteractingWithView() must be
+ // called on the UI BrowserThread.
+ SEQUENCE_CHECKER(ui_sequence_checker_);
+
+ base::WeakPtrFactory<MouseCursorOverlayController> weak_factory_;
+
+ // Minium movement before the cursor has been considered intentionally moved
+ // by the user.
+ static constexpr int kMinMovementPixels = 15;
+
+ // Amount of time to elapse with no mouse activity before the cursor should
+ // stop showing.
+ static constexpr base::TimeDelta kIdleTimeout =
+ base::TimeDelta::FromSeconds(2);
+
+ DISALLOW_COPY_AND_ASSIGN(MouseCursorOverlayController);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_CAPTURE_MOUSE_CURSOR_OVERLAY_CONTROLLER_H_
diff --git a/chromium/content/browser/media/capture/mouse_cursor_overlay_controller_aura.cc b/chromium/content/browser/media/capture/mouse_cursor_overlay_controller_aura.cc
new file mode 100644
index 00000000000..0075be20bb2
--- /dev/null
+++ b/chromium/content/browser/media/capture/mouse_cursor_overlay_controller_aura.cc
@@ -0,0 +1,226 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/capture/mouse_cursor_overlay_controller.h"
+
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/base/cursor/cursor_loader.h"
+#include "ui/base/cursor/cursor_type.h"
+#include "ui/events/event.h"
+#include "ui/events/event_handler.h"
+#include "ui/wm/public/activation_client.h"
+
+namespace content {
+
+namespace {
+
+ui::Cursor CreateDefaultPointerCursor() {
+ ui::Cursor cursor(ui::CursorType::kPointer);
+ std::unique_ptr<ui::CursorLoader> loader(ui::CursorLoader::Create());
+ loader->SetPlatformCursor(&cursor);
+ return cursor;
+}
+
+} // namespace
+
+class MouseCursorOverlayController::Observer : public ui::EventHandler,
+ public aura::WindowObserver {
+ public:
+ explicit Observer(MouseCursorOverlayController* controller,
+ aura::Window* window)
+ : controller_(controller), window_(window) {
+ DCHECK(controller_);
+ DCHECK(window_);
+ controller_->OnMouseHasGoneIdle();
+ window_->AddObserver(this);
+ window_->AddPreTargetHandler(this);
+ }
+
+ ~Observer() final {
+ if (window_) {
+ OnWindowDestroying(window_);
+ }
+ }
+
+ void StopTracking() {
+ if (window_) {
+ window_->RemovePreTargetHandler(this);
+ controller_->OnMouseHasGoneIdle();
+ }
+ }
+
+ static aura::Window* GetTargetWindow(
+ const std::unique_ptr<Observer>& observer) {
+ if (observer) {
+ return observer->window_;
+ }
+ return nullptr;
+ }
+
+ private:
+ bool IsWindowActive() const {
+ if (window_) {
+ if (auto* root_window = window_->GetRootWindow()) {
+ if (window_ == root_window) {
+ return true;
+ }
+ if (auto* client = wm::GetActivationClient(root_window)) {
+ if (auto* active_window = client->GetActiveWindow()) {
+ return active_window->Contains(window_);
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ gfx::PointF AsLocationInWindow(const ui::Event& event) const {
+ gfx::PointF location = event.AsLocatedEvent()->location_f();
+ if (event.target() != window_) {
+ aura::Window::ConvertPointToTarget(
+ static_cast<aura::Window*>(event.target()), window_, &location);
+ }
+ return location;
+ }
+
+ // ui::EventHandler overrides.
+ void OnEvent(ui::Event* event) final {
+ switch (event->type()) {
+ case ui::ET_MOUSE_DRAGGED:
+ case ui::ET_MOUSE_MOVED:
+ case ui::ET_MOUSE_ENTERED:
+ case ui::ET_MOUSE_EXITED:
+ case ui::ET_TOUCH_MOVED:
+ if (IsWindowActive()) {
+ controller_->OnMouseMoved(AsLocationInWindow(*event));
+ }
+ break;
+
+ case ui::ET_MOUSE_PRESSED:
+ case ui::ET_MOUSE_RELEASED:
+ case ui::ET_MOUSEWHEEL:
+ case ui::ET_TOUCH_PRESSED:
+ case ui::ET_TOUCH_RELEASED: {
+ controller_->OnMouseClicked(AsLocationInWindow(*event));
+ break;
+ }
+
+ default:
+ return;
+ }
+ }
+
+ // aura::WindowObserver overrides.
+ void OnWindowDestroying(aura::Window* window) final {
+ DCHECK_EQ(window_, window);
+ StopTracking();
+ window_->RemoveObserver(this);
+ window_ = nullptr;
+ }
+
+ MouseCursorOverlayController* const controller_;
+ aura::Window* window_;
+
+ DISALLOW_COPY_AND_ASSIGN(Observer);
+};
+
+MouseCursorOverlayController::MouseCursorOverlayController()
+ : mouse_move_behavior_atomic_(kNotMoving), weak_factory_(this) {
+ // MouseCursorOverlayController can be constructed on any thread, but
+ // thereafter must be used according to class-level comments.
+ DETACH_FROM_SEQUENCE(ui_sequence_checker_);
+}
+
+MouseCursorOverlayController::~MouseCursorOverlayController() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
+
+ observer_.reset();
+ Stop();
+}
+
+void MouseCursorOverlayController::SetTargetView(aura::Window* window) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
+
+ observer_.reset();
+ if (window) {
+ observer_ = std::make_unique<Observer>(this, window);
+ }
+}
+
+gfx::NativeCursor MouseCursorOverlayController::GetCurrentCursorOrDefault()
+ const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
+
+ if (auto* window = Observer::GetTargetWindow(observer_)) {
+ if (auto* host = window->GetHost()) {
+ const gfx::NativeCursor cursor = host->last_cursor();
+ if (cursor != ui::CursorType::kNull) {
+ return cursor;
+ }
+ }
+ }
+
+ return CreateDefaultPointerCursor();
+}
+
+gfx::RectF MouseCursorOverlayController::ComputeRelativeBoundsForOverlay(
+ const gfx::NativeCursor& cursor,
+ const gfx::PointF& location) const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
+
+ if (auto* window = Observer::GetTargetWindow(observer_)) {
+ const gfx::Size window_size = window->bounds().size();
+ if (!window_size.IsEmpty()) {
+ if (auto* root_window = window->GetRootWindow()) {
+ // Compute the cursor size in terms of DIP coordinates.
+ const SkBitmap& bitmap = cursor.GetBitmap();
+ const float scale_factor = cursor.device_scale_factor();
+ const gfx::SizeF size =
+ scale_factor > 0.0f
+ ? gfx::ScaleSize(gfx::SizeF(bitmap.width(), bitmap.height()),
+ 1.0f / scale_factor)
+ : gfx::SizeF(bitmap.width(), bitmap.height());
+
+ // Compute the hotspot in terms of DIP coordinates.
+ const gfx::PointF hotspot =
+ scale_factor > 0.0f
+ ? gfx::ScalePoint(gfx::PointF(cursor.GetHotspot()),
+ 1.0f / scale_factor)
+ : gfx::PointF(cursor.GetHotspot());
+
+ // Finally, put it all together: Scale the absolute bounds of the
+ // overlay by the window size to produce relative coordinates.
+ return gfx::ScaleRect(
+ gfx::RectF(location - hotspot.OffsetFromOrigin(), size),
+ 1.0f / window_size.width(), 1.0f / window_size.height());
+ }
+ }
+ }
+
+ return gfx::RectF();
+}
+
+void MouseCursorOverlayController::DisconnectFromToolkitForTesting() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
+
+ observer_->StopTracking();
+
+ // The default cursor is ui::CursorType::kNone. Make it kPointer so the tests
+ // have a non-empty cursor bitmap to work with.
+ auto* const window = Observer::GetTargetWindow(observer_);
+ CHECK(window);
+ auto* const host = window->GetHost();
+ CHECK(host);
+ host->SetCursor(CreateDefaultPointerCursor());
+}
+
+// static
+SkBitmap MouseCursorOverlayController::GetCursorImage(
+ const gfx::NativeCursor& cursor) {
+ return cursor.GetBitmap();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/capture/mouse_cursor_overlay_controller_browsertest.cc b/chromium/content/browser/media/capture/mouse_cursor_overlay_controller_browsertest.cc
new file mode 100644
index 00000000000..5a05b17ff0b
--- /dev/null
+++ b/chromium/content/browser/media/capture/mouse_cursor_overlay_controller_browsertest.cc
@@ -0,0 +1,260 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/capture/mouse_cursor_overlay_controller.h"
+
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/shell/browser/shell.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/size_f.h"
+
+namespace content {
+namespace {
+
+class FakeOverlay : public MouseCursorOverlayController::Overlay {
+ public:
+ FakeOverlay() = default;
+ ~FakeOverlay() final = default;
+
+ const SkBitmap& image() const { return image_; }
+ const gfx::RectF& bounds() const { return bounds_; }
+
+ void SetImageAndBounds(const SkBitmap& image,
+ const gfx::RectF& bounds) final {
+ image_ = image;
+ bounds_ = bounds;
+ }
+
+ void SetBounds(const gfx::RectF& bounds) final { bounds_ = bounds; }
+
+ private:
+ SkBitmap image_;
+ gfx::RectF bounds_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeOverlay);
+};
+
+} // namespace
+
+class MouseCursorOverlayControllerBrowserTest : public ContentBrowserTest {
+ public:
+ MouseCursorOverlayControllerBrowserTest() = default;
+ ~MouseCursorOverlayControllerBrowserTest() override = default;
+
+ void SetUpOnMainThread() final {
+ ContentBrowserTest::SetUpOnMainThread();
+ controller_.SetTargetView(shell()->web_contents()->GetNativeView());
+ controller_.DisconnectFromToolkitForTesting();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ FakeOverlay* Start() {
+ auto overlay_ptr = std::make_unique<FakeOverlay>();
+ FakeOverlay* const overlay = overlay_ptr.get();
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ controller_.Start(std::move(overlay_ptr),
+ BrowserThread::GetTaskRunnerForThread(BrowserThread::UI));
+ return overlay;
+ }
+
+ gfx::PointF GetLowerRightMostPointInsideView() {
+ const gfx::Size& view_size = GetAbsoluteViewSize();
+ return gfx::PointF(1.0f - 1.0f / view_size.width(),
+ 1.0f - 1.0f / view_size.height());
+ }
+
+ void SimulateMouseTravel(float from_x, float from_y, float to_x, float to_y) {
+ constexpr int kNumMoves = 10;
+ for (int i = kNumMoves; i >= 0; --i) {
+ const float t = static_cast<float>(i) / kNumMoves;
+ const float x = t * from_x + (1.0f - t) * to_x;
+ const float y = t * from_y + (1.0f - t) * to_y;
+ controller_.OnMouseMoved(ToAbsoluteLocationInView(x, y));
+ }
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void SimulateMouseClick(float x, float y) {
+ controller_.OnMouseClicked(ToAbsoluteLocationInView(x, y));
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void SimulateMouseHasGoneIdle() {
+ controller_.OnMouseHasGoneIdle();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(controller_.mouse_activity_ended_timer_.IsRunning());
+ }
+
+ void SimulateUnintentionalMouseMovement(float x, float y) {
+ const gfx::Size& view_size = GetAbsoluteViewSize();
+ const float distance_x =
+ (0.5f * MouseCursorOverlayController::kMinMovementPixels) /
+ view_size.width();
+ const float distance_y =
+ (0.5f * MouseCursorOverlayController::kMinMovementPixels) /
+ view_size.height();
+ DoSquareDance(x, y, distance_x, distance_y);
+ }
+
+ void SimulateBarelyIntentionalMouseMovement(float x, float y) {
+ const gfx::Size& view_size = GetAbsoluteViewSize();
+ const float distance_x =
+ (1.5f * MouseCursorOverlayController::kMinMovementPixels) /
+ view_size.width();
+ const float distance_y =
+ (1.5f * MouseCursorOverlayController::kMinMovementPixels) /
+ view_size.height();
+ DoSquareDance(x, y, distance_x, distance_y);
+ }
+
+ void ExpectOverlayPositionedAt(const FakeOverlay& overlay,
+ float expected_x,
+ float expected_y) {
+ const gfx::SizeF& overlay_size = GetExpectedOverlaySize();
+ // The position will be slightly off because of the hotspot offset.
+ EXPECT_NEAR(expected_x, overlay.bounds().x(), overlay_size.width() / 2.0f);
+ EXPECT_NEAR(expected_y, overlay.bounds().y(), overlay_size.height() / 2.0f);
+ }
+
+ void ExpectOverlaySizeMatchesCurrentCursor(const FakeOverlay& overlay) const {
+ const gfx::SizeF& expected_size = GetExpectedOverlaySize();
+ EXPECT_FALSE(expected_size.IsEmpty());
+ EXPECT_FALSE(overlay.image().drawsNothing());
+ EXPECT_NEAR(expected_size.width(), overlay.bounds().width(), 0.001);
+ EXPECT_NEAR(expected_size.height(), overlay.bounds().height(), 0.001);
+ }
+
+ bool IsUserInteractingWithView() const {
+ return controller_.IsUserInteractingWithView();
+ }
+
+ private:
+ gfx::Size GetAbsoluteViewSize() const {
+ const gfx::Size view_size =
+ shell()->web_contents()->GetContainerBounds().size();
+ CHECK(!view_size.IsEmpty());
+ return view_size;
+ }
+
+ gfx::PointF ToAbsoluteLocationInView(float relative_x, float relative_y) {
+ const gfx::Size& view_size = GetAbsoluteViewSize();
+ return gfx::PointF(relative_x * view_size.width(),
+ relative_y * view_size.height());
+ }
+
+ gfx::SizeF GetExpectedOverlaySize() const {
+ const gfx::Size& view_size = GetAbsoluteViewSize();
+ const SkBitmap image =
+ controller_.GetCursorImage(controller_.GetCurrentCursorOrDefault());
+ return gfx::SizeF(static_cast<float>(image.width()) / view_size.width(),
+ static_cast<float>(image.height()) / view_size.height());
+ }
+
+ void DoSquareDance(float x, float y, float distance_x, float distance_y) {
+ SimulateMouseTravel(x, y, x + distance_x, y);
+ SimulateMouseTravel(x + distance_x, y, x + distance_x, y + distance_y);
+ SimulateMouseTravel(x + distance_x, y + distance_y, x, y + distance_y);
+ SimulateMouseTravel(x, y + distance_y, x, y);
+ base::RunLoop().RunUntilIdle();
+ }
+
+ MouseCursorOverlayController controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(MouseCursorOverlayControllerBrowserTest);
+};
+
+IN_PROC_BROWSER_TEST_F(MouseCursorOverlayControllerBrowserTest,
+ PositionsOverlayOnMouseMoves) {
+ FakeOverlay* const overlay = Start();
+
+ // Cursor not showing at start.
+ EXPECT_TRUE(overlay->image().drawsNothing());
+ EXPECT_TRUE(overlay->bounds().IsEmpty());
+ EXPECT_FALSE(IsUserInteractingWithView());
+
+ // Move to upper-leftmost corner.
+ {
+ SCOPED_TRACE(testing::Message() << "upper-leftmost corner of view");
+ SimulateMouseTravel(0.5f, 0.5f, 0.0f, 0.0f);
+ ExpectOverlayPositionedAt(*overlay, 0.0f, 0.0f);
+ ExpectOverlaySizeMatchesCurrentCursor(*overlay);
+ EXPECT_TRUE(IsUserInteractingWithView());
+ }
+
+ // Move to middle.
+ {
+ SCOPED_TRACE(testing::Message() << "center of view");
+ SimulateMouseTravel(0.0f, 0.0f, 0.5f, 0.5f);
+ ExpectOverlayPositionedAt(*overlay, 0.5f, 0.5f);
+ ExpectOverlaySizeMatchesCurrentCursor(*overlay);
+ EXPECT_TRUE(IsUserInteractingWithView());
+ }
+
+ // Move to lower-rightmost corner.
+ {
+ SCOPED_TRACE(testing::Message() << "lower-rightmost corner of view");
+ const gfx::PointF lower_right = GetLowerRightMostPointInsideView();
+ SimulateMouseTravel(0.5f, 0.5f, lower_right.x(), lower_right.y());
+ ExpectOverlayPositionedAt(*overlay, lower_right.x(), lower_right.y());
+ ExpectOverlaySizeMatchesCurrentCursor(*overlay);
+ EXPECT_TRUE(IsUserInteractingWithView());
+ }
+}
+
+IN_PROC_BROWSER_TEST_F(MouseCursorOverlayControllerBrowserTest,
+ PositionsOverlayOnMouseClicks) {
+ FakeOverlay* const overlay = Start();
+
+ // Cursor not showing at start.
+ EXPECT_TRUE(overlay->bounds().IsEmpty());
+ EXPECT_FALSE(IsUserInteractingWithView());
+
+ // Click in the middle of the view.
+ SimulateMouseClick(0.5f, 0.5f);
+ ExpectOverlayPositionedAt(*overlay, 0.5f, 0.5f);
+ ExpectOverlaySizeMatchesCurrentCursor(*overlay);
+ EXPECT_TRUE(IsUserInteractingWithView());
+}
+
+IN_PROC_BROWSER_TEST_F(MouseCursorOverlayControllerBrowserTest,
+ CursorHidesWhenMouseStopsMoving) {
+ FakeOverlay* const overlay = Start();
+
+ // Cursor not showing at start.
+ EXPECT_TRUE(overlay->bounds().IsEmpty());
+ EXPECT_FALSE(IsUserInteractingWithView());
+
+ // Move to middle.
+ SimulateMouseTravel(0.0f, 0.0f, 0.5f, 0.5f);
+ ExpectOverlayPositionedAt(*overlay, 0.5f, 0.5f);
+ ExpectOverlaySizeMatchesCurrentCursor(*overlay);
+ EXPECT_TRUE(IsUserInteractingWithView());
+
+ // Simulate no movement for the timeout period.
+ SimulateMouseHasGoneIdle();
+ EXPECT_TRUE(overlay->bounds().IsEmpty());
+ EXPECT_FALSE(IsUserInteractingWithView());
+
+ // Move the mouse a little, but not enough to trip the "intentionally moved"
+ // logic.
+ SimulateUnintentionalMouseMovement(0.5f, 0.5f);
+ EXPECT_TRUE(overlay->bounds().IsEmpty());
+ EXPECT_FALSE(IsUserInteractingWithView());
+
+ // Move the mouse just a bit more, to trip the "intentionally moved" logic.
+ SimulateBarelyIntentionalMouseMovement(0.5f, 0.5f);
+ ExpectOverlayPositionedAt(*overlay, 0.5f, 0.5f);
+ ExpectOverlaySizeMatchesCurrentCursor(*overlay);
+ EXPECT_TRUE(IsUserInteractingWithView());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/capture/mouse_cursor_overlay_controller_mac.mm b/chromium/content/browser/media/capture/mouse_cursor_overlay_controller_mac.mm
new file mode 100644
index 00000000000..fa6a82e6e37
--- /dev/null
+++ b/chromium/content/browser/media/capture/mouse_cursor_overlay_controller_mac.mm
@@ -0,0 +1,198 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/capture/mouse_cursor_overlay_controller.h"
+
+#include <Cocoa/Cocoa.h>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_nsobject.h"
+#include "skia/ext/skia_utils_mac.h"
+#include "ui/base/cocoa/tracking_area.h"
+
+namespace {
+using LocationUpdateCallback = base::RepeatingCallback<void(const NSPoint&)>;
+} // namespace;
+
+// Uses a CrTrackingArea to monitor for mouse events and forwards them to the
+// MouseCursorOverlayController::Observer.
+@interface MouseCursorOverlayTracker : NSObject {
+ @private
+ LocationUpdateCallback callback_;
+ ui::ScopedCrTrackingArea trackingArea_;
+}
+- (instancetype)initWithCallback:(LocationUpdateCallback)callback
+ andView:(NSView*)nsView;
+- (void)stopTracking:(NSView*)nsView;
+@end
+
+@implementation MouseCursorOverlayTracker
+
+- (instancetype)initWithCallback:(LocationUpdateCallback)callback
+ andView:(NSView*)nsView {
+ if ((self = [super init])) {
+ callback_ = std::move(callback);
+ constexpr NSTrackingAreaOptions kTrackingOptions =
+ NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveInKeyWindow | NSTrackingInVisibleRect |
+ NSTrackingEnabledDuringMouseDrag;
+ trackingArea_.reset([[CrTrackingArea alloc] initWithRect:NSZeroRect
+ options:kTrackingOptions
+ owner:self
+ userInfo:nil]);
+ [nsView addTrackingArea:trackingArea_.get()];
+ }
+ return self;
+}
+
+- (void)stopTracking:(NSView*)nsView {
+ [nsView removeTrackingArea:trackingArea_.get()];
+ trackingArea_.reset();
+ callback_.Reset();
+}
+
+- (void)mouseMoved:(NSEvent*)theEvent {
+ callback_.Run([theEvent locationInWindow]);
+}
+
+- (void)mouseEntered:(NSEvent*)theEvent {
+ callback_.Run([theEvent locationInWindow]);
+}
+
+- (void)mouseExited:(NSEvent*)theEvent {
+ callback_.Run([theEvent locationInWindow]);
+}
+
+@end
+
+namespace content {
+
+class MouseCursorOverlayController::Observer {
+ public:
+ explicit Observer(MouseCursorOverlayController* controller, NSView* view)
+ : controller_(controller), view_([view retain]) {
+ DCHECK(controller_);
+ DCHECK(view_);
+ controller_->OnMouseHasGoneIdle();
+ mouse_tracker_.reset([[MouseCursorOverlayTracker alloc]
+ initWithCallback:base::BindRepeating(&Observer::OnMouseMoved,
+ base::Unretained(this))
+ andView:view_.get()]);
+ }
+
+ ~Observer() { StopTracking(); }
+
+ void StopTracking() {
+ if (mouse_tracker_) {
+ [mouse_tracker_ stopTracking:view_.get()];
+ mouse_tracker_.reset();
+ controller_->OnMouseHasGoneIdle();
+ }
+ }
+
+ static NSView* GetTargetView(const std::unique_ptr<Observer>& observer) {
+ if (observer) {
+ return observer->view_.get();
+ }
+ return nil;
+ }
+
+ private:
+ void OnMouseMoved(const NSPoint& location_in_window) {
+ // Compute the location within the view using Aura conventions: (0,0) is the
+ // upper-left corner. So, if the NSView is flipped in Cocoa, it's not
+ // flipped in Aura.
+ NSPoint location_aura =
+ [view_ convertPoint:location_in_window fromView:nil];
+ if (![view_ isFlipped]) {
+ location_aura.y = NSHeight([view_ bounds]) - location_aura.y;
+ }
+ controller_->OnMouseMoved(gfx::PointF(location_aura.x, location_aura.y));
+ }
+
+ MouseCursorOverlayController* const controller_;
+ base::scoped_nsobject<NSView> view_;
+ base::scoped_nsobject<MouseCursorOverlayTracker> mouse_tracker_;
+
+ DISALLOW_COPY_AND_ASSIGN(Observer);
+};
+
+MouseCursorOverlayController::MouseCursorOverlayController()
+ : mouse_move_behavior_atomic_(kNotMoving), weak_factory_(this) {
+ // MouseCursorOverlayController can be constructed on any thread, but
+ // thereafter must be used according to class-level comments.
+ DETACH_FROM_SEQUENCE(ui_sequence_checker_);
+}
+
+MouseCursorOverlayController::~MouseCursorOverlayController() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
+
+ observer_.reset();
+ Stop();
+}
+
+void MouseCursorOverlayController::SetTargetView(NSView* view) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
+
+ observer_.reset();
+ if (view) {
+ observer_ = std::make_unique<Observer>(this, view);
+ }
+}
+
+gfx::NativeCursor MouseCursorOverlayController::GetCurrentCursorOrDefault()
+ const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
+
+ NSCursor* cursor = [NSCursor currentCursor];
+ if (!cursor) {
+ cursor = [NSCursor arrowCursor];
+ }
+ return cursor;
+}
+
+gfx::RectF MouseCursorOverlayController::ComputeRelativeBoundsForOverlay(
+ const gfx::NativeCursor& cursor,
+ const gfx::PointF& location_aura) const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
+
+ if (NSView* view = Observer::GetTargetView(observer_)) {
+ const NSRect view_bounds = [view bounds];
+ if (!NSIsEmptyRect(view_bounds)) {
+ // The documentation on NSCursor reference states that the hot spot is in
+ // flipped coordinates which, from the perspective of the Aura coordinate
+ // system, means it's not flipped.
+ const NSPoint hotspot = [cursor hotSpot];
+ const NSSize size = [[cursor image] size];
+ return gfx::ScaleRect(
+ gfx::RectF(location_aura.x() - hotspot.x,
+ location_aura.y() - hotspot.y, size.width, size.height),
+ 1.0 / NSWidth(view_bounds), 1.0 / NSHeight(view_bounds));
+ }
+ }
+
+ return gfx::RectF();
+}
+
+void MouseCursorOverlayController::DisconnectFromToolkitForTesting() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
+
+ observer_->StopTracking();
+
+ // Note: Not overriding the mouse cursor since the default is already
+ // [NSCursor arrowCursor], which provides the tests a bitmap they can work
+ // with.
+}
+
+// static
+SkBitmap MouseCursorOverlayController::GetCursorImage(
+ const gfx::NativeCursor& cursor) {
+ return skia::NSImageToSkBitmapWithColorSpace(
+ [cursor image], /*is_opaque=*/false, base::mac::GetSystemColorSpace());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/capture/screen_capture_device_android.cc b/chromium/content/browser/media/capture/screen_capture_device_android.cc
index 9d5cf896498..d97c36be52c 100644
--- a/chromium/content/browser/media/capture/screen_capture_device_android.cc
+++ b/chromium/content/browser/media/capture/screen_capture_device_android.cc
@@ -25,8 +25,10 @@ void ScreenCaptureDeviceAndroid::AllocateAndStart(
if (params.requested_format.pixel_format != media::PIXEL_FORMAT_I420) {
client->OnError(
- FROM_HERE, "unsupported format: " + media::VideoCaptureFormat::ToString(
- params.requested_format));
+ media::VideoCaptureError::kAndroidScreenCaptureUnsupportedFormat,
+ FROM_HERE,
+ "unsupported format: " +
+ media::VideoCaptureFormat::ToString(params.requested_format));
return;
}
@@ -34,7 +36,10 @@ void ScreenCaptureDeviceAndroid::AllocateAndStart(
oracle_proxy_ = new media::ThreadSafeCaptureOracle(std::move(client), params);
if (!capture_machine_.Start(oracle_proxy_, params)) {
- oracle_proxy_->ReportError(FROM_HERE, "Failed to start capture machine.");
+ oracle_proxy_->ReportError(
+ media::VideoCaptureError::
+ kAndroidScreenCaptureFailedToStartCaptureMachine,
+ FROM_HERE, "Failed to start capture machine.");
StopAndDeAllocate();
} else {
// The |capture_machine_| will later report to the |oracle_proxy_| whether
diff --git a/chromium/content/browser/media/capture/screen_capture_device_android_unittest.cc b/chromium/content/browser/media/capture/screen_capture_device_android_unittest.cc
index dda49dcb222..ffbe9c52a13 100644
--- a/chromium/content/browser/media/capture/screen_capture_device_android_unittest.cc
+++ b/chromium/content/browser/media/capture/screen_capture_device_android_unittest.cc
@@ -36,9 +36,11 @@ class MockDeviceClient : public media::VideoCaptureDevice::Client {
MOCK_METHOD0(DoOnIncomingCapturedBuffer, void(void));
MOCK_METHOD0(DoOnIncomingCapturedVideoFrame, void(void));
MOCK_METHOD0(DoResurrectLastOutputBuffer, void(void));
- MOCK_METHOD2(OnError,
- void(const base::Location& from_here,
+ MOCK_METHOD3(OnError,
+ void(media::VideoCaptureError error,
+ const base::Location& from_here,
const std::string& reason));
+ MOCK_METHOD1(OnFrameDropped, void(media::VideoCaptureFrameDropReason reason));
MOCK_CONST_METHOD0(GetBufferPoolUtilization, double(void));
MOCK_METHOD0(OnStarted, void(void));
@@ -95,7 +97,7 @@ TEST_F(ScreenCaptureDeviceAndroidTest, DISABLED_StartAndStop) {
ASSERT_TRUE(capture_device);
std::unique_ptr<MockDeviceClient> client(new MockDeviceClient());
- EXPECT_CALL(*client, OnError(_, _)).Times(0);
+ EXPECT_CALL(*client, OnError(_, _, _)).Times(0);
// |STARTED| is reported asynchronously, which may not be received if capture
// is stopped immediately.
EXPECT_CALL(*client, OnStarted()).Times(AtMost(1));
diff --git a/chromium/content/browser/media/capture/web_contents_audio_input_stream.cc b/chromium/content/browser/media/capture/web_contents_audio_input_stream.cc
index e1593cc807e..75d9bee6e9a 100644
--- a/chromium/content/browser/media/capture/web_contents_audio_input_stream.cc
+++ b/chromium/content/browser/media/capture/web_contents_audio_input_stream.cc
@@ -5,6 +5,7 @@
#include "content/browser/media/capture/web_contents_audio_input_stream.h"
#include <memory>
+#include <set>
#include <string>
#include "base/bind.h"
@@ -60,8 +61,6 @@ class WebContentsAudioInputStream::Impl
private:
friend class base::RefCountedThreadSafe<WebContentsAudioInputStream::Impl>;
- typedef AudioMirroringManager::SourceFrameRef SourceFrameRef;
-
enum State {
CONSTRUCTED,
OPENED,
@@ -88,10 +87,11 @@ class WebContentsAudioInputStream::Impl
void UnmuteWebContentsAudio();
// AudioMirroringManager::MirroringDestination implementation
- void QueryForMatches(const std::set<SourceFrameRef>& candidates,
- const MatchesCallback& results_callback) override;
- void QueryForMatchesOnUIThread(const std::set<SourceFrameRef>& candidates,
- const MatchesCallback& results_callback);
+ void QueryForMatches(const std::set<GlobalFrameRoutingId>& candidates,
+ MatchesCallback results_callback) override;
+ void QueryForMatchesOnUIThread(
+ const std::set<GlobalFrameRoutingId>& candidates,
+ MatchesCallback results_callback);
media::AudioOutputStream* AddInput(
const media::AudioParameters& params) override;
media::AudioPushSink* AddPushInput(
@@ -297,35 +297,34 @@ void WebContentsAudioInputStream::Impl::UnmuteWebContentsAudio() {
}
void WebContentsAudioInputStream::Impl::QueryForMatches(
- const std::set<SourceFrameRef>& candidates,
- const MatchesCallback& results_callback) {
+ const std::set<GlobalFrameRoutingId>& candidates,
+ MatchesCallback results_callback) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::BindOnce(&Impl::QueryForMatchesOnUIThread, this, candidates,
- media::BindToCurrentLoop(results_callback)));
+ media::BindToCurrentLoop(std::move(results_callback))));
}
void WebContentsAudioInputStream::Impl::QueryForMatchesOnUIThread(
- const std::set<SourceFrameRef>& candidates,
- const MatchesCallback& results_callback) {
+ const std::set<GlobalFrameRoutingId>& candidates,
+ MatchesCallback results_callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- std::set<SourceFrameRef> matches;
+ std::set<GlobalFrameRoutingId> matches;
WebContents* const contents = tracker_->web_contents();
if (contents) {
// Add each ID to |matches| if it maps to a RenderFrameHost that maps to the
// currently-tracked WebContents.
- for (std::set<SourceFrameRef>::const_iterator i = candidates.begin();
- i != candidates.end(); ++i) {
+ for (const auto& it : candidates) {
WebContents* const contents_containing_frame =
WebContents::FromRenderFrameHost(
- RenderFrameHost::FromID(i->first, i->second));
+ RenderFrameHost::FromID(it.child_id, it.frame_routing_id));
if (contents_containing_frame == contents)
- matches.insert(*i);
+ matches.insert(it);
}
}
- results_callback.Run(matches, is_duplication_);
+ std::move(results_callback).Run(matches, is_duplication_);
}
media::AudioOutputStream* WebContentsAudioInputStream::Impl::AddInput(
diff --git a/chromium/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc b/chromium/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc
index e0d3842142b..f27817f8604 100644
--- a/chromium/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc
+++ b/chromium/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc
@@ -471,7 +471,9 @@ TEST_P(WebContentsAudioInputStreamTest, MirroringOutputWithinSession) {
RUN_ON_AUDIO_THREAD(Close);
}
-TEST_P(WebContentsAudioInputStreamTest, MirroringNothingWithTargetChange) {
+// TODO(https://crbug.com/872340): Test appears to have timing-dependent flake.
+TEST_P(WebContentsAudioInputStreamTest,
+ DISABLED_MirroringNothingWithTargetChange) {
RUN_ON_AUDIO_THREAD(Open);
RUN_ON_AUDIO_THREAD(Start);
RUN_ON_AUDIO_THREAD(ChangeMirroringTarget);
diff --git a/chromium/content/browser/media/capture/web_contents_audio_muter.cc b/chromium/content/browser/media/capture/web_contents_audio_muter.cc
index 59a30348350..c10f52250b5 100644
--- a/chromium/content/browser/media/capture/web_contents_audio_muter.cc
+++ b/chromium/content/browser/media/capture/web_contents_audio_muter.cc
@@ -80,33 +80,32 @@ class WebContentsAudioMuter::MuteDestination
private:
friend class base::RefCountedThreadSafe<MuteDestination>;
- typedef AudioMirroringManager::SourceFrameRef SourceFrameRef;
-
~MuteDestination() override {}
- void QueryForMatches(const std::set<SourceFrameRef>& candidates,
- const MatchesCallback& results_callback) override {
+ void QueryForMatches(const std::set<GlobalFrameRoutingId>& candidates,
+ MatchesCallback results_callback) override {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::BindOnce(&MuteDestination::QueryForMatchesOnUIThread, this,
- candidates, media::BindToCurrentLoop(results_callback)));
+ candidates,
+ media::BindToCurrentLoop(std::move(results_callback))));
}
- void QueryForMatchesOnUIThread(const std::set<SourceFrameRef>& candidates,
- const MatchesCallback& results_callback) {
+ void QueryForMatchesOnUIThread(
+ const std::set<GlobalFrameRoutingId>& candidates,
+ MatchesCallback results_callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- std::set<SourceFrameRef> matches;
+ std::set<GlobalFrameRoutingId> matches;
// Add each ID to |matches| if it maps to a RenderFrameHost that maps to the
// WebContents being muted.
- for (std::set<SourceFrameRef>::const_iterator i = candidates.begin();
- i != candidates.end(); ++i) {
+ for (const auto& it : candidates) {
WebContents* const contents_containing_frame =
WebContents::FromRenderFrameHost(
- RenderFrameHost::FromID(i->first, i->second));
+ RenderFrameHost::FromID(it.child_id, it.frame_routing_id));
if (contents_containing_frame == web_contents_)
- matches.insert(*i);
+ matches.insert(it);
}
- results_callback.Run(matches, false);
+ std::move(results_callback).Run(matches, false);
}
media::AudioOutputStream* AddInput(
diff --git a/chromium/content/browser/media/capture/web_contents_video_capture_device.cc b/chromium/content/browser/media/capture/web_contents_video_capture_device.cc
index e4122a24cdf..ff8651a5084 100644
--- a/chromium/content/browser/media/capture/web_contents_video_capture_device.cc
+++ b/chromium/content/browser/media/capture/web_contents_video_capture_device.cc
@@ -4,12 +4,15 @@
#include "content/browser/media/capture/web_contents_video_capture_device.h"
+#include <utility>
+
#include "base/bind.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "content/browser/media/capture/mouse_cursor_overlay_controller.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
@@ -31,14 +34,14 @@ class WebContentsVideoCaptureDevice::FrameTracker
WebContentsVideoCaptureDevice::FrameTracker> {
public:
FrameTracker(base::WeakPtr<WebContentsVideoCaptureDevice> device,
- CursorRenderer* cursor_renderer,
+ MouseCursorOverlayController* cursor_controller,
int render_process_id,
int main_render_frame_id)
: device_(std::move(device)),
device_task_runner_(base::ThreadTaskRunnerHandle::Get()),
- cursor_renderer_(cursor_renderer) {
+ cursor_controller_(cursor_controller) {
DCHECK(device_task_runner_);
- DCHECK(cursor_renderer_);
+ DCHECK(cursor_controller_);
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
@@ -175,10 +178,10 @@ class WebContentsVideoCaptureDevice::FrameTracker
if (native_view != target_native_view_) {
target_native_view_ = native_view;
- // Note: CursorRenderer runs on the UI thread. It's also important that
- // SetTargetView() be called in the current stack while |native_view| is
- // known to be a valid pointer. http://crbug.com/818679
- cursor_renderer_->SetTargetView(native_view);
+ // Note: MouseCursorOverlayController runs on the UI thread. It's also
+ // important that SetTargetView() be called in the current stack while
+ // |native_view| is known to be a valid pointer. http://crbug.com/818679
+ cursor_controller_->SetTargetView(native_view);
}
} else {
device_task_runner_->PostTask(
@@ -186,7 +189,7 @@ class WebContentsVideoCaptureDevice::FrameTracker
base::BindOnce(
&WebContentsVideoCaptureDevice::OnTargetPermanentlyLost,
device_));
- cursor_renderer_->SetTargetView(gfx::NativeView());
+ cursor_controller_->SetTargetView(gfx::NativeView());
}
}
@@ -196,8 +199,8 @@ class WebContentsVideoCaptureDevice::FrameTracker
// Owned by FrameSinkVideoCaptureDevice. This will be valid for the life of
// FrameTracker because the FrameTracker deleter task will be posted to the UI
- // thread before the CursorRenderer deleter task.
- CursorRenderer* const cursor_renderer_;
+ // thread before the MouseCursorOverlayController deleter task.
+ MouseCursorOverlayController* const cursor_controller_;
viz::FrameSinkId target_frame_sink_id_;
gfx::NativeView target_native_view_ = gfx::NativeView();
@@ -212,7 +215,7 @@ WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice(
int render_process_id,
int main_render_frame_id)
: tracker_(new FrameTracker(AsWeakPtr(),
- cursor_renderer(),
+ cursor_controller(),
render_process_id,
main_render_frame_id)) {}
diff --git a/chromium/content/browser/media/cdm_file_impl.cc b/chromium/content/browser/media/cdm_file_impl.cc
index 4c1657d1b6c..7a0b8ba427b 100644
--- a/chromium/content/browser/media/cdm_file_impl.cc
+++ b/chromium/content/browser/media/cdm_file_impl.cc
@@ -10,7 +10,7 @@
#include "base/callback.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "storage/browser/fileapi/file_system_context.h"
#include "storage/browser/fileapi/file_system_operation_context.h"
#include "storage/browser/fileapi/file_system_url.h"
diff --git a/chromium/content/browser/media/flinging_renderer.cc b/chromium/content/browser/media/flinging_renderer.cc
index b6119358422..89ead4205b6 100644
--- a/chromium/content/browser/media/flinging_renderer.cc
+++ b/chromium/content/browser/media/flinging_renderer.cc
@@ -15,10 +15,14 @@
namespace content {
FlingingRenderer::FlingingRenderer(
- std::unique_ptr<media::MediaController> controller)
- : controller_(std::move(controller)) {}
+ std::unique_ptr<media::FlingingController> controller)
+ : controller_(std::move(controller)) {
+ controller_->AddMediaStatusObserver(this);
+}
-FlingingRenderer::~FlingingRenderer() = default;
+FlingingRenderer::~FlingingRenderer() {
+ controller_->RemoveMediaStatusObserver(this);
+};
// static
std::unique_ptr<FlingingRenderer> FlingingRenderer::Create(
@@ -43,15 +47,15 @@ std::unique_ptr<FlingingRenderer> FlingingRenderer::Create(
if (!presentation_delegate)
return nullptr;
- auto media_controller = presentation_delegate->GetMediaController(
+ auto flinging_controller = presentation_delegate->GetFlingingController(
render_frame_host->GetProcess()->GetID(),
render_frame_host->GetRoutingID(), presentation_id);
- if (!media_controller)
+ if (!flinging_controller)
return nullptr;
return base::WrapUnique<FlingingRenderer>(
- new FlingingRenderer(std::move(media_controller)));
+ new FlingingRenderer(std::move(flinging_controller)));
}
// media::Renderer implementation
@@ -59,6 +63,7 @@ void FlingingRenderer::Initialize(media::MediaResource* media_resource,
media::RendererClient* client,
const media::PipelineStatusCB& init_cb) {
DVLOG(2) << __func__;
+ client_ = client;
init_cb.Run(media::PIPELINE_OK);
}
@@ -76,26 +81,40 @@ void FlingingRenderer::Flush(const base::Closure& flush_cb) {
void FlingingRenderer::StartPlayingFrom(base::TimeDelta time) {
DVLOG(2) << __func__;
- controller_->Seek(time);
- controller_->Play();
+ controller_->GetMediaController()->Seek(time);
+
+ // After a seek when using the FlingingRenderer, WMPI will never get back to
+ // BUFFERING_HAVE_ENOUGH. This prevents Blink from getting the appropriate
+ // seek completion signals, and time updates are never re-scheduled.
+ //
+ // The FlingingRenderer doesn't need to buffer, since playback happens on a
+ // different device. This means it's ok to always send BUFFERING_HAVE_ENOUGH
+ // when sending buffering state changes. That being said, sending state
+ // changes here might be surprising, but the same signals are sent from
+ // MediaPlayerRenderer::StartPlayingFrom(), and it has been working mostly
+ // smoothly for all HLS playback.
+ client_->OnBufferingStateChange(media::BUFFERING_HAVE_ENOUGH);
}
void FlingingRenderer::SetPlaybackRate(double playback_rate) {
DVLOG(2) << __func__;
if (playback_rate == 0)
- controller_->Pause();
+ controller_->GetMediaController()->Pause();
else
- controller_->Play();
+ controller_->GetMediaController()->Play();
}
void FlingingRenderer::SetVolume(float volume) {
DVLOG(2) << __func__;
- controller_->SetVolume(volume);
+ controller_->GetMediaController()->SetVolume(volume);
}
base::TimeDelta FlingingRenderer::GetMediaTime() {
- // TODO(https://crbug.com/830871): return correct media time.
- return base::TimeDelta();
+ return controller_->GetApproximateCurrentTime();
+}
+
+void FlingingRenderer::OnMediaStatusUpdated(const media::MediaStatus& status) {
+ // TODO(tguilbert): propagate important changes to RendererClient.
}
} // namespace content
diff --git a/chromium/content/browser/media/flinging_renderer.h b/chromium/content/browser/media/flinging_renderer.h
index 38c411cd6d5..023c216dbcf 100644
--- a/chromium/content/browser/media/flinging_renderer.h
+++ b/chromium/content/browser/media/flinging_renderer.h
@@ -7,8 +7,9 @@
#include "base/callback.h"
#include "content/common/content_export.h"
-#include "media/base/media_controller.h"
+#include "media/base/flinging_controller.h"
#include "media/base/media_resource.h"
+#include "media/base/media_status_observer.h"
#include "media/base/renderer.h"
#include "media/base/renderer_client.h"
#include "url/gurl.h"
@@ -23,7 +24,8 @@ class RenderFrameHost;
// playback commands. In this case, the media we are controlling should be an
// already existing RemotingCastSession, which should have been initiated by a
// blink::RemotePlayback object, using the PresentationService.
-class CONTENT_EXPORT FlingingRenderer : public media::Renderer {
+class CONTENT_EXPORT FlingingRenderer : public media::Renderer,
+ media::MediaStatusObserver {
public:
// Helper method to create a FlingingRenderer from an already existing
// presentation ID.
@@ -47,12 +49,18 @@ class CONTENT_EXPORT FlingingRenderer : public media::Renderer {
void SetVolume(float volume) override;
base::TimeDelta GetMediaTime() override;
+ // media::MediaStatusObserver implementation.
+ void OnMediaStatusUpdated(const media::MediaStatus& status) override;
+
private:
friend class FlingingRendererTest;
- explicit FlingingRenderer(std::unique_ptr<media::MediaController> controller);
+ explicit FlingingRenderer(
+ std::unique_ptr<media::FlingingController> controller);
+
+ media::RendererClient* client_;
- std::unique_ptr<media::MediaController> controller_;
+ std::unique_ptr<media::FlingingController> controller_;
DISALLOW_COPY_AND_ASSIGN(FlingingRenderer);
};
diff --git a/chromium/content/browser/media/flinging_renderer_unittest.cc b/chromium/content/browser/media/flinging_renderer_unittest.cc
index 680ac22101c..28395a2da23 100644
--- a/chromium/content/browser/media/flinging_renderer_unittest.cc
+++ b/chromium/content/browser/media/flinging_renderer_unittest.cc
@@ -4,6 +4,9 @@
#include "content/browser/media/flinging_renderer.h"
+#include "base/bind_helpers.h"
+#include "base/memory/ptr_util.h"
+#include "base/time/time.h"
#include "base/version.h"
#include "media/base/media_controller.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -11,6 +14,7 @@
using ::testing::_;
using ::testing::StrictMock;
+using ::testing::NiceMock;
namespace content {
@@ -23,44 +27,82 @@ class MockMediaController : public media::MediaController {
MOCK_METHOD1(Seek, void(base::TimeDelta));
};
+class MockRendererClient : public media::RendererClient {
+ public:
+ MOCK_METHOD1(OnError, void(media::PipelineStatus));
+ MOCK_METHOD0(OnEnded, void());
+ MOCK_METHOD1(OnStatisticsUpdate, void(const media::PipelineStatistics&));
+ MOCK_METHOD1(OnBufferingStateChange, void(media::BufferingState));
+ MOCK_METHOD0(OnWaitingForDecryptionKey, void());
+ MOCK_METHOD1(OnAudioConfigChange, void(const media::AudioDecoderConfig&));
+ MOCK_METHOD1(OnVideoConfigChange, void(const media::VideoDecoderConfig&));
+ MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size&));
+ MOCK_METHOD1(OnVideoOpacityChange, void(bool));
+ MOCK_METHOD1(OnDurationChange, void(base::TimeDelta));
+};
+
+class MockFlingingController : public media::FlingingController {
+ public:
+ explicit MockFlingingController(media::MediaController* media_controller)
+ : media_controller_(media_controller) {}
+
+ media::MediaController* GetMediaController() { return media_controller_; }
+
+ MOCK_METHOD1(AddMediaStatusObserver, void(media::MediaStatusObserver*));
+ MOCK_METHOD1(RemoveMediaStatusObserver, void(media::MediaStatusObserver*));
+ MOCK_METHOD0(GetApproximateCurrentTime, base::TimeDelta());
+
+ private:
+ media::MediaController* media_controller_;
+};
+
class FlingingRendererTest : public testing::Test {
public:
FlingingRendererTest()
: media_controller_(new StrictMock<MockMediaController>()),
- renderer_(std::unique_ptr<media::MediaController>(media_controller_)) {}
+ flinging_controller_(
+ new StrictMock<MockFlingingController>(media_controller_.get())) {
+ EXPECT_CALL(*flinging_controller_, AddMediaStatusObserver(_));
+ EXPECT_CALL(*flinging_controller_, RemoveMediaStatusObserver(_));
+
+ renderer_ = base::WrapUnique(new FlingingRenderer(
+ std::unique_ptr<media::FlingingController>(flinging_controller_)));
+
+ renderer_->Initialize(nullptr, &renderer_client_, base::DoNothing());
+ }
protected:
- StrictMock<MockMediaController>* media_controller_;
- FlingingRenderer renderer_;
+ NiceMock<MockRendererClient> renderer_client_;
+ std::unique_ptr<MockMediaController> media_controller_;
+ StrictMock<MockFlingingController>* flinging_controller_;
+ std::unique_ptr<FlingingRenderer> renderer_;
};
TEST_F(FlingingRendererTest, StartPlayingFromTime) {
base::TimeDelta seek_time = base::TimeDelta::FromSeconds(10);
- EXPECT_CALL(*media_controller_, Play());
EXPECT_CALL(*media_controller_, Seek(seek_time));
- renderer_.StartPlayingFrom(seek_time);
+ renderer_->StartPlayingFrom(seek_time);
}
TEST_F(FlingingRendererTest, StartPlayingFromBeginning) {
- EXPECT_CALL(*media_controller_, Play());
EXPECT_CALL(*media_controller_, Seek(base::TimeDelta()));
- renderer_.StartPlayingFrom(base::TimeDelta());
+ renderer_->StartPlayingFrom(base::TimeDelta());
}
TEST_F(FlingingRendererTest, SetPlaybackRate) {
double playback_rate = 1.0;
EXPECT_CALL(*media_controller_, Play());
- renderer_.SetPlaybackRate(playback_rate);
+ renderer_->SetPlaybackRate(playback_rate);
}
TEST_F(FlingingRendererTest, SetPlaybackRateToZero) {
double playback_rate = 0.0;
EXPECT_CALL(*media_controller_, Pause());
- renderer_.SetPlaybackRate(playback_rate);
+ renderer_->SetPlaybackRate(playback_rate);
}
// Setting the volume to a positive value should not change the mute state.
@@ -69,7 +111,7 @@ TEST_F(FlingingRendererTest, SetVolume) {
EXPECT_CALL(*media_controller_, SetVolume(volume));
EXPECT_CALL(*media_controller_, SetMute(_)).Times(0);
- renderer_.SetVolume(volume);
+ renderer_->SetVolume(volume);
}
// Setting the volume to 0 should not set the mute state.
@@ -78,7 +120,7 @@ TEST_F(FlingingRendererTest, SetVolumeToZero) {
EXPECT_CALL(*media_controller_, SetVolume(volume));
EXPECT_CALL(*media_controller_, SetMute(_)).Times(0);
- renderer_.SetVolume(volume);
+ renderer_->SetVolume(volume);
}
} // namespace content
diff --git a/chromium/content/browser/media/forwarding_audio_stream_factory.cc b/chromium/content/browser/media/forwarding_audio_stream_factory.cc
index 694f8bfe4d2..f9181735959 100644
--- a/chromium/content/browser/media/forwarding_audio_stream_factory.cc
+++ b/chromium/content/browser/media/forwarding_audio_stream_factory.cc
@@ -13,11 +13,49 @@
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
+#include "media/audio/audio_device_description.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/audio/public/mojom/constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
namespace content {
+namespace {
+
+// A mojom::RendererAudioInputStreamFactoryClient that holds a
+// AudioLoopbackStreamCreator::StreamCreatedCallback. The callback runs when the
+// requested audio stream is created.
+class StreamCreatedCallbackAdapter final
+ : public mojom::RendererAudioInputStreamFactoryClient {
+ public:
+ explicit StreamCreatedCallbackAdapter(
+ const AudioLoopbackStreamCreator::StreamCreatedCallback& callback)
+ : callback_(callback) {
+ DCHECK(callback_);
+ }
+
+ ~StreamCreatedCallbackAdapter() override {}
+
+ // mojom::RendererAudioInputStreamFactoryClient implementation.
+ void StreamCreated(
+ media::mojom::AudioInputStreamPtr stream,
+ media::mojom::AudioInputStreamClientRequest client_request,
+ media::mojom::ReadOnlyAudioDataPipePtr data_pipe,
+ bool initially_muted,
+ const base::Optional<base::UnguessableToken>& stream_id) override {
+ DCHECK(!initially_muted); // Loopback streams shouldn't be started muted.
+ callback_.Run(std::move(stream), std::move(client_request),
+ std::move(data_pipe));
+ }
+
+ private:
+ const AudioLoopbackStreamCreator::StreamCreatedCallback callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(StreamCreatedCallbackAdapter);
+};
+
+} // namespace
+
ForwardingAudioStreamFactory::ForwardingAudioStreamFactory(
WebContents* web_contents,
std::unique_ptr<service_manager::Connector> connector,
@@ -27,7 +65,6 @@ ForwardingAudioStreamFactory::ForwardingAudioStreamFactory(
broker_factory_(std::move(broker_factory)),
group_id_(base::UnguessableToken::Create()) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- DCHECK(web_contents);
DCHECK(broker_factory_);
}
@@ -54,15 +91,16 @@ void ForwardingAudioStreamFactory::CreateInputStream(
const media::AudioParameters& params,
uint32_t shared_memory_count,
bool enable_agc,
+ audio::mojom::AudioProcessingConfigPtr processing_config,
mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- const int process_id = frame->GetProcess()->GetID();
- const int frame_id = frame->GetRoutingID();
+ const int process_id = frame ? frame->GetProcess()->GetID() : -1;
+ const int frame_id = frame ? frame->GetRoutingID() : -1;
inputs_
.insert(broker_factory_->CreateAudioInputStreamBroker(
process_id, frame_id, device_id, params, shared_memory_count,
- enable_agc,
+ enable_agc, std::move(processing_config),
base::BindOnce(&ForwardingAudioStreamFactory::RemoveInput,
base::Unretained(this)),
std::move(renderer_factory_client)))
@@ -75,7 +113,7 @@ void ForwardingAudioStreamFactory::AssociateInputAndOutputForAec(
const std::string& raw_output_device_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Avoid spawning a factory if this for some reason gets called with an
- // invalid input_stream_id before any streams are created.
+ // invalid |input_stream_id| before any streams are created.
if (!inputs_.empty()) {
GetFactory()->AssociateInputAndOutputForAec(input_stream_id,
raw_output_device_id);
@@ -86,6 +124,7 @@ void ForwardingAudioStreamFactory::CreateOutputStream(
RenderFrameHost* frame,
const std::string& device_id,
const media::AudioParameters& params,
+ const base::Optional<base::UnguessableToken>& processing_id,
media::mojom::AudioOutputStreamProviderClientPtr client) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -95,7 +134,7 @@ void ForwardingAudioStreamFactory::CreateOutputStream(
outputs_
.insert(broker_factory_->CreateAudioOutputStreamBroker(
process_id, frame_id, ++stream_id_counter_, device_id, params,
- group_id_,
+ group_id_, processing_id,
base::BindOnce(&ForwardingAudioStreamFactory::RemoveOutput,
base::Unretained(this)),
std::move(client)))
@@ -111,7 +150,6 @@ void ForwardingAudioStreamFactory::CreateLoopbackStream(
bool mute_source,
mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- DCHECK(frame);
DCHECK(frame_of_source_web_contents);
TRACE_EVENT_BEGIN1("audio", "CreateLoopbackStream", "group",
@@ -125,8 +163,8 @@ void ForwardingAudioStreamFactory::CreateLoopbackStream(
return;
}
- const int process_id = frame->GetProcess()->GetID();
- const int frame_id = frame->GetRoutingID();
+ const int process_id = frame ? frame->GetProcess()->GetID() : -1;
+ const int frame_id = frame ? frame->GetRoutingID() : -1;
inputs_
.insert(broker_factory_->CreateAudioLoopbackStreamBroker(
process_id, frame_id,
@@ -145,6 +183,29 @@ void ForwardingAudioStreamFactory::CreateLoopbackStream(
.GetLowForSerialization());
}
+void ForwardingAudioStreamFactory::CreateInProcessLoopbackStream(
+ RenderFrameHost* frame_of_source_web_contents,
+ const media::AudioParameters& params,
+ uint32_t shared_memory_count,
+ const AudioLoopbackStreamCreator::StreamCreatedCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ mojom::RendererAudioInputStreamFactoryClientPtr client;
+ mojo::MakeStrongBinding(
+ std::make_unique<StreamCreatedCallbackAdapter>(callback),
+ mojo::MakeRequest(&client));
+ if (frame_of_source_web_contents) {
+ CreateLoopbackStream(nullptr, frame_of_source_web_contents, params,
+ shared_memory_count, true /* mute_source */,
+ std::move(client));
+ } else {
+ // A null |frame_of_source_web_contents| requests system-wide loopback.
+ CreateInputStream(nullptr,
+ media::AudioDeviceDescription::kLoopbackWithMuteDeviceId,
+ params, shared_memory_count, false /* enable_agc */,
+ nullptr /* processing_config */, std::move(client));
+ }
+}
+
void ForwardingAudioStreamFactory::SetMuted(bool muted) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_NE(muted, IsMuted());
@@ -176,8 +237,10 @@ void ForwardingAudioStreamFactory::CleanupStreamsBelongingTo(
RenderFrameHost* render_frame_host) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- const int process_id = render_frame_host->GetProcess()->GetID();
- const int frame_id = render_frame_host->GetRoutingID();
+ const int process_id =
+ render_frame_host ? render_frame_host->GetProcess()->GetID() : -1;
+ const int frame_id =
+ render_frame_host ? render_frame_host->GetRoutingID() : -1;
TRACE_EVENT_BEGIN2("audio", "CleanupStreamsBelongingTo", "group",
group_id_.GetLowForSerialization(), "process id",
diff --git a/chromium/content/browser/media/forwarding_audio_stream_factory.h b/chromium/content/browser/media/forwarding_audio_stream_factory.h
index 26ffbb89bbb..6c1bfbc8dd9 100644
--- a/chromium/content/browser/media/forwarding_audio_stream_factory.h
+++ b/chromium/content/browser/media/forwarding_audio_stream_factory.h
@@ -17,6 +17,7 @@
#include "content/browser/media/audio_stream_broker.h"
#include "content/common/content_export.h"
#include "content/common/media/renderer_audio_input_stream_factory.mojom.h"
+#include "content/public/browser/audio_loopback_stream_creator.h"
#include "content/public/browser/web_contents_observer.h"
#include "services/audio/public/mojom/stream_factory.mojom.h"
@@ -39,6 +40,8 @@ class WebContents;
class CONTENT_EXPORT ForwardingAudioStreamFactory final
: public WebContentsObserver {
public:
+ // |web_contents| is null in the browser-privileged access case, i.e., when
+ // the streams created with this factory will not be consumed by a renderer.
ForwardingAudioStreamFactory(
WebContents* web_contents,
std::unique_ptr<service_manager::Connector> connector,
@@ -61,6 +64,7 @@ class CONTENT_EXPORT ForwardingAudioStreamFactory final
const media::AudioParameters& params,
uint32_t shared_memory_count,
bool enable_agc,
+ audio::mojom::AudioProcessingConfigPtr processing_config,
mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client);
void AssociateInputAndOutputForAec(
@@ -71,6 +75,7 @@ class CONTENT_EXPORT ForwardingAudioStreamFactory final
RenderFrameHost* frame,
const std::string& device_id,
const media::AudioParameters& params,
+ const base::Optional<base::UnguessableToken>& processing_id,
media::mojom::AudioOutputStreamProviderClientPtr client);
void CreateLoopbackStream(
@@ -81,6 +86,15 @@ class CONTENT_EXPORT ForwardingAudioStreamFactory final
bool mute_source,
mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client);
+ // Creates a loopback stream that captures the audio from
+ // |frame_of_source_web_contents|, or the default system playback if the
+ // source is not provided. The source/system audio is muted during capturing.
+ void CreateInProcessLoopbackStream(
+ RenderFrameHost* frame_of_source_web_contents,
+ const media::AudioParameters& params,
+ uint32_t shared_memory_count,
+ const AudioLoopbackStreamCreator::StreamCreatedCallback& callback);
+
// Sets the muting state for all output streams created through this factory.
void SetMuted(bool muted);
diff --git a/chromium/content/browser/media/forwarding_audio_stream_factory_unittest.cc b/chromium/content/browser/media/forwarding_audio_stream_factory_unittest.cc
index e0764947aa1..421f66bdac7 100644
--- a/chromium/content/browser/media/forwarding_audio_stream_factory_unittest.cc
+++ b/chromium/content/browser/media/forwarding_audio_stream_factory_unittest.cc
@@ -111,6 +111,7 @@ class MockBrokerFactory : public AudioStreamBrokerFactory {
const media::AudioParameters& params,
uint32_t shared_memory_count,
bool enable_agc,
+ audio::mojom::AudioProcessingConfigPtr processing_config,
AudioStreamBroker::DeleterCallback deleter,
mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client)
final {
@@ -131,6 +132,7 @@ class MockBrokerFactory : public AudioStreamBrokerFactory {
const std::string& output_device_id,
const media::AudioParameters& params,
const base::UnguessableToken& group_id,
+ const base::Optional<base::UnguessableToken>& processing_id,
AudioStreamBroker::DeleterCallback deleter,
media::mojom::AudioOutputStreamProviderClientPtr client) final {
std::unique_ptr<MockBroker> prepared_broker =
@@ -257,7 +259,8 @@ TEST_F(ForwardingAudioStreamFactoryTest, CreateInputStream_CreatesInputStream) {
EXPECT_CALL(*broker, CreateStream(NotNull()));
mojo::MakeRequest(&client);
factory.CreateInputStream(main_rfh(), kInputDeviceId, kParams,
- kSharedMemoryCount, kEnableAgc, std::move(client));
+ kSharedMemoryCount, kEnableAgc, nullptr,
+ std::move(client));
}
TEST_F(ForwardingAudioStreamFactoryTest,
@@ -288,7 +291,7 @@ TEST_F(ForwardingAudioStreamFactoryTest,
EXPECT_CALL(*broker, CreateStream(NotNull()));
mojo::MakeRequest(&client);
factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams,
- std::move(client));
+ base::nullopt, std::move(client));
}
TEST_F(ForwardingAudioStreamFactoryTest,
@@ -306,7 +309,7 @@ TEST_F(ForwardingAudioStreamFactoryTest,
EXPECT_CALL(*main_rfh_broker, CreateStream(NotNull()));
mojo::MakeRequest(&client);
factory.CreateInputStream(main_rfh(), kInputDeviceId, kParams,
- kSharedMemoryCount, kEnableAgc,
+ kSharedMemoryCount, kEnableAgc, nullptr,
std::move(client));
testing::Mock::VerifyAndClear(&*main_rfh_broker);
}
@@ -314,7 +317,7 @@ TEST_F(ForwardingAudioStreamFactoryTest,
EXPECT_CALL(*other_rfh_broker, CreateStream(NotNull()));
mojo::MakeRequest(&client);
factory.CreateInputStream(other_rfh(), kInputDeviceId, kParams,
- kSharedMemoryCount, kEnableAgc,
+ kSharedMemoryCount, kEnableAgc, nullptr,
std::move(client));
testing::Mock::VerifyAndClear(&*other_rfh_broker);
}
@@ -375,14 +378,14 @@ TEST_F(ForwardingAudioStreamFactoryTest,
EXPECT_CALL(*main_rfh_broker, CreateStream(NotNull()));
mojo::MakeRequest(&client);
factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams,
- std::move(client));
+ base::nullopt, std::move(client));
testing::Mock::VerifyAndClear(&*main_rfh_broker);
}
{
EXPECT_CALL(*other_rfh_broker, CreateStream(NotNull()));
mojo::MakeRequest(&client);
factory.CreateOutputStream(other_rfh(), kOutputDeviceId, kParams,
- std::move(client));
+ base::nullopt, std::move(client));
testing::Mock::VerifyAndClear(&*other_rfh_broker);
}
@@ -419,7 +422,7 @@ TEST_F(ForwardingAudioStreamFactoryTest, DestroyFrame_DestroysRelatedStreams) {
EXPECT_CALL(*main_rfh_input_broker, CreateStream(NotNull()));
mojo::MakeRequest(&input_client);
factory.CreateInputStream(main_rfh(), kInputDeviceId, kParams,
- kSharedMemoryCount, kEnableAgc,
+ kSharedMemoryCount, kEnableAgc, nullptr,
std::move(input_client));
testing::Mock::VerifyAndClear(&*main_rfh_input_broker);
}
@@ -427,7 +430,7 @@ TEST_F(ForwardingAudioStreamFactoryTest, DestroyFrame_DestroysRelatedStreams) {
EXPECT_CALL(*other_rfh_input_broker, CreateStream(NotNull()));
mojo::MakeRequest(&input_client);
factory.CreateInputStream(other_rfh(), kInputDeviceId, kParams,
- kSharedMemoryCount, kEnableAgc,
+ kSharedMemoryCount, kEnableAgc, nullptr,
std::move(input_client));
testing::Mock::VerifyAndClear(&*other_rfh_input_broker);
}
@@ -453,14 +456,14 @@ TEST_F(ForwardingAudioStreamFactoryTest, DestroyFrame_DestroysRelatedStreams) {
EXPECT_CALL(*main_rfh_output_broker, CreateStream(NotNull()));
mojo::MakeRequest(&output_client);
factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams,
- std::move(output_client));
+ base::nullopt, std::move(output_client));
testing::Mock::VerifyAndClear(&*main_rfh_output_broker);
}
{
EXPECT_CALL(*other_rfh_output_broker, CreateStream(NotNull()));
mojo::MakeRequest(&output_client);
factory.CreateOutputStream(other_rfh(), kOutputDeviceId, kParams,
- std::move(output_client));
+ base::nullopt, std::move(output_client));
testing::Mock::VerifyAndClear(&*other_rfh_output_broker);
}
@@ -493,13 +496,13 @@ TEST_F(ForwardingAudioStreamFactoryTest, DestroyWebContents_DestroysStreams) {
EXPECT_CALL(*input_broker, CreateStream(NotNull()));
mojo::MakeRequest(&input_client);
factory.CreateInputStream(main_rfh(), kInputDeviceId, kParams,
- kSharedMemoryCount, kEnableAgc,
+ kSharedMemoryCount, kEnableAgc, nullptr,
std::move(input_client));
EXPECT_CALL(*output_broker, CreateStream(NotNull()));
mojo::MakeRequest(&output_client);
factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams,
- std::move(output_client));
+ base::nullopt, std::move(output_client));
DeleteContents();
base::RunLoop().RunUntilIdle();
@@ -530,7 +533,7 @@ TEST_F(ForwardingAudioStreamFactoryTest, LastStreamDeleted_ClearsFactoryPtr) {
EXPECT_CALL(*main_rfh_input_broker, CreateStream(NotNull()));
mojo::MakeRequest(&input_client);
factory.CreateInputStream(main_rfh(), kInputDeviceId, kParams,
- kSharedMemoryCount, kEnableAgc,
+ kSharedMemoryCount, kEnableAgc, nullptr,
std::move(input_client));
testing::Mock::VerifyAndClear(&*main_rfh_input_broker);
}
@@ -538,7 +541,7 @@ TEST_F(ForwardingAudioStreamFactoryTest, LastStreamDeleted_ClearsFactoryPtr) {
EXPECT_CALL(*other_rfh_input_broker, CreateStream(NotNull()));
mojo::MakeRequest(&input_client);
factory.CreateInputStream(other_rfh(), kInputDeviceId, kParams,
- kSharedMemoryCount, kEnableAgc,
+ kSharedMemoryCount, kEnableAgc, nullptr,
std::move(input_client));
testing::Mock::VerifyAndClear(&*other_rfh_input_broker);
}
@@ -547,14 +550,14 @@ TEST_F(ForwardingAudioStreamFactoryTest, LastStreamDeleted_ClearsFactoryPtr) {
EXPECT_CALL(*main_rfh_output_broker, CreateStream(NotNull()));
mojo::MakeRequest(&output_client);
factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams,
- std::move(output_client));
+ base::nullopt, std::move(output_client));
testing::Mock::VerifyAndClear(&*main_rfh_output_broker);
}
{
EXPECT_CALL(*other_rfh_output_broker, CreateStream(NotNull()));
mojo::MakeRequest(&output_client);
factory.CreateOutputStream(other_rfh(), kOutputDeviceId, kParams,
- std::move(output_client));
+ base::nullopt, std::move(output_client));
testing::Mock::VerifyAndClear(&*other_rfh_output_broker);
}
@@ -606,7 +609,7 @@ TEST_F(ForwardingAudioStreamFactoryTest, MuteWithOutputStream_ConnectsMuter) {
EXPECT_CALL(*broker, CreateStream(NotNull()));
mojo::MakeRequest(&client);
factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams,
- std::move(client));
+ base::nullopt, std::move(client));
base::RunLoop().RunUntilIdle();
testing::Mock::VerifyAndClear(&*broker);
@@ -645,7 +648,7 @@ TEST_F(ForwardingAudioStreamFactoryTest,
EXPECT_CALL(*broker, CreateStream(NotNull()));
mojo::MakeRequest(&client);
factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams,
- std::move(client));
+ base::nullopt, std::move(client));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(factory.IsMuted());
EXPECT_TRUE(stream_factory_.IsConnected());
@@ -673,7 +676,7 @@ TEST_F(ForwardingAudioStreamFactoryTest,
EXPECT_CALL(*broker, CreateStream(NotNull()));
mojo::MakeRequest(&client);
factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams,
- std::move(client));
+ base::nullopt, std::move(client));
base::RunLoop().RunUntilIdle();
testing::Mock::VerifyAndClear(&*broker);
}
@@ -690,7 +693,7 @@ TEST_F(ForwardingAudioStreamFactoryTest,
EXPECT_CALL(*another_broker, CreateStream(NotNull()));
mojo::MakeRequest(&client);
factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams,
- std::move(client));
+ base::nullopt, std::move(client));
base::RunLoop().RunUntilIdle();
testing::Mock::VerifyAndClear(&*another_broker);
}
diff --git a/chromium/content/browser/media/in_process_audio_loopback_stream_creator.cc b/chromium/content/browser/media/in_process_audio_loopback_stream_creator.cc
new file mode 100644
index 00000000000..618c9b8f3a5
--- /dev/null
+++ b/chromium/content/browser/media/in_process_audio_loopback_stream_creator.cc
@@ -0,0 +1,44 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/in_process_audio_loopback_stream_creator.h"
+
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/service_manager_connection.h"
+#include "services/service_manager/public/cpp/connector.h"
+
+namespace content {
+
+InProcessAudioLoopbackStreamCreator::InProcessAudioLoopbackStreamCreator()
+ : factory_(nullptr,
+ content::ServiceManagerConnection::GetForProcess()
+ ->GetConnector()
+ ->Clone(),
+ AudioStreamBrokerFactory::CreateImpl()) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+}
+
+InProcessAudioLoopbackStreamCreator::~InProcessAudioLoopbackStreamCreator() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ factory_.FrameDeleted(nullptr);
+}
+
+void InProcessAudioLoopbackStreamCreator::CreateLoopbackStream(
+ WebContents* loopback_source,
+ const media::AudioParameters& params,
+ uint32_t total_segments,
+ const StreamCreatedCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ RenderFrameHost* loopback_source_frame = nullptr;
+ if (loopback_source) {
+ loopback_source_frame = loopback_source->GetMainFrame();
+ DCHECK(loopback_source_frame);
+ }
+ factory_.CreateInProcessLoopbackStream(loopback_source_frame, params,
+ total_segments, callback);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/in_process_audio_loopback_stream_creator.h b/chromium/content/browser/media/in_process_audio_loopback_stream_creator.h
new file mode 100644
index 00000000000..09b9c050915
--- /dev/null
+++ b/chromium/content/browser/media/in_process_audio_loopback_stream_creator.h
@@ -0,0 +1,41 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_MEDIA_IN_PROCESS_AUDIO_LOOPBACK_STREAM_CREATOR_H_
+#define CONTENT_BROWSER_MEDIA_IN_PROCESS_AUDIO_LOOPBACK_STREAM_CREATOR_H_
+
+#include "base/macros.h"
+#include "content/browser/media/forwarding_audio_stream_factory.h"
+#include "content/public/browser/audio_loopback_stream_creator.h"
+
+namespace media {
+class AudioParameters;
+}
+
+namespace content {
+
+// This class handles creating a loopback stream that either captures audio from
+// a WebContents or the system-wide loopback through the Audio Service.
+// This class is operated on the UI thread.
+class CONTENT_EXPORT InProcessAudioLoopbackStreamCreator final
+ : public AudioLoopbackStreamCreator {
+ public:
+ InProcessAudioLoopbackStreamCreator();
+ ~InProcessAudioLoopbackStreamCreator() override;
+
+ private:
+ // AudioLoopbackStreamCreator implementation.
+ void CreateLoopbackStream(WebContents* loopback_source,
+ const media::AudioParameters& params,
+ uint32_t total_segments,
+ const StreamCreatedCallback& callback) override;
+
+ ForwardingAudioStreamFactory factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(InProcessAudioLoopbackStreamCreator);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_IN_PROCESS_AUDIO_LOOPBACK_STREAM_CREATOR_H_
diff --git a/chromium/content/browser/media/media_browsertest.cc b/chromium/content/browser/media/media_browsertest.cc
index 8e6045d5d33..93bea4f82b9 100644
--- a/chromium/content/browser/media/media_browsertest.cc
+++ b/chromium/content/browser/media/media_browsertest.cc
@@ -156,11 +156,15 @@ IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearWebm) {
PlayVideo("bear.webm", GetParam());
}
-IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearOpusWebm) {
+IN_PROC_BROWSER_TEST_P(MediaTest, AudioBearOpusWebm) {
PlayVideo("bear-opus.webm", GetParam());
}
-IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearOpusOgg) {
+IN_PROC_BROWSER_TEST_P(MediaTest, AudioBearOpusMp4) {
+ PlayVideo("bear-opus.mp4", GetParam());
+}
+
+IN_PROC_BROWSER_TEST_P(MediaTest, AudioBearOpusOgg) {
PlayVideo("bear-opus.ogg", GetParam());
}
@@ -179,11 +183,6 @@ IN_PROC_BROWSER_TEST_P(MediaTest, VideoBear12DepthVP9) {
}
#endif
-#if BUILDFLAG(USE_PROPRIETARY_CODECS)
-IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearMp4) {
- PlayVideo("bear.mp4", GetParam());
-}
-
IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearMp4Vp9) {
PlayVideo("bear-320x240-v_frag-vp9.mp4", GetParam());
}
@@ -196,20 +195,6 @@ IN_PROC_BROWSER_TEST_P(MediaTest, AudioBearFlac192kHzMp4) {
PlayAudio("bear-flac-192kHz.mp4", GetParam());
}
-// Android devices usually only support baseline, main and high.
-#if !defined(OS_ANDROID)
-IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearHighBitDepthMp4) {
- PlayVideo("bear-320x180-hi10p.mp4", GetParam());
-}
-#endif // !defined(OS_ANDROID)
-
-IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearSilentMp4) {
- PlayVideo("bear_silent.mp4", GetParam());
-}
-
-// While we support the big endian (be) PCM codecs on Chromium, Quicktime seems
-// to be the only creator of this format and only for .mov files.
-// TODO(dalecurtis/ihf): Find or create some .wav test cases for "be" format.
IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearMovPcmS16be) {
PlayVideo("bear_pcm_s16be.mov", GetParam());
}
@@ -218,6 +203,15 @@ IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearMovPcmS24be) {
PlayVideo("bear_pcm_s24be.mov", GetParam());
}
+#if BUILDFLAG(USE_PROPRIETARY_CODECS)
+IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearMp4) {
+ PlayVideo("bear.mp4", GetParam());
+}
+
+IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearSilentMp4) {
+ PlayVideo("bear_silent.mp4", GetParam());
+}
+
IN_PROC_BROWSER_TEST_F(MediaTest, VideoBearRotated0) {
RunVideoSizeTest("bear_rotate_0.mp4", 1280, 720);
}
@@ -234,18 +228,21 @@ IN_PROC_BROWSER_TEST_F(MediaTest, VideoBearRotated270) {
RunVideoSizeTest("bear_rotate_270.mp4", 720, 1280);
}
+#if !defined(OS_ANDROID)
+// Android devices usually only support baseline, main and high.
+IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearHighBitDepthMp4) {
+ PlayVideo("bear-320x180-hi10p.mp4", GetParam());
+}
+
// Android can't reliably load lots of videos on a page.
// See http://crbug.com/749265
-#if !defined(OS_ANDROID)
IN_PROC_BROWSER_TEST_F(MediaTest, LoadManyVideos) {
base::StringPairs query_params;
RunMediaTestPage("load_many_videos.html", query_params, media::kEnded, true);
}
#endif // !defined(OS_ANDROID)
-#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
#if defined(OS_CHROMEOS)
-#if BUILDFLAG(USE_PROPRIETARY_CODECS)
IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearAviMp3Mpeg4) {
PlayVideo("bear_mpeg4_mp3.avi", GetParam());
}
@@ -269,8 +266,8 @@ IN_PROC_BROWSER_TEST_P(MediaTest, VideoBear3gpAmrnbMpeg4) {
IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearWavGsmms) {
PlayAudio("bear_gsm_ms.wav", GetParam());
}
-#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
IN_PROC_BROWSER_TEST_P(MediaTest, AudioBearFlac) {
PlayAudio("bear.flac", GetParam());
diff --git a/chromium/content/browser/media/media_canplaytype_browsertest.cc b/chromium/content/browser/media/media_canplaytype_browsertest.cc
index c517a4bf7c4..47a3ad4f528 100644
--- a/chromium/content/browser/media/media_canplaytype_browsertest.cc
+++ b/chromium/content/browser/media/media_canplaytype_browsertest.cc
@@ -203,11 +203,13 @@ class MediaCanPlayTypeTest : public MediaBrowserTest {
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.4D401E, vorbis\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3.64001F, vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1, opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3, opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.4D401E, opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3.64001F, opus\"'"));
+ if (mime != "audio/mp4" && mime != "video/mp4") {
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"opus\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1, opus\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3, opus\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.4D401E, opus\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3.64001F, opus\"'"));
+ }
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp8\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp9\"'"));
@@ -825,6 +827,8 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1, avc3\"'"));
EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1, flac\"'"));
EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3, flac\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1, opus\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3, opus\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E01E\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42101E\"'"));
@@ -896,6 +900,11 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
CanPlay("'video/mp4; codecs=\"avc1.4D401E, flac\"'"));
EXPECT_EQ(kPropProbably,
CanPlay("'video/mp4; codecs=\"avc3.64001F, flac\"'"));
+ EXPECT_EQ(kProbably, CanPlay("'video/mp4; codecs=\"opus\"'"));
+ EXPECT_EQ(kPropProbably,
+ CanPlay("'video/mp4; codecs=\"avc1.4D401E, opus\"'"));
+ EXPECT_EQ(kPropProbably,
+ CanPlay("'video/mp4; codecs=\"avc3.64001F, opus\"'"));
TestMPEGUnacceptableCombinations("video/mp4");
// This result is incorrect. See https://crbug.com/592889.
@@ -970,6 +979,7 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"avc1.640028,mp4a.A6\"'"));
EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"flac\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/x-m4v; codecs=\"opus\"'"));
TestMPEGUnacceptableCombinations("video/x-m4v");
@@ -988,6 +998,7 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.40.29\"'"));
EXPECT_EQ(kProbably, CanPlay("'audio/mp4; codecs=\"flac\"'"));
+ EXPECT_EQ(kProbably, CanPlay("'audio/mp4; codecs=\"opus\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"avc1\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"avc3\"'"));
@@ -1055,6 +1066,7 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"mp4a.A6\"'"));
EXPECT_EQ(kNot, CanPlay("'video/x-m4a; codecs=\"flac\"'"));
+ EXPECT_EQ(kNot, CanPlay("'video/x-m4a; codecs=\"opus\"'"));
TestMPEGUnacceptableCombinations("audio/x-m4a");
}
diff --git a/chromium/content/browser/media/media_color_browsertest.cc b/chromium/content/browser/media/media_color_browsertest.cc
index 158109139a5..6cc930bb586 100644
--- a/chromium/content/browser/media/media_color_browsertest.cc
+++ b/chromium/content/browser/media/media_color_browsertest.cc
@@ -18,17 +18,15 @@ class MediaColorTest : public MediaBrowserTest {
RunTest(GetFileUrlWithQuery(path, video_file), media::kEnded);
EXPECT_EQ(media::kEnded, final_title);
}
+ void SetUp() override {
+ EnablePixelOutput();
+ MediaBrowserTest::SetUp();
+ }
};
// Android doesn't support Theora.
#if !defined(OS_ANDROID)
-// This fails on Linux: http://crbug.com/767926.
-#if defined(OS_LINUX)
-#define MAYBE_Yuv420pTheora DISABLED_Yuv420pTheora
-#else
-#define MAYBE_Yuv420pTheora Yuv420pTheora
-#endif
-IN_PROC_BROWSER_TEST_F(MediaColorTest, MAYBE_Yuv420pTheora) {
+IN_PROC_BROWSER_TEST_F(MediaColorTest, Yuv420pTheora) {
RunColorTest("yuv420p.ogv");
}
@@ -41,13 +39,7 @@ IN_PROC_BROWSER_TEST_F(MediaColorTest, Yuv444pTheora) {
}
#endif // !defined(OS_ANDROID)
-// This fails on Linux: http://crbug.com/767926.
-#if defined(OS_LINUX)
-#define MAYBE_Yuv420pVp8 DISABLED_Yuv420pVp8
-#else
-#define MAYBE_Yuv420pVp8 Yuv420pVp8
-#endif
-IN_PROC_BROWSER_TEST_F(MediaColorTest, MAYBE_Yuv420pVp8) {
+IN_PROC_BROWSER_TEST_F(MediaColorTest, Yuv420pVp8) {
RunColorTest("yuv420p.webm");
}
@@ -57,20 +49,13 @@ IN_PROC_BROWSER_TEST_F(MediaColorTest, Yuv444pVp9) {
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
-// This fails on some Android devices: http://crbug.com/649199,
-// and Linux: http://crbug.com/767926.
-#if defined(OS_LINUX) || defined(OS_ANDROID)
-#define MAYBE_Yuv420pH264 DISABLED_Yuv420pH264
-#else
-#define MAYBE_Yuv420pH264 Yuv420pH264
-#endif
-IN_PROC_BROWSER_TEST_F(MediaColorTest, MAYBE_Yuv420pH264) {
+IN_PROC_BROWSER_TEST_F(MediaColorTest, Yuv420pH264) {
RunColorTest("yuv420p.mp4");
}
-// This test fails on Android: http://crbug.com/647818, OSX:
-// http://crbug.com/647838 and Linux: http://crbug.com/767926.
-#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_ANDROID)
+// This test fails on Android: http://crbug.com/647818 and OSX:
+// http://crbug.com/647838
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
#define MAYBE_Yuvj420pH264 DISABLED_Yuvj420pH264
#else
#define MAYBE_Yuvj420pH264 Yuvj420pH264
@@ -79,11 +64,8 @@ IN_PROC_BROWSER_TEST_F(MediaColorTest, MAYBE_Yuvj420pH264) {
RunColorTest("yuvj420p.mp4");
}
-// This fails on Linux & ChromeOS: http://crbug.com/647400,
-// Windows: http://crbug.com/647842, and Android: http://crbug.com/649199,
-// http://crbug.com/649185.
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_WIN) || \
- defined(OS_ANDROID)
+// This fails on ChromeOS: http://crbug.com/647400,
+#if defined(OS_CHROMEOS)
#define MAYBE_Yuv420pRec709H264 DISABLED_Yuv420pRec709H264
#else
#define MAYBE_Yuv420pRec709H264 Yuv420pRec709H264
@@ -92,9 +74,9 @@ IN_PROC_BROWSER_TEST_F(MediaColorTest, MAYBE_Yuv420pRec709H264) {
RunColorTest("yuv420p_rec709.mp4");
}
-// This fails on Linux: http://crbug.com/767926. Android doesn't support 10bpc.
+// Android doesn't support 10bpc.
// This test flakes on mac: http://crbug.com/810908
-#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_MACOSX)
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
#define MAYBE_Yuv420pHighBitDepth DISABLED_Yuv420pHighBitDepth
#else
#define MAYBE_Yuv420pHighBitDepth Yuv420pHighBitDepth
diff --git a/chromium/content/browser/media/media_devices_permission_checker.cc b/chromium/content/browser/media/media_devices_permission_checker.cc
index 6a8aee944a5..8c16627a4a1 100644
--- a/chromium/content/browser/media/media_devices_permission_checker.cc
+++ b/chromium/content/browser/media/media_devices_permission_checker.cc
@@ -9,14 +9,12 @@
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/feature_list.h"
#include "content/browser/frame_host/render_frame_host_delegate.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/common/media/media_devices.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
-#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -43,12 +41,10 @@ MediaDevicesManager::BoolDeviceTypes DoCheckPermissionsOnUIThread(
frame_host, origin, MEDIA_DEVICE_AUDIO_CAPTURE);
bool mic_feature_policy = true;
bool camera_feature_policy = true;
- if (base::FeatureList::IsEnabled(features::kUseFeaturePolicyForPermissions)) {
- mic_feature_policy = frame_host->IsFeatureEnabled(
- blink::mojom::FeaturePolicyFeature::kMicrophone);
- camera_feature_policy = frame_host->IsFeatureEnabled(
- blink::mojom::FeaturePolicyFeature::kCamera);
- }
+ mic_feature_policy = frame_host->IsFeatureEnabled(
+ blink::mojom::FeaturePolicyFeature::kMicrophone);
+ camera_feature_policy =
+ frame_host->IsFeatureEnabled(blink::mojom::FeaturePolicyFeature::kCamera);
MediaDevicesManager::BoolDeviceTypes result;
// Speakers.
diff --git a/chromium/content/browser/media/media_devices_permission_checker_unittest.cc b/chromium/content/browser/media/media_devices_permission_checker_unittest.cc
index 5e95d2bdd69..bb82f2e182e 100644
--- a/chromium/content/browser/media/media_devices_permission_checker_unittest.cc
+++ b/chromium/content/browser/media/media_devices_permission_checker_unittest.cc
@@ -5,12 +5,10 @@
#include "content/browser/media/media_devices_permission_checker.h"
#include "base/run_loop.h"
-#include "base/test/scoped_feature_list.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
-#include "content/public/common/content_features.h"
#include "content/public/common/media_stream_request.h"
#include "content/public/test/test_renderer_host.h"
#include "content/test/test_render_view_host.h"
@@ -101,8 +99,6 @@ class MediaDevicesPermissionCheckerTest : public RenderViewHostImplTestHarness {
// feature_policy_unittest.cc and in
// render_frame_host_feature_policy_unittest.cc.
TEST_F(MediaDevicesPermissionCheckerTest, CheckPermissionWithFeaturePolicy) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(features::kUseFeaturePolicyForPermissions);
// Mic and Camera should be enabled by default for a frame (if permission is
// granted).
EXPECT_TRUE(CheckPermission(MEDIA_DEVICE_TYPE_AUDIO_INPUT));
@@ -117,14 +113,6 @@ TEST_F(MediaDevicesPermissionCheckerTest, CheckPermissionWithFeaturePolicy) {
/*enabled=*/false);
EXPECT_TRUE(CheckPermission(MEDIA_DEVICE_TYPE_AUDIO_INPUT));
EXPECT_FALSE(CheckPermission(MEDIA_DEVICE_TYPE_VIDEO_INPUT));
-
- // Ensure that the policy is ignored if kUseFeaturePolicyForPermissions is
- // disabled.
- base::test::ScopedFeatureList empty_feature_list;
- empty_feature_list.InitAndDisableFeature(
- features::kUseFeaturePolicyForPermissions);
- EXPECT_TRUE(CheckPermission(MEDIA_DEVICE_TYPE_AUDIO_INPUT));
- EXPECT_TRUE(CheckPermission(MEDIA_DEVICE_TYPE_VIDEO_INPUT));
}
} // namespace
diff --git a/chromium/content/browser/media/media_internals.cc b/chromium/content/browser/media/media_internals.cc
index 54b72c76803..a4257d16db9 100644
--- a/chromium/content/browser/media/media_internals.cc
+++ b/chromium/content/browser/media/media_internals.cc
@@ -16,6 +16,8 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
+#include "content/browser/media/session/audio_focus_manager.h"
+#include "content/browser/media/session/media_session_impl.h"
#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
@@ -136,6 +138,7 @@ class MediaInternals::AudioLogImpl : public media::mojom::AudioLog,
void OnError() override;
void OnSetVolume(double volume) override;
void OnLogMessage(const std::string& message) override;
+ void OnProcessingStateChanged(const std::string& message) override;
private:
// If possible, i.e. a WebContents exists for the given RenderFrameHostID,
@@ -236,6 +239,11 @@ void MediaInternals::AudioLogImpl::OnSetVolume(double volume) {
&dict);
}
+void MediaInternals::AudioLogImpl::OnProcessingStateChanged(
+ const std::string& message) {
+ SendSingleStringUpdate("processing state", message);
+}
+
void MediaInternals::AudioLogImpl::OnLogMessage(const std::string& message) {
MediaStreamManager::SendMessageToNativeLog(message);
}
@@ -645,6 +653,8 @@ void MediaInternals::AddUpdateCallback(const UpdateCallback& callback) {
base::AutoLock auto_lock(lock_);
can_update_ = true;
+
+ RegisterAudioFocusObserver();
}
void MediaInternals::RemoveUpdateCallback(const UpdateCallback& callback) {
@@ -658,6 +668,9 @@ void MediaInternals::RemoveUpdateCallback(const UpdateCallback& callback) {
base::AutoLock auto_lock(lock_);
can_update_ = !update_callbacks_.empty();
+
+ if (!can_update_)
+ UnregisterAudioFocusObserver();
}
bool MediaInternals::CanUpdate() {
@@ -698,6 +711,35 @@ void MediaInternals::SendVideoCaptureDeviceCapabilities() {
&video_capture_capabilities_cached_data_));
}
+void MediaInternals::SendAudioFocusState() {
+#if !defined(OS_ANDROID)
+ if (!CanUpdate())
+ return;
+
+ base::DictionaryValue audio_focus_data;
+ const std::list<AudioFocusManager::StackRow>& stack =
+ AudioFocusManager::GetInstance()->audio_focus_stack_;
+
+ // We should go backwards through the stack so the top of the stack is always
+ // shown first in the list.
+ base::ListValue stack_data;
+ for (auto iter = stack.rbegin(); iter != stack.rend(); ++iter) {
+ MediaSessionImpl::DebugInfo debug_info =
+ (*iter).media_session->GetDebugInfo();
+ base::DictionaryValue media_session_data;
+ media_session_data.SetKey("name", base::Value(debug_info.name));
+ media_session_data.SetKey("owner", base::Value(debug_info.owner));
+ media_session_data.SetKey("state", base::Value(debug_info.state));
+ stack_data.GetList().push_back(std::move(media_session_data));
+ }
+
+ audio_focus_data.SetKey("sessions", std::move(stack_data));
+
+ SendUpdate(
+ SerializeUpdate("media.onReceiveAudioFocusState", &audio_focus_data));
+#endif // !defined(OS_ANDROID)
+}
+
void MediaInternals::UpdateVideoCaptureDeviceCapabilities(
const std::vector<std::tuple<media::VideoCaptureDeviceDescriptor,
media::VideoCaptureFormats>>&
@@ -778,6 +820,25 @@ void MediaInternals::OnProcessTerminatedForTesting(int process_id) {
uma_handler_->OnProcessTerminated(process_id);
}
+void MediaInternals::OnFocusGained(
+ media_session::mojom::MediaSessionPtr media_session,
+ media_session::mojom::AudioFocusType type) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&MediaInternals::SendAudioFocusState,
+ base::Unretained(this)));
+}
+
+void MediaInternals::OnFocusLost(
+ media_session::mojom::MediaSessionPtr media_session) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&MediaInternals::SendAudioFocusState,
+ base::Unretained(this)));
+}
+
void MediaInternals::SendUpdate(const base::string16& update) {
// SendUpdate() may be called from any thread, but must run on the UI thread.
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
diff --git a/chromium/content/browser/media/media_internals.h b/chromium/content/browser/media/media_internals.h
index 494c251ad9c..7aa7ddcaaa8 100644
--- a/chromium/content/browser/media/media_internals.h
+++ b/chromium/content/browser/media/media_internals.h
@@ -18,6 +18,7 @@
#include "base/strings/string16.h"
#include "base/synchronization/lock.h"
#include "base/values.h"
+#include "content/browser/media/session/audio_focus_observer.h"
#include "content/common/content_export.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
@@ -31,12 +32,19 @@ namespace media {
struct MediaLogEvent;
}
+namespace media_session {
+namespace mojom {
+enum class AudioFocusType;
+} // namespace mojom
+} // namespace media_session
+
namespace content {
// This class stores information about currently active media.
// TODO(crbug.com/812557): Remove inheritance from media::AudioLogFactory once
// the creation of the AudioManager instance moves to the audio service.
class CONTENT_EXPORT MediaInternals : public media::AudioLogFactory,
+ public AudioFocusObserver,
public NotificationObserver {
public:
// Called with the update string.
@@ -74,6 +82,9 @@ class CONTENT_EXPORT MediaInternals : public media::AudioLogFactory,
// UpdateCallback.
void SendVideoCaptureDeviceCapabilities();
+ // Sends all audio focus information to each registered UpdateCallback.
+ void SendAudioFocusState();
+
// Called to inform of the capabilities enumerated for video devices.
void UpdateVideoCaptureDeviceCapabilities(
const std::vector<std::tuple<media::VideoCaptureDeviceDescriptor,
@@ -109,6 +120,12 @@ class CONTENT_EXPORT MediaInternals : public media::AudioLogFactory,
MediaInternals();
+ // AudioFocusObserver implementation.
+ void OnFocusGained(media_session::mojom::MediaSessionPtr media_session,
+ media_session::mojom::AudioFocusType type) override;
+ void OnFocusLost(
+ media_session::mojom::MediaSessionPtr media_session) override;
+
// Sends |update| to each registered UpdateCallback. Safe to call from any
// thread, but will forward to the IO thread.
void SendUpdate(const base::string16& update);
diff --git a/chromium/content/browser/media/media_internals_proxy.cc b/chromium/content/browser/media/media_internals_proxy.cc
index dfadf6b30c4..8526ebc04a4 100644
--- a/chromium/content/browser/media/media_internals_proxy.cc
+++ b/chromium/content/browser/media/media_internals_proxy.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/location.h"
+#include "build/build_config.h"
#include "content/browser/media/media_internals.h"
#include "content/browser/media/media_internals_handler.h"
#include "content/public/browser/browser_thread.h"
@@ -48,6 +49,10 @@ void MediaInternalsProxy::GetEverythingOnIOThread() {
// TODO(xhwang): Investigate whether we can update on UI thread directly.
MediaInternals::GetInstance()->SendAudioStreamData();
MediaInternals::GetInstance()->SendVideoCaptureDeviceCapabilities();
+
+#if !defined(OS_ANDROID)
+ MediaInternals::GetInstance()->SendAudioFocusState();
+#endif
}
void MediaInternalsProxy::UpdateUIOnUIThread(const base::string16& update) {
diff --git a/chromium/content/browser/media/media_internals_unittest.cc b/chromium/content/browser/media/media_internals_unittest.cc
index a02bcadfbf0..033385ac2de 100644
--- a/chromium/content/browser/media/media_internals_unittest.cc
+++ b/chromium/content/browser/media/media_internals_unittest.cc
@@ -12,13 +12,21 @@
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_command_line.h"
#include "base/test/test_message_loop.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
+#include "content/browser/media/session/audio_focus_manager.h"
+#include "content/browser/media/session/media_session_impl.h"
+#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/test/test_web_contents.h"
#include "media/base/audio_parameters.h"
#include "media/base/channel_layout.h"
#include "media/base/media_log.h"
+#include "media/base/media_switches.h"
+#include "services/media_session/public/cpp/switches.h"
+#include "services/media_session/public/mojom/audio_focus.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/size.h"
@@ -97,6 +105,8 @@ class MediaInternalsTestBase {
namespace content {
+using media_session::mojom::AudioFocusType;
+
class MediaInternalsVideoCaptureDeviceTest : public testing::Test,
public MediaInternalsTestBase {
public:
@@ -279,4 +289,145 @@ INSTANTIATE_TEST_CASE_P(
media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER,
media::AudioLogFactory::AUDIO_OUTPUT_STREAM));
+// TODO(https://crbug.com/873320): AudioFocusManager is not available on
+// Android.
+#if !defined(OS_ANDROID)
+
+namespace {
+
+// Test page titles.
+const char kTestTitle1[] = "Test Title 1";
+const char kTestTitle2[] = "Test Title 2";
+
+} // namespace
+
+class MediaInternalsAudioFocusTest : public testing::Test,
+ public MediaInternalsTestBase {
+ public:
+ void SetUp() override {
+ update_cb_ =
+ base::BindRepeating(&MediaInternalsAudioFocusTest::UpdateCallbackImpl,
+ base::Unretained(this));
+
+ scoped_command_line_.GetProcessCommandLine()->AppendSwitch(
+ media_session::switches::kEnableAudioFocus);
+
+ content::MediaInternals::GetInstance()->AddUpdateCallback(update_cb_);
+ browser_context_.reset(new TestBrowserContext());
+ }
+
+ void TearDown() override {
+ content::MediaInternals::GetInstance()->RemoveUpdateCallback(update_cb_);
+ browser_context_.reset();
+ }
+
+ protected:
+ void ExpectValue(base::ListValue expected_list) {
+ base::DictionaryValue expected_data;
+ expected_data.SetKey("sessions", std::move(expected_list));
+ EXPECT_EQ(expected_data, update_data_);
+ }
+
+ std::unique_ptr<TestWebContents> CreateWebContents() {
+ return TestWebContents::Create(
+ browser_context_.get(), SiteInstance::Create(browser_context_.get()));
+ }
+
+ base::Value GetAddressAsValue(MediaSessionImpl* media_session) {
+ std::stringstream stream;
+ stream << media_session;
+ return base::Value(stream.str());
+ }
+
+ void RemoveAllPlayersForTest(MediaSessionImpl* session) {
+ session->RemoveAllPlayersForTest();
+ }
+
+ void WaitForCallback() {
+ AudioFocusManager::GetInstance()->FlushForTesting();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ MediaInternals::UpdateCallback update_cb_;
+
+ private:
+ base::test::ScopedCommandLine scoped_command_line_;
+ std::unique_ptr<TestBrowserContext> browser_context_;
+};
+
+TEST_F(MediaInternalsAudioFocusTest, AudioFocusStateIsUpdated) {
+ // Create a test media session and request audio focus.
+ std::unique_ptr<TestWebContents> web_contents1 = CreateWebContents();
+ web_contents1->SetTitle(base::UTF8ToUTF16(kTestTitle1));
+ MediaSessionImpl* media_session1 = MediaSessionImpl::Get(web_contents1.get());
+ media_session1->RequestSystemAudioFocus(AudioFocusType::kGain);
+ WaitForCallback();
+
+ // Check JSON is what we expect.
+ {
+ base::DictionaryValue expected_session;
+ expected_session.SetKey("name", GetAddressAsValue(media_session1));
+ expected_session.SetKey("owner", base::Value(kTestTitle1));
+ expected_session.SetKey("state", base::Value("Active"));
+
+ base::ListValue expected_list;
+ expected_list.GetList().push_back(std::move(expected_session));
+ ExpectValue(std::move(expected_list));
+ }
+
+ // Create another media session.
+ std::unique_ptr<TestWebContents> web_contents2 = CreateWebContents();
+ web_contents2->SetTitle(base::UTF8ToUTF16(kTestTitle2));
+ MediaSessionImpl* media_session2 = MediaSessionImpl::Get(web_contents2.get());
+ media_session2->RequestSystemAudioFocus(
+ AudioFocusType::kGainTransientMayDuck);
+ WaitForCallback();
+
+ // Check JSON is what we expect.
+ {
+ base::DictionaryValue expected_session1;
+ expected_session1.SetKey("name", GetAddressAsValue(media_session2));
+ expected_session1.SetKey("owner", base::Value(kTestTitle2));
+ expected_session1.SetKey("state", base::Value("Active"));
+
+ base::DictionaryValue expected_session2;
+ expected_session2.SetKey("name", GetAddressAsValue(media_session1));
+ expected_session2.SetKey("owner", base::Value(kTestTitle1));
+ expected_session2.SetKey("state", base::Value("Active Ducked"));
+
+ base::ListValue expected_list;
+ expected_list.GetList().push_back(std::move(expected_session1));
+ expected_list.GetList().push_back(std::move(expected_session2));
+ ExpectValue(std::move(expected_list));
+ }
+
+ // Abandon audio focus.
+ RemoveAllPlayersForTest(media_session2);
+ WaitForCallback();
+
+ // Check JSON is what we expect.
+ {
+ base::DictionaryValue expected_session;
+ expected_session.SetKey("name", GetAddressAsValue(media_session1));
+ expected_session.SetKey("owner", base::Value(kTestTitle1));
+ expected_session.SetKey("state", base::Value("Active"));
+
+ base::ListValue expected_list;
+ expected_list.GetList().push_back(std::move(expected_session));
+ ExpectValue(std::move(expected_list));
+ }
+
+ // Abandon audio focus.
+ RemoveAllPlayersForTest(media_session1);
+ WaitForCallback();
+
+ // Check JSON is what we expect.
+ {
+ base::ListValue expected_list;
+ ExpectValue(std::move(expected_list));
+ }
+}
+
+#endif // !defined(OS_ANDROID)
+
} // namespace content
diff --git a/chromium/content/browser/media/media_source_browsertest.cc b/chromium/content/browser/media/media_source_browsertest.cc
index a7d782ba920..c03bf22239e 100644
--- a/chromium/content/browser/media/media_source_browsertest.cc
+++ b/chromium/content/browser/media/media_source_browsertest.cc
@@ -28,10 +28,7 @@ const char kMp4FlacAudioOnly[] = "audio/mp4; codecs=\"flac\"";
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
const char kMp4AudioOnly[] = "audio/mp4; codecs=\"mp4a.40.2\"'";
-
-#if !defined(OS_ANDROID)
const char kMp4VideoOnly[] = "video/mp4; codecs=\"avc1.4D4041\"'";
-#endif // !defined(OS_ANDROID)
#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
const char kMp2tAudioVideo[] = "video/mp2t; codecs=\"mp4a.40.2, avc1.42E01E\"";
@@ -105,9 +102,6 @@ IN_PROC_BROWSER_TEST_F(MediaSourceTest, ConfigChangeVideo) {
}
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
-
-// TODO(chcunningham): Figure out why this is flaky on android. crbug/607841
-#if !defined(OS_ANDROID)
IN_PROC_BROWSER_TEST_F(MediaSourceTest, Playback_Video_MP4_Audio_WEBM) {
base::StringPairs query_params;
query_params.push_back(
@@ -119,7 +113,6 @@ IN_PROC_BROWSER_TEST_F(MediaSourceTest, Playback_Video_MP4_Audio_WEBM) {
RunMediaTestPage("mse_different_containers.html", query_params, media::kEnded,
true);
}
-#endif // !defined(OS_ANDROID)
IN_PROC_BROWSER_TEST_F(MediaSourceTest, Playback_Video_WEBM_Audio_MP4) {
base::StringPairs query_params;
diff --git a/chromium/content/browser/media/media_web_contents_observer.cc b/chromium/content/browser/media/media_web_contents_observer.cc
index 1b013f92874..c605c930a59 100644
--- a/chromium/content/browser/media/media_web_contents_observer.cc
+++ b/chromium/content/browser/media/media_web_contents_observer.cc
@@ -123,6 +123,10 @@ MediaWebContentsObserver::GetPictureInPictureVideoMediaPlayerId() const {
return pip_player_;
}
+void MediaWebContentsObserver::ResetPictureInPictureVideoMediaPlayerId() {
+ pip_player_.reset();
+}
+
bool MediaWebContentsObserver::OnMessageReceived(
const IPC::Message& msg,
RenderFrameHost* render_frame_host) {
@@ -147,6 +151,9 @@ bool MediaWebContentsObserver::OnMessageReceived(
IPC_MESSAGE_HANDLER(MediaPlayerDelegateHostMsg_OnPictureInPictureModeEnded,
OnPictureInPictureModeEnded)
IPC_MESSAGE_HANDLER(
+ MediaPlayerDelegateHostMsg_OnSetPictureInPictureCustomControls,
+ OnSetPictureInPictureCustomControls)
+ IPC_MESSAGE_HANDLER(
MediaPlayerDelegateHostMsg_OnPictureInPictureSurfaceChanged,
OnPictureInPictureSurfaceChanged)
IPC_MESSAGE_UNHANDLED(handled = false)
@@ -159,6 +166,10 @@ void MediaWebContentsObserver::OnVisibilityChanged(
UpdateVideoLock();
}
+void MediaWebContentsObserver::DidUpdateAudioMutingState(bool muted) {
+ session_controllers_manager_.WebContentsMutedStateChanged(muted);
+}
+
void MediaWebContentsObserver::RequestPersistentVideo(bool value) {
if (!fullscreen_player_)
return;
@@ -206,9 +217,7 @@ void MediaWebContentsObserver::OnMediaPaused(RenderFrameHost* render_frame_host,
UpdateVideoLock();
- // TODO(872066): check for |pip_player_| fully matching paused player.
- if (!web_contents()->IsBeingDestroyed() && pip_player_.has_value() &&
- pip_player_->render_frame_host == render_frame_host) {
+ if (!web_contents()->IsBeingDestroyed() && pip_player_ == player_id) {
PictureInPictureWindowControllerImpl* pip_controller =
PictureInPictureWindowControllerImpl::FromWebContents(
web_contents_impl());
@@ -262,9 +271,7 @@ void MediaWebContentsObserver::OnMediaPlaying(
return;
}
- // TODO(872066): check for |pip_player_| fully matching paused player.
- if (!web_contents()->IsBeingDestroyed() && pip_player_.has_value() &&
- pip_player_->render_frame_host == render_frame_host) {
+ if (!web_contents()->IsBeingDestroyed() && pip_player_ == id) {
PictureInPictureWindowControllerImpl* pip_controller =
PictureInPictureWindowControllerImpl::FromWebContents(
web_contents_impl());
@@ -349,13 +356,23 @@ void MediaWebContentsObserver::OnPictureInPictureModeEnded(
render_frame_host->GetRoutingID(), delegate_id, request_id));
}
+void MediaWebContentsObserver::OnSetPictureInPictureCustomControls(
+ RenderFrameHost* render_frame_host,
+ int delegate_id,
+ const std::vector<blink::PictureInPictureControlInfo>& controls) {
+ PictureInPictureWindowControllerImpl* pip_controller =
+ PictureInPictureWindowControllerImpl::FromWebContents(
+ web_contents_impl());
+ if (pip_controller)
+ pip_controller->SetPictureInPictureCustomControls(controls);
+}
+
void MediaWebContentsObserver::OnPictureInPictureSurfaceChanged(
RenderFrameHost* render_frame_host,
int delegate_id,
const viz::SurfaceId& surface_id,
const gfx::Size& natural_size) {
DCHECK(surface_id.is_valid());
- DCHECK(pip_player_);
pip_player_ = MediaPlayerId(render_frame_host, delegate_id);
@@ -515,7 +532,7 @@ void MediaWebContentsObserver::ExitPictureInPictureInternal() {
// Reset must happen after notifying the WebContents because it may interact
// with it.
- pip_player_.reset();
+ ResetPictureInPictureVideoMediaPlayerId();
UpdateVideoLock();
}
diff --git a/chromium/content/browser/media/media_web_contents_observer.h b/chromium/content/browser/media/media_web_contents_observer.h
index 67d25de6fd2..febe37fe409 100644
--- a/chromium/content/browser/media/media_web_contents_observer.h
+++ b/chromium/content/browser/media/media_web_contents_observer.h
@@ -23,6 +23,7 @@
namespace blink {
enum class WebFullscreenVideoStatus;
+struct PictureInPictureControlInfo;
} // namespace blink
namespace media {
@@ -73,12 +74,17 @@ class CONTENT_EXPORT MediaWebContentsObserver : public WebContentsObserver {
const base::Optional<MediaPlayerId>& GetPictureInPictureVideoMediaPlayerId()
const;
+ // Reset the MediaPlayerId of the picture in picture video when user closes
+ // Picture-in-Picture window manually.
+ void ResetPictureInPictureVideoMediaPlayerId();
+
// WebContentsObserver implementation.
void WebContentsDestroyed() override;
void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
bool OnMessageReceived(const IPC::Message& message,
RenderFrameHost* render_frame_host) override;
void OnVisibilityChanged(content::Visibility visibility) override;
+ void DidUpdateAudioMutingState(bool muted) override;
// TODO(zqzhang): this method is temporarily in MediaWebContentsObserver as
// the effectively fullscreen video code is also here. We need to consider
@@ -134,6 +140,10 @@ class CONTENT_EXPORT MediaWebContentsObserver : public WebContentsObserver {
void OnPictureInPictureModeEnded(RenderFrameHost* render_frame_host,
int delegate_id,
int request_id);
+ void OnSetPictureInPictureCustomControls(
+ RenderFrameHost* render_frame_host,
+ int delegate_id,
+ const std::vector<blink::PictureInPictureControlInfo>& controls);
void OnPictureInPictureSurfaceChanged(RenderFrameHost*,
int delegate_id,
const viz::SurfaceId&,
diff --git a/chromium/content/browser/media/session/audio_focus_delegate.h b/chromium/content/browser/media/session/audio_focus_delegate.h
index 5df555a56e5..ba23f16f875 100644
--- a/chromium/content/browser/media/session/audio_focus_delegate.h
+++ b/chromium/content/browser/media/session/audio_focus_delegate.h
@@ -7,6 +7,12 @@
#include "content/browser/media/session/audio_focus_manager.h"
+namespace media_session {
+namespace mojom {
+enum class AudioFocusType;
+} // namespace mojom
+} // namespace media_session
+
namespace content {
class MediaSessionImpl;
@@ -22,8 +28,11 @@ class AudioFocusDelegate {
virtual ~AudioFocusDelegate() = default;
virtual bool RequestAudioFocus(
- AudioFocusManager::AudioFocusType audio_focus_type) = 0;
+ media_session::mojom::AudioFocusType audio_focus_type) = 0;
virtual void AbandonAudioFocus() = 0;
+
+ // Retrieves the current |AudioFocusType| for the associated |MediaSession|.
+ virtual media_session::mojom::AudioFocusType GetCurrentFocusType() const = 0;
};
} // namespace content
diff --git a/chromium/content/browser/media/session/audio_focus_delegate_android.cc b/chromium/content/browser/media/session/audio_focus_delegate_android.cc
index 603c5c9b6a2..211aad42013 100644
--- a/chromium/content/browser/media/session/audio_focus_delegate_android.cc
+++ b/chromium/content/browser/media/session/audio_focus_delegate_android.cc
@@ -7,6 +7,7 @@
#include "base/android/jni_android.h"
#include "content/browser/media/session/media_session_impl.h"
#include "jni/AudioFocusDelegate_jni.h"
+#include "services/media_session/public/mojom/audio_focus.mojom.h"
using base::android::JavaParamRef;
@@ -30,13 +31,13 @@ void AudioFocusDelegateAndroid::Initialize() {
}
bool AudioFocusDelegateAndroid::RequestAudioFocus(
- AudioFocusManager::AudioFocusType audio_focus_type) {
+ media_session::mojom::AudioFocusType audio_focus_type) {
JNIEnv* env = base::android::AttachCurrentThread();
DCHECK(env);
return Java_AudioFocusDelegate_requestAudioFocus(
env, j_media_session_delegate_,
audio_focus_type ==
- AudioFocusManager::AudioFocusType::GainTransientMayDuck);
+ media_session::mojom::AudioFocusType::kGainTransientMayDuck);
}
void AudioFocusDelegateAndroid::AbandonAudioFocus() {
@@ -45,6 +46,16 @@ void AudioFocusDelegateAndroid::AbandonAudioFocus() {
Java_AudioFocusDelegate_abandonAudioFocus(env, j_media_session_delegate_);
}
+media_session::mojom::AudioFocusType
+AudioFocusDelegateAndroid::GetCurrentFocusType() const {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ DCHECK(env);
+ return Java_AudioFocusDelegate_isFocusTransient(env,
+ j_media_session_delegate_)
+ ? media_session::mojom::AudioFocusType::kGainTransientMayDuck
+ : media_session::mojom::AudioFocusType::kGain;
+}
+
void AudioFocusDelegateAndroid::OnSuspend(JNIEnv*,
const JavaParamRef<jobject>&) {
if (!media_session_->IsActive())
diff --git a/chromium/content/browser/media/session/audio_focus_delegate_android.h b/chromium/content/browser/media/session/audio_focus_delegate_android.h
index 1c787004724..8c18679e42e 100644
--- a/chromium/content/browser/media/session/audio_focus_delegate_android.h
+++ b/chromium/content/browser/media/session/audio_focus_delegate_android.h
@@ -10,6 +10,12 @@
#include "base/android/scoped_java_ref.h"
#include "content/browser/media/session/audio_focus_delegate.h"
+namespace media_session {
+namespace mojom {
+enum class AudioFocusType;
+} // namespace mojom
+} // namespace media_session
+
namespace content {
// AudioFocusDelegateAndroid handles the audio focus at a system level on
@@ -22,8 +28,9 @@ class AudioFocusDelegateAndroid : public AudioFocusDelegate {
void Initialize();
bool RequestAudioFocus(
- AudioFocusManager::AudioFocusType audio_focus_type) override;
+ media_session::mojom::AudioFocusType audio_focus_type) override;
void AbandonAudioFocus() override;
+ media_session::mojom::AudioFocusType GetCurrentFocusType() const override;
// Called when the Android system requests the MediaSession to be suspended.
// Called by Java through JNI.
diff --git a/chromium/content/browser/media/session/audio_focus_delegate_default.cc b/chromium/content/browser/media/session/audio_focus_delegate_default.cc
index 586bbf361c1..eb7ec76aaf2 100644
--- a/chromium/content/browser/media/session/audio_focus_delegate_default.cc
+++ b/chromium/content/browser/media/session/audio_focus_delegate_default.cc
@@ -4,13 +4,13 @@
#include "content/browser/media/session/audio_focus_delegate.h"
-#include "base/command_line.h"
#include "content/browser/media/session/audio_focus_manager.h"
-#include "media/base/media_switches.h"
+#include "services/media_session/public/cpp/switches.h"
+#include "services/media_session/public/mojom/audio_focus.mojom.h"
namespace content {
-using AudioFocusType = AudioFocusManager::AudioFocusType;
+using media_session::mojom::AudioFocusType;
namespace {
@@ -22,13 +22,16 @@ class AudioFocusDelegateDefault : public AudioFocusDelegate {
~AudioFocusDelegateDefault() override;
// AudioFocusDelegate implementation.
- bool RequestAudioFocus(
- AudioFocusManager::AudioFocusType audio_focus_type) override;
+ bool RequestAudioFocus(AudioFocusType audio_focus_type) override;
void AbandonAudioFocus() override;
+ AudioFocusType GetCurrentFocusType() const override;
private:
// Weak pointer because |this| is owned by |media_session_|.
MediaSessionImpl* media_session_;
+
+ // The last requested AudioFocusType by the associated |media_session_|.
+ AudioFocusType audio_focus_type_if_disabled_;
};
} // anonymous namespace
@@ -40,11 +43,11 @@ AudioFocusDelegateDefault::AudioFocusDelegateDefault(
AudioFocusDelegateDefault::~AudioFocusDelegateDefault() = default;
bool AudioFocusDelegateDefault::RequestAudioFocus(
- AudioFocusManager::AudioFocusType audio_focus_type) {
- if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableAudioFocus)) {
+ AudioFocusType audio_focus_type) {
+ audio_focus_type_if_disabled_ = audio_focus_type;
+
+ if (!media_session::IsAudioFocusEnabled())
return true;
- }
AudioFocusManager::GetInstance()->RequestAudioFocus(media_session_,
audio_focus_type);
@@ -55,6 +58,15 @@ void AudioFocusDelegateDefault::AbandonAudioFocus() {
AudioFocusManager::GetInstance()->AbandonAudioFocus(media_session_);
}
+AudioFocusType AudioFocusDelegateDefault::GetCurrentFocusType() const {
+ if (media_session::IsAudioFocusEnabled()) {
+ return AudioFocusManager::GetInstance()->GetFocusTypeForSession(
+ media_session_);
+ }
+
+ return audio_focus_type_if_disabled_;
+}
+
// static
std::unique_ptr<AudioFocusDelegate> AudioFocusDelegate::Create(
MediaSessionImpl* media_session) {
diff --git a/chromium/content/browser/media/session/audio_focus_delegate_default_browsertest.cc b/chromium/content/browser/media/session/audio_focus_delegate_default_browsertest.cc
index ed4ec737d31..8d5e777f70a 100644
--- a/chromium/content/browser/media/session/audio_focus_delegate_default_browsertest.cc
+++ b/chromium/content/browser/media/session/audio_focus_delegate_default_browsertest.cc
@@ -8,14 +8,14 @@
#include "content/public/test/content_browser_test.h"
#include "content/shell/browser/shell.h"
#include "media/base/media_content_type.h"
-#include "media/base/media_switches.h"
+#include "services/media_session/public/cpp/switches.h"
namespace content {
class AudioFocusDelegateDefaultBrowserTest : public ContentBrowserTest {
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
- command_line->AppendSwitch(switches::kEnableAudioFocus);
+ command_line->AppendSwitch(media_session::switches::kEnableAudioFocus);
}
void Run(WebContents* start_contents, WebContents* interrupt_contents) {
diff --git a/chromium/content/browser/media/session/audio_focus_manager.cc b/chromium/content/browser/media/session/audio_focus_manager.cc
index 6a9e7215d5c..fbd8af4da47 100644
--- a/chromium/content/browser/media/session/audio_focus_manager.cc
+++ b/chromium/content/browser/media/session/audio_focus_manager.cc
@@ -4,11 +4,28 @@
#include "content/browser/media/session/audio_focus_manager.h"
+#include "content/browser/media/session/audio_focus_observer.h"
#include "content/browser/media/session/media_session_impl.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "services/media_session/public/mojom/audio_focus.mojom.h"
namespace content {
+using media_session::mojom::AudioFocusType;
+
+namespace {
+
+media_session::mojom::MediaSessionPtr GetSessionMojoPtr(
+ MediaSessionImpl* session) {
+ media_session::mojom::MediaSessionPtr media_session_ptr;
+ session->BindToMojoRequest(mojo::MakeRequest(&media_session_ptr));
+ return media_session_ptr;
+}
+
+} // namespace
+
// static
AudioFocusManager* AudioFocusManager::GetInstance() {
return base::Singleton<AudioFocusManager>::get();
@@ -17,9 +34,9 @@ AudioFocusManager* AudioFocusManager::GetInstance() {
void AudioFocusManager::RequestAudioFocus(MediaSessionImpl* media_session,
AudioFocusType type) {
if (!audio_focus_stack_.empty() &&
- audio_focus_stack_.back() == media_session &&
- audio_focus_stack_.back()->audio_focus_type() == type &&
- audio_focus_stack_.back()->IsActive()) {
+ audio_focus_stack_.back().media_session == media_session &&
+ audio_focus_stack_.back().audio_focus_type == type &&
+ audio_focus_stack_.back().media_session->IsActive()) {
// Early returning if |media_session| is already on top (has focus) and is
// active.
return;
@@ -32,64 +49,125 @@ void AudioFocusManager::RequestAudioFocus(MediaSessionImpl* media_session,
// too much. Maybe it's better to do some abstraction and refactoring to clean
// up the relation between AudioFocusManager and MediaSessionImpl.
// See https://crbug.com/651069
- if (type == AudioFocusType::GainTransientMayDuck) {
- for (auto* old_session : audio_focus_stack_) {
- old_session->StartDucking();
+ if (type == AudioFocusType::kGainTransientMayDuck) {
+ for (auto& old_session : audio_focus_stack_) {
+ old_session.media_session->StartDucking();
}
} else {
- for (auto* old_session : audio_focus_stack_) {
- if (old_session->IsActive()) {
- if (old_session->HasPepper())
- old_session->StartDucking();
+ for (auto& old_session : audio_focus_stack_) {
+ if (old_session.media_session->IsActive()) {
+ if (old_session.media_session->HasPepper())
+ old_session.media_session->StartDucking();
else
- old_session->Suspend(MediaSessionImpl::SuspendType::SYSTEM);
+ old_session.media_session->Suspend(
+ MediaSessionImpl::SuspendType::SYSTEM);
}
}
}
- audio_focus_stack_.push_back(media_session);
- audio_focus_stack_.back()->StopDucking();
+ // Store the MediaSession and requested focus type.
+ audio_focus_stack_.emplace_back(media_session, type);
+ audio_focus_stack_.back().media_session->StopDucking();
+
+ // Notify observers that we were gained audio focus.
+ observers_.ForAllPtrs(
+ [media_session,
+ type](media_session::mojom::AudioFocusObserver* observer) {
+ observer->OnFocusGained(GetSessionMojoPtr(media_session), type);
+ });
}
void AudioFocusManager::AbandonAudioFocus(MediaSessionImpl* media_session) {
if (audio_focus_stack_.empty())
return;
- if (audio_focus_stack_.back() != media_session) {
+ if (audio_focus_stack_.back().media_session != media_session) {
MaybeRemoveFocusEntry(media_session);
return;
}
audio_focus_stack_.pop_back();
- if (audio_focus_stack_.empty())
+ if (audio_focus_stack_.empty()) {
+ // Notify observers that we lost audio focus.
+ observers_.ForAllPtrs(
+ [media_session](media_session::mojom::AudioFocusObserver* observer) {
+ observer->OnFocusLost(GetSessionMojoPtr(media_session));
+ });
return;
+ }
// Allow the top-most MediaSessionImpl having Pepper to unduck pepper even if
// it's
// not active.
for (auto iter = audio_focus_stack_.rbegin();
iter != audio_focus_stack_.rend(); ++iter) {
- if (!(*iter)->HasPepper())
+ if (!iter->media_session->HasPepper())
continue;
- MediaSessionImpl* pepper_session = *iter;
+ MediaSessionImpl* pepper_session = iter->media_session;
+ AudioFocusType focus_type = iter->audio_focus_type;
pepper_session->StopDucking();
MaybeRemoveFocusEntry(pepper_session);
- audio_focus_stack_.push_back(pepper_session);
+ audio_focus_stack_.emplace_back(pepper_session, focus_type);
return;
}
// Only try to unduck the new MediaSessionImpl on top. The session might be
// still
// inactive but it will not be resumed (so it doesn't surprise the user).
- audio_focus_stack_.back()->StopDucking();
+ audio_focus_stack_.back().media_session->StopDucking();
+
+ // Notify observers that we lost audio focus.
+ observers_.ForAllPtrs(
+ [media_session](media_session::mojom::AudioFocusObserver* observer) {
+ observer->OnFocusLost(GetSessionMojoPtr(media_session));
+ });
+}
+
+mojo::InterfacePtrSetElementId AudioFocusManager::AddObserver(
+ media_session::mojom::AudioFocusObserverPtr observer) {
+ return observers_.AddPtr(std::move(observer));
+}
+
+AudioFocusType AudioFocusManager::GetFocusTypeForSession(
+ MediaSessionImpl* media_session) const {
+ for (auto row : audio_focus_stack_) {
+ if (row.media_session == media_session)
+ return row.audio_focus_type;
+ }
+
+ NOTREACHED();
+ return AudioFocusType::kGain;
+}
+
+void AudioFocusManager::RemoveObserver(mojo::InterfacePtrSetElementId id) {
+ observers_.RemovePtr(id);
+}
+
+void AudioFocusManager::ResetForTesting() {
+ audio_focus_stack_.clear();
+ observers_.CloseAll();
+}
+
+void AudioFocusManager::FlushForTesting() {
+ observers_.FlushForTesting();
}
-AudioFocusManager::AudioFocusManager() = default;
+AudioFocusManager::AudioFocusManager() {
+ // Make sure we start AudioFocusManager on the browser UI thread. This is to
+ // ensure thread consistency for mojo::InterfaceSetPtr.
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+}
AudioFocusManager::~AudioFocusManager() = default;
void AudioFocusManager::MaybeRemoveFocusEntry(MediaSessionImpl* media_session) {
- audio_focus_stack_.remove(media_session);
+ for (auto iter = audio_focus_stack_.begin(); iter != audio_focus_stack_.end();
+ ++iter) {
+ if (iter->media_session == media_session) {
+ audio_focus_stack_.erase(iter);
+ break;
+ }
+ }
}
} // namespace content
diff --git a/chromium/content/browser/media/session/audio_focus_manager.h b/chromium/content/browser/media/session/audio_focus_manager.h
index df49b85fc1f..3bc2cc78253 100644
--- a/chromium/content/browser/media/session/audio_focus_manager.h
+++ b/chromium/content/browser/media/session/audio_focus_manager.h
@@ -11,6 +11,8 @@
#include "base/memory/singleton.h"
#include "content/common/content_export.h"
#include "content/public/browser/web_contents_observer.h"
+#include "mojo/public/cpp/bindings/interface_ptr_set.h"
+#include "services/media_session/public/mojom/audio_focus.mojom.h"
namespace content {
@@ -18,30 +20,55 @@ class MediaSessionImpl;
class CONTENT_EXPORT AudioFocusManager {
public:
- enum class AudioFocusType {
- Gain,
- GainTransientMayDuck,
- };
-
// Returns Chromium's internal AudioFocusManager.
static AudioFocusManager* GetInstance();
- void RequestAudioFocus(MediaSessionImpl* media_session, AudioFocusType type);
+ void RequestAudioFocus(MediaSessionImpl* media_session,
+ media_session::mojom::AudioFocusType type);
void AbandonAudioFocus(MediaSessionImpl* media_session);
+ media_session::mojom::AudioFocusType GetFocusTypeForSession(
+ MediaSessionImpl* media_session) const;
+
+ // Adds/removes audio focus observers.
+ mojo::InterfacePtrSetElementId AddObserver(
+ media_session::mojom::AudioFocusObserverPtr);
+ void RemoveObserver(mojo::InterfacePtrSetElementId);
+
private:
friend struct base::DefaultSingletonTraits<AudioFocusManager>;
friend class AudioFocusManagerTest;
+ // Media internals UI needs access to internal state.
+ friend class MediaInternalsAudioFocusTest;
+ friend class MediaInternals;
+
+ // Flush for testing will flush any pending messages to the observers.
+ void FlushForTesting();
+
+ // Reset for testing will clear any built up internal state.
+ void ResetForTesting();
+
AudioFocusManager();
~AudioFocusManager();
void MaybeRemoveFocusEntry(MediaSessionImpl* media_session);
- // Weak reference of managed MediaSessions. A MediaSession must abandon audio
- // foucs before its destruction.
- std::list<MediaSessionImpl*> audio_focus_stack_;
+ // Weak reference of managed observers. Observers are expected to remove
+ // themselves before being destroyed.
+ mojo::InterfacePtrSet<media_session::mojom::AudioFocusObserver> observers_;
+
+ // Weak reference of managed MediaSessions and their requested focus type.
+ // A MediaSession must abandon audio focus before its destruction.
+ struct StackRow {
+ StackRow(MediaSessionImpl* media_session,
+ media_session::mojom::AudioFocusType audio_focus_type)
+ : media_session(media_session), audio_focus_type(audio_focus_type) {}
+ MediaSessionImpl* media_session;
+ media_session::mojom::AudioFocusType audio_focus_type;
+ };
+ std::list<StackRow> audio_focus_stack_;
};
} // namespace content
diff --git a/chromium/content/browser/media/session/audio_focus_manager_unittest.cc b/chromium/content/browser/media/session/audio_focus_manager_unittest.cc
index 459ce5089f4..fc4a5974244 100644
--- a/chromium/content/browser/media/session/audio_focus_manager_unittest.cc
+++ b/chromium/content/browser/media/session/audio_focus_manager_unittest.cc
@@ -7,7 +7,9 @@
#include <memory>
#include "base/command_line.h"
+#include "base/optional.h"
#include "base/run_loop.h"
+#include "content/browser/media/session/audio_focus_observer.h"
#include "content/browser/media/session/media_session_impl.h"
#include "content/browser/media/session/media_session_player_observer.h"
#include "content/public/test/mock_render_process_host.h"
@@ -15,12 +17,36 @@
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/test/test_web_contents.h"
#include "media/base/media_content_type.h"
-#include "media/base/media_switches.h"
+#include "services/media_session/public/cpp/switches.h"
+#include "services/media_session/public/mojom/audio_focus.mojom.h"
namespace content {
+using media_session::mojom::AudioFocusType;
+using media_session::mojom::MediaSessionPtr;
+
namespace {
+class MockAudioFocusObserver : public AudioFocusObserver {
+ public:
+ MockAudioFocusObserver() { RegisterAudioFocusObserver(); }
+
+ void OnFocusGained(MediaSessionPtr session, AudioFocusType type) override {
+ EXPECT_TRUE(session.is_bound());
+ focus_gained_call_ = type;
+ focus_lost_call_ = false;
+ }
+
+ void OnFocusLost(MediaSessionPtr session) override {
+ EXPECT_TRUE(session.is_bound());
+ focus_lost_call_ = true;
+ focus_gained_call_.reset();
+ }
+
+ base::Optional<AudioFocusType> focus_gained_call_;
+ bool focus_lost_call_ = false;
+};
+
class MockMediaSessionPlayerObserver : public MediaSessionPlayerObserver {
public:
void OnSuspend(int player_id) override {}
@@ -34,7 +60,6 @@ class MockMediaSessionPlayerObserver : public MediaSessionPlayerObserver {
} // anonymous namespace
-using AudioFocusType = AudioFocusManager::AudioFocusType;
using SuspendType = MediaSession::SuspendType;
class AudioFocusManagerTest : public testing::Test {
@@ -43,12 +68,16 @@ class AudioFocusManagerTest : public testing::Test {
void SetUp() override {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kEnableAudioFocus);
+ media_session::switches::kEnableAudioFocus);
rph_factory_.reset(new MockRenderProcessHostFactory());
RenderProcessHostImpl::set_render_process_host_factory_for_testing(
rph_factory_.get());
browser_context_.reset(new TestBrowserContext());
pepper_observer_.reset(new MockMediaSessionPlayerObserver());
+
+ // AudioFocusManager is a singleton so we should make sure we reset any
+ // state in between tests.
+ AudioFocusManager::GetInstance()->ResetForTesting();
}
void TearDown() override {
@@ -61,29 +90,28 @@ class AudioFocusManagerTest : public testing::Test {
}
MediaSessionImpl* GetAudioFocusedSession() const {
- const auto& audio_focus_stack =
- AudioFocusManager::GetInstance()->audio_focus_stack_;
+ const AudioFocusManager* manager = AudioFocusManager::GetInstance();
+ const auto& audio_focus_stack = manager->audio_focus_stack_;
+
for (auto iter = audio_focus_stack.rbegin();
iter != audio_focus_stack.rend(); ++iter) {
- if ((*iter)->audio_focus_type() ==
- AudioFocusManager::AudioFocusType::Gain)
- return (*iter);
+ if ((*iter).audio_focus_type == AudioFocusType::kGain)
+ return (*iter).media_session;
}
return nullptr;
}
int GetTransientMaybeDuckCount() const {
+ const AudioFocusManager* manager = AudioFocusManager::GetInstance();
+ const auto& audio_focus_stack = manager->audio_focus_stack_;
int count = 0;
- const auto& audio_focus_stack =
- AudioFocusManager::GetInstance()->audio_focus_stack_;
+
for (auto iter = audio_focus_stack.rbegin();
iter != audio_focus_stack.rend(); ++iter) {
- if ((*iter)->audio_focus_type() ==
- AudioFocusManager::AudioFocusType::GainTransientMayDuck) {
- ++count;
- } else {
+ if ((*iter).audio_focus_type == AudioFocusType::kGainTransientMayDuck)
+ ++count;
+ else
break;
- }
}
return count;
@@ -94,7 +122,7 @@ class AudioFocusManagerTest : public testing::Test {
}
void RequestAudioFocus(MediaSessionImpl* session,
- AudioFocusManager::AudioFocusType audio_focus_type) {
+ AudioFocusType audio_focus_type) {
session->RequestSystemAudioFocus(audio_focus_type);
}
@@ -102,6 +130,10 @@ class AudioFocusManagerTest : public testing::Test {
session->AbandonSystemAudioFocusIfNeeded();
}
+ void FlushForTesting() {
+ AudioFocusManager::GetInstance()->FlushForTesting();
+ }
+
std::unique_ptr<WebContents> CreateWebContents() {
return TestWebContents::Create(browser_context_.get(),
SiteInstance::SiteInstance::Create(browser_context_.get()));
@@ -137,13 +169,13 @@ TEST_F(AudioFocusManagerTest, RequestAudioFocusGain_ReplaceFocusedEntry) {
ASSERT_EQ(nullptr, GetAudioFocusedSession());
- RequestAudioFocus(media_session_1, AudioFocusManager::AudioFocusType::Gain);
+ RequestAudioFocus(media_session_1, AudioFocusType::kGain);
ASSERT_EQ(media_session_1, GetAudioFocusedSession());
- RequestAudioFocus(media_session_2, AudioFocusManager::AudioFocusType::Gain);
+ RequestAudioFocus(media_session_2, AudioFocusType::kGain);
ASSERT_EQ(media_session_2, GetAudioFocusedSession());
- RequestAudioFocus(media_session_3, AudioFocusManager::AudioFocusType::Gain);
+ RequestAudioFocus(media_session_3, AudioFocusType::kGain);
ASSERT_EQ(media_session_3, GetAudioFocusedSession());
}
@@ -153,10 +185,10 @@ TEST_F(AudioFocusManagerTest, RequestAudioFocusGain_Duplicate) {
ASSERT_EQ(nullptr, GetAudioFocusedSession());
- RequestAudioFocus(media_session, AudioFocusManager::AudioFocusType::Gain);
+ RequestAudioFocus(media_session, AudioFocusType::kGain);
ASSERT_EQ(media_session, GetAudioFocusedSession());
- RequestAudioFocus(media_session, AudioFocusManager::AudioFocusType::Gain);
+ RequestAudioFocus(media_session, AudioFocusType::kGain);
ASSERT_EQ(media_session, GetAudioFocusedSession());
}
@@ -164,12 +196,11 @@ TEST_F(AudioFocusManagerTest, RequestAudioFocusGain_FromTransient) {
std::unique_ptr<WebContents> web_contents(CreateWebContents());
MediaSessionImpl* media_session = MediaSessionImpl::Get(web_contents.get());
- RequestAudioFocus(
- media_session, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
+ RequestAudioFocus(media_session, AudioFocusType::kGainTransientMayDuck);
ASSERT_EQ(nullptr, GetAudioFocusedSession());
ASSERT_EQ(1, GetTransientMaybeDuckCount());
- RequestAudioFocus(media_session, AudioFocusManager::AudioFocusType::Gain);
+ RequestAudioFocus(media_session, AudioFocusType::kGain);
ASSERT_EQ(media_session, GetAudioFocusedSession());
ASSERT_EQ(0, GetTransientMaybeDuckCount());
}
@@ -178,12 +209,11 @@ TEST_F(AudioFocusManagerTest, RequestAudioFocusTransient_FromGain) {
std::unique_ptr<WebContents> web_contents(CreateWebContents());
MediaSessionImpl* media_session = MediaSessionImpl::Get(web_contents.get());
- RequestAudioFocus(media_session, AudioFocusManager::AudioFocusType::Gain);
+ RequestAudioFocus(media_session, AudioFocusType::kGain);
ASSERT_EQ(media_session, GetAudioFocusedSession());
ASSERT_EQ(0, GetTransientMaybeDuckCount());
- RequestAudioFocus(
- media_session, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
+ RequestAudioFocus(media_session, AudioFocusType::kGainTransientMayDuck);
ASSERT_EQ(nullptr, GetAudioFocusedSession());
ASSERT_EQ(1, GetTransientMaybeDuckCount());
ASSERT_FALSE(IsSessionDucking(media_session));
@@ -198,17 +228,15 @@ TEST_F(AudioFocusManagerTest, RequestAudioFocusTransient_FromGainWhileDucking) {
MediaSessionImpl* media_session_2 =
MediaSessionImpl::Get(web_contents_2.get());
- RequestAudioFocus(media_session_1, AudioFocusManager::AudioFocusType::Gain);
+ RequestAudioFocus(media_session_1, AudioFocusType::kGain);
ASSERT_EQ(0, GetTransientMaybeDuckCount());
ASSERT_FALSE(IsSessionDucking(media_session_1));
- RequestAudioFocus(
- media_session_2, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
+ RequestAudioFocus(media_session_2, AudioFocusType::kGainTransientMayDuck);
ASSERT_EQ(1, GetTransientMaybeDuckCount());
ASSERT_TRUE(IsSessionDucking(media_session_1));
- RequestAudioFocus(
- media_session_1, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
+ RequestAudioFocus(media_session_1, AudioFocusType::kGainTransientMayDuck);
ASSERT_EQ(2, GetTransientMaybeDuckCount());
ASSERT_FALSE(IsSessionDucking(media_session_1));
}
@@ -217,7 +245,7 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_RemovesFocusedEntry) {
std::unique_ptr<WebContents> web_contents(CreateWebContents());
MediaSessionImpl* media_session = MediaSessionImpl::Get(web_contents.get());
- RequestAudioFocus(media_session, AudioFocusManager::AudioFocusType::Gain);
+ RequestAudioFocus(media_session, AudioFocusType::kGain);
ASSERT_EQ(media_session, GetAudioFocusedSession());
AbandonAudioFocus(media_session);
@@ -236,12 +264,17 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_RemovesTransientEntry) {
std::unique_ptr<WebContents> web_contents(CreateWebContents());
MediaSessionImpl* media_session = MediaSessionImpl::Get(web_contents.get());
- RequestAudioFocus(
- media_session, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
+ RequestAudioFocus(media_session, AudioFocusType::kGainTransientMayDuck);
ASSERT_EQ(1, GetTransientMaybeDuckCount());
- AbandonAudioFocus(media_session);
- ASSERT_EQ(0, GetTransientMaybeDuckCount());
+ {
+ MockAudioFocusObserver observer;
+ AbandonAudioFocus(media_session);
+ FlushForTesting();
+
+ EXPECT_EQ(0, GetTransientMaybeDuckCount());
+ EXPECT_TRUE(observer.focus_lost_call_);
+ }
}
TEST_F(AudioFocusManagerTest, AbandonAudioFocus_WhileDuckingThenResume) {
@@ -253,12 +286,11 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_WhileDuckingThenResume) {
MediaSessionImpl* media_session_2 =
MediaSessionImpl::Get(web_contents_2.get());
- RequestAudioFocus(media_session_1, AudioFocusManager::AudioFocusType::Gain);
+ RequestAudioFocus(media_session_1, AudioFocusType::kGain);
ASSERT_EQ(0, GetTransientMaybeDuckCount());
ASSERT_FALSE(IsSessionDucking(media_session_1));
- RequestAudioFocus(
- media_session_2, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
+ RequestAudioFocus(media_session_2, AudioFocusType::kGainTransientMayDuck);
ASSERT_EQ(1, GetTransientMaybeDuckCount());
ASSERT_TRUE(IsSessionDucking(media_session_1));
@@ -268,7 +300,7 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_WhileDuckingThenResume) {
AbandonAudioFocus(media_session_2);
ASSERT_EQ(0, GetTransientMaybeDuckCount());
- RequestAudioFocus(media_session_1, AudioFocusManager::AudioFocusType::Gain);
+ RequestAudioFocus(media_session_1, AudioFocusType::kGain);
ASSERT_FALSE(IsSessionDucking(media_session_1));
}
@@ -281,12 +313,11 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_StopsDucking) {
MediaSessionImpl* media_session_2 =
MediaSessionImpl::Get(web_contents_2.get());
- RequestAudioFocus(media_session_1, AudioFocusManager::AudioFocusType::Gain);
+ RequestAudioFocus(media_session_1, AudioFocusType::kGain);
ASSERT_EQ(0, GetTransientMaybeDuckCount());
ASSERT_FALSE(IsSessionDucking(media_session_1));
- RequestAudioFocus(
- media_session_2, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
+ RequestAudioFocus(media_session_2, AudioFocusType::kGainTransientMayDuck);
ASSERT_EQ(1, GetTransientMaybeDuckCount());
ASSERT_TRUE(IsSessionDucking(media_session_1));
@@ -304,11 +335,10 @@ TEST_F(AudioFocusManagerTest, DuckWhilePlaying) {
MediaSessionImpl* media_session_2 =
MediaSessionImpl::Get(web_contents_2.get());
- RequestAudioFocus(media_session_1, AudioFocusManager::AudioFocusType::Gain);
+ RequestAudioFocus(media_session_1, AudioFocusType::kGain);
ASSERT_FALSE(IsSessionDucking(media_session_1));
- RequestAudioFocus(
- media_session_2, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
+ RequestAudioFocus(media_session_2, AudioFocusType::kGainTransientMayDuck);
ASSERT_TRUE(IsSessionDucking(media_session_1));
}
@@ -321,10 +351,9 @@ TEST_F(AudioFocusManagerTest, GainSuspendsTransient) {
MediaSessionImpl* media_session_2 =
MediaSessionImpl::Get(web_contents_2.get());
- RequestAudioFocus(
- media_session_2, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
+ RequestAudioFocus(media_session_2, AudioFocusType::kGainTransientMayDuck);
- RequestAudioFocus(media_session_1, AudioFocusManager::AudioFocusType::Gain);
+ RequestAudioFocus(media_session_1, AudioFocusType::kGain);
ASSERT_TRUE(media_session_2->IsSuspended());
}
@@ -341,15 +370,13 @@ TEST_F(AudioFocusManagerTest, DuckWithMultipleTransients) {
MediaSessionImpl* media_session_3 =
MediaSessionImpl::Get(web_contents_3.get());
- RequestAudioFocus(media_session_1, AudioFocusManager::AudioFocusType::Gain);
+ RequestAudioFocus(media_session_1, AudioFocusType::kGain);
ASSERT_FALSE(IsSessionDucking(media_session_1));
- RequestAudioFocus(
- media_session_2, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
+ RequestAudioFocus(media_session_2, AudioFocusType::kGainTransientMayDuck);
ASSERT_TRUE(IsSessionDucking(media_session_1));
- RequestAudioFocus(
- media_session_3, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
+ RequestAudioFocus(media_session_3, AudioFocusType::kGainTransientMayDuck);
ASSERT_TRUE(IsSessionDucking(media_session_1));
AbandonAudioFocus(media_session_2);
@@ -363,7 +390,7 @@ TEST_F(AudioFocusManagerTest, WebContentsDestroyed_ReleasesFocus) {
std::unique_ptr<WebContents> web_contents(CreateWebContents());
MediaSessionImpl* media_session = MediaSessionImpl::Get(web_contents.get());
- RequestAudioFocus(media_session, AudioFocusManager::AudioFocusType::Gain);
+ RequestAudioFocus(media_session, AudioFocusType::kGain);
ASSERT_EQ(media_session, GetAudioFocusedSession());
web_contents.reset();
@@ -374,8 +401,7 @@ TEST_F(AudioFocusManagerTest, WebContentsDestroyed_ReleasesTransients) {
std::unique_ptr<WebContents> web_contents(CreateWebContents());
MediaSessionImpl* media_session = MediaSessionImpl::Get(web_contents.get());
- RequestAudioFocus(
- media_session, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
+ RequestAudioFocus(media_session, AudioFocusType::kGainTransientMayDuck);
ASSERT_EQ(1, GetTransientMaybeDuckCount());
web_contents.reset();
@@ -391,11 +417,10 @@ TEST_F(AudioFocusManagerTest, WebContentsDestroyed_StopsDucking) {
MediaSessionImpl* media_session_2 =
MediaSessionImpl::Get(web_contents_2.get());
- RequestAudioFocus(media_session_1, AudioFocusManager::AudioFocusType::Gain);
+ RequestAudioFocus(media_session_1, AudioFocusType::kGain);
ASSERT_FALSE(IsSessionDucking(media_session_1));
- RequestAudioFocus(
- media_session_2, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
+ RequestAudioFocus(media_session_2, AudioFocusType::kGainTransientMayDuck);
ASSERT_TRUE(IsSessionDucking(media_session_1));
web_contents_2.reset();
@@ -426,8 +451,7 @@ TEST_F(AudioFocusManagerTest, GainDucksPepper) {
media_session_1->AddPlayer(
pepper_observer_.get(), 0, media::MediaContentType::Pepper);
- RequestAudioFocus(
- media_session_2, AudioFocusManager::AudioFocusType::Gain);
+ RequestAudioFocus(media_session_2, AudioFocusType::kGain);
ASSERT_EQ(media_session_2, GetAudioFocusedSession());
ASSERT_TRUE(media_session_1->IsActive());
@@ -450,10 +474,8 @@ TEST_F(AudioFocusManagerTest, AbandoningGainFocusRevokesTopMostPepperSession) {
media_session_1->AddPlayer(
pepper_observer_.get(), 0, media::MediaContentType::Pepper);
- RequestAudioFocus(
- media_session_2, AudioFocusManager::AudioFocusType::Gain);
- RequestAudioFocus(
- media_session_3, AudioFocusManager::AudioFocusType::Gain);
+ RequestAudioFocus(media_session_2, AudioFocusType::kGain);
+ RequestAudioFocus(media_session_3, AudioFocusType::kGain);
ASSERT_EQ(media_session_3, GetAudioFocusedSession());
ASSERT_TRUE(media_session_2->IsSuspended());
@@ -464,4 +486,65 @@ TEST_F(AudioFocusManagerTest, AbandoningGainFocusRevokesTopMostPepperSession) {
ASSERT_EQ(media_session_1, GetAudioFocusedSession());
}
+TEST_F(AudioFocusManagerTest, AudioFocusObserver_AbandonNoop) {
+ std::unique_ptr<WebContents> web_contents(CreateWebContents());
+ MediaSessionImpl* media_session = MediaSessionImpl::Get(web_contents.get());
+
+ {
+ MockAudioFocusObserver observer;
+ AbandonAudioFocus(media_session);
+ FlushForTesting();
+
+ EXPECT_EQ(nullptr, GetAudioFocusedSession());
+ EXPECT_FALSE(observer.focus_lost_call_);
+ }
+}
+
+TEST_F(AudioFocusManagerTest, AudioFocusObserver_RequestNoop) {
+ std::unique_ptr<WebContents> web_contents(CreateWebContents());
+ MediaSessionImpl* media_session = MediaSessionImpl::Get(web_contents.get());
+
+ {
+ MockAudioFocusObserver observer;
+ RequestAudioFocus(media_session, AudioFocusType::kGain);
+ FlushForTesting();
+
+ EXPECT_EQ(media_session, GetAudioFocusedSession());
+ EXPECT_EQ(AudioFocusType::kGain, observer.focus_gained_call_.value());
+ }
+
+ {
+ MockAudioFocusObserver observer;
+ RequestAudioFocus(media_session, AudioFocusType::kGain);
+ FlushForTesting();
+
+ EXPECT_EQ(media_session, GetAudioFocusedSession());
+ EXPECT_FALSE(observer.focus_gained_call_.has_value());
+ }
+}
+
+TEST_F(AudioFocusManagerTest, AudioFocusObserver_TransientMayDuck) {
+ std::unique_ptr<WebContents> web_contents(CreateWebContents());
+ MediaSessionImpl* media_session = MediaSessionImpl::Get(web_contents.get());
+
+ {
+ MockAudioFocusObserver observer;
+ RequestAudioFocus(media_session, AudioFocusType::kGainTransientMayDuck);
+ FlushForTesting();
+
+ EXPECT_EQ(1, GetTransientMaybeDuckCount());
+ EXPECT_EQ(AudioFocusType::kGainTransientMayDuck,
+ observer.focus_gained_call_.value());
+ }
+
+ {
+ MockAudioFocusObserver observer;
+ AbandonAudioFocus(media_session);
+ FlushForTesting();
+
+ EXPECT_EQ(0, GetTransientMaybeDuckCount());
+ EXPECT_TRUE(observer.focus_lost_call_);
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/media/session/audio_focus_observer.cc b/chromium/content/browser/media/session/audio_focus_observer.cc
new file mode 100644
index 00000000000..b78c54c4b5f
--- /dev/null
+++ b/chromium/content/browser/media/session/audio_focus_observer.cc
@@ -0,0 +1,46 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/session/audio_focus_observer.h"
+
+#include "build/build_config.h"
+#include "content/browser/media/session/audio_focus_manager.h"
+#include "content/public/browser/browser_thread.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+
+namespace content {
+
+AudioFocusObserver::AudioFocusObserver() : binding_(this) {}
+
+void AudioFocusObserver::RegisterAudioFocusObserver() {
+ if (observer_id_.has_value())
+ return;
+
+#if !defined(OS_ANDROID)
+ // TODO(https://crbug.com/873320): Add support for Android.
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ media_session::mojom::AudioFocusObserverPtr observer;
+ binding_.Bind(mojo::MakeRequest(&observer));
+ observer_id_ =
+ AudioFocusManager::GetInstance()->AddObserver(std::move(observer));
+#endif
+}
+
+void AudioFocusObserver::UnregisterAudioFocusObserver() {
+ if (!observer_id_.has_value())
+ return;
+
+#if !defined(OS_ANDROID)
+ // TODO(https://crbug.com/873320): Add support for Android.
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ binding_.Close();
+ AudioFocusManager::GetInstance()->RemoveObserver(observer_id_.value());
+#endif
+
+ observer_id_.reset();
+}
+
+AudioFocusObserver::~AudioFocusObserver() = default;
+
+} // namespace content
diff --git a/chromium/content/browser/media/session/audio_focus_observer.h b/chromium/content/browser/media/session/audio_focus_observer.h
new file mode 100644
index 00000000000..c4eae2b9f56
--- /dev/null
+++ b/chromium/content/browser/media/session/audio_focus_observer.h
@@ -0,0 +1,47 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_MEDIA_SESSION_AUDIO_FOCUS_OBSERVER_H_
+#define CONTENT_BROWSER_MEDIA_SESSION_AUDIO_FOCUS_OBSERVER_H_
+
+#include "base/macros.h"
+#include "base/optional.h"
+#include "content/common/content_export.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/interface_ptr_set.h"
+#include "services/media_session/public/mojom/audio_focus.mojom.h"
+
+namespace content {
+
+// The observer for observing audio focus events. This will not work on Android
+// as it does not use the internal AudioFocusManager implementation.
+class CONTENT_EXPORT AudioFocusObserver
+ : public media_session::mojom::AudioFocusObserver {
+ public:
+ AudioFocusObserver();
+ ~AudioFocusObserver() override;
+
+ // The given media session gained audio focus with the specified type.
+ void OnFocusGained(::media_session::mojom::MediaSessionPtr,
+ media_session::mojom::AudioFocusType) override {}
+
+ // The given media session lost audio focus.
+ void OnFocusLost(::media_session::mojom::MediaSessionPtr) override {}
+
+ protected:
+ // Called by subclasses to (un-)register the observer with AudioFocusManager.
+ void RegisterAudioFocusObserver();
+ void UnregisterAudioFocusObserver();
+
+ private:
+ base::Optional<mojo::InterfacePtrSetElementId> observer_id_;
+
+ mojo::Binding<media_session::mojom::AudioFocusObserver> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(AudioFocusObserver);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_SESSION_AUDIO_FOCUS_OBSERVER_H_
diff --git a/chromium/content/browser/media/session/media_session_android.cc b/chromium/content/browser/media/session/media_session_android.cc
index cd30af13b23..e110c52ea5e 100644
--- a/chromium/content/browser/media/session/media_session_android.cc
+++ b/chromium/content/browser/media/session/media_session_android.cc
@@ -12,6 +12,7 @@
#include "content/common/android/media_metadata_android.h"
#include "content/public/browser/media_session.h"
#include "jni/MediaSessionImpl_jni.h"
+#include "services/media_session/public/mojom/audio_focus.mojom.h"
namespace content {
@@ -167,7 +168,7 @@ void MediaSessionAndroid::RequestSystemAudioFocus(
const base::android::JavaParamRef<jobject>& j_obj) {
DCHECK(media_session());
static_cast<MediaSessionImpl*>(media_session())
- ->RequestSystemAudioFocus(AudioFocusManager::AudioFocusType::Gain);
+ ->RequestSystemAudioFocus(media_session::mojom::AudioFocusType::kGain);
}
WebContentsAndroid* MediaSessionAndroid::GetWebContentsAndroid() {
diff --git a/chromium/content/browser/media/session/media_session_browsertest.cc b/chromium/content/browser/media/session/media_session_browsertest.cc
index fb669cc671b..f89836e50a4 100644
--- a/chromium/content/browser/media/session/media_session_browsertest.cc
+++ b/chromium/content/browser/media/session/media_session_browsertest.cc
@@ -15,6 +15,7 @@
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "media/base/media_switches.h"
+#include "services/media_session/public/cpp/switches.h"
namespace content {
@@ -36,7 +37,7 @@ class MediaSessionBrowserTest : public ContentBrowserTest {
void EnableInternalMediaSesion() {
#if !defined(OS_ANDROID)
base::CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kEnableInternalMediaSession);
+ media_session::switches::kEnableInternalMediaSession);
#endif // !defined(OS_ANDROID)
}
@@ -176,6 +177,27 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, MultiplePlayersPlayPause) {
EXPECT_TRUE(IsPlaying(shell(), "long-audio"));
}
+IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, WebContents_Muted) {
+ EnableInternalMediaSesion();
+
+ NavigateToURL(shell(), GetTestUrl("media/session", "media-session.html"));
+
+ shell()->web_contents()->SetAudioMuted(true);
+ MediaSession* media_session = MediaSession::Get(shell()->web_contents());
+ ASSERT_NE(nullptr, media_session);
+
+ StartPlaybackAndWait(shell(), "long-video");
+ EXPECT_FALSE(media_session->IsControllable());
+
+ // Unmute the web contents and the player should be created.
+ shell()->web_contents()->SetAudioMuted(false);
+ EXPECT_TRUE(media_session->IsControllable());
+
+ // Now mute it again and the player should be removed.
+ shell()->web_contents()->SetAudioMuted(true);
+ EXPECT_FALSE(media_session->IsControllable());
+}
+
#if !defined(OS_ANDROID)
// On Android, System Audio Focus would break this test.
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, MultipleTabsPlayPause) {
diff --git a/chromium/content/browser/media/session/media_session_controller.cc b/chromium/content/browser/media/session/media_session_controller.cc
index 69df8daac0e..fa1a8a50405 100644
--- a/chromium/content/browser/media/session/media_session_controller.cc
+++ b/chromium/content/browser/media/session/media_session_controller.cc
@@ -32,6 +32,11 @@ bool MediaSessionController::Initialize(
bool has_audio,
bool is_remote,
media::MediaContentType media_content_type) {
+ // Store these as we will need them later.
+ is_remote_ = is_remote;
+ has_audio_ = has_audio;
+ media_content_type_ = media_content_type;
+
// Don't generate a new id if one has already been set.
if (!has_session_) {
// These objects are only created on the UI thread, so this is safe.
@@ -50,12 +55,13 @@ bool MediaSessionController::Initialize(
//
// TODO(dalecurtis): Delete sticky audio once we're no longer using WMPA and
// the BrowserMediaPlayerManagers. Tracked by http://crbug.com/580626
- has_audio = true;
+ has_audio_ = true;
}
// Don't bother with a MediaSession for remote players or without audio. If
// we already have a session from a previous call, release it.
- if (!has_audio || is_remote) {
+ if (!has_audio_ || is_remote ||
+ media_web_contents_observer_->web_contents()->IsAudioMuted()) {
if (has_session_) {
has_session_ = false;
media_session_->RemovePlayer(this, player_id_);
@@ -120,4 +126,19 @@ void MediaSessionController::OnPlaybackPaused() {
media_session_->OnPlayerPaused(this, player_id_);
}
+void MediaSessionController::WebContentsMutedStateChanged(bool muted) {
+ if (!has_audio_ || is_remote_)
+ return;
+
+ // We want to make sure we do not request audio focus on a muted tab as it
+ // would break user expectations by pausing/ducking other playbacks.
+ if (!muted && !has_session_) {
+ if (media_session_->AddPlayer(this, player_id_, media_content_type_))
+ has_session_ = true;
+ } else if (muted && has_session_) {
+ has_session_ = false;
+ media_session_->RemovePlayer(this, player_id_);
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/media/session/media_session_controller.h b/chromium/content/browser/media/session/media_session_controller.h
index 3a9ea7cfcc0..cff0dc78c0e 100644
--- a/chromium/content/browser/media/session/media_session_controller.h
+++ b/chromium/content/browser/media/session/media_session_controller.h
@@ -10,10 +10,7 @@
#include "content/browser/media/session/media_session_player_observer.h"
#include "content/common/content_export.h"
#include "content/public/browser/web_contents_observer.h"
-
-namespace media {
-enum class MediaContentType;
-} // namespace media
+#include "media/base/media_content_type.h"
namespace content {
@@ -57,6 +54,9 @@ class CONTENT_EXPORT MediaSessionController
// Test helpers.
int get_player_id_for_testing() const { return player_id_; }
+ // Called when the WebContents is either muted or unmuted.
+ void WebContentsMutedStateChanged(bool muted);
+
private:
const WebContentsObserver::MediaPlayerId id_;
@@ -68,6 +68,10 @@ class CONTENT_EXPORT MediaSessionController
int player_id_ = 0;
bool has_session_ = false;
+ bool has_audio_ = false;
+ bool is_remote_ = false;
+ media::MediaContentType media_content_type_ =
+ media::MediaContentType::Persistent;
DISALLOW_COPY_AND_ASSIGN(MediaSessionController);
};
diff --git a/chromium/content/browser/media/session/media_session_controllers_manager.cc b/chromium/content/browser/media/session/media_session_controllers_manager.cc
index 33947c0d4b6..4607e46dc8b 100644
--- a/chromium/content/browser/media/session/media_session_controllers_manager.cc
+++ b/chromium/content/browser/media/session/media_session_controllers_manager.cc
@@ -4,28 +4,11 @@
#include "content/browser/media/session/media_session_controllers_manager.h"
-#include "base/command_line.h"
#include "content/browser/media/session/media_session_controller.h"
-#include "media/base/media_switches.h"
+#include "services/media_session/public/cpp/switches.h"
namespace content {
-namespace {
-
-bool IsMediaSessionEnabled() {
-// Media session is enabled on Android and Chrome OS to allow control of media
-// players as needed.
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
- return true;
-#else
- base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
- return command_line->HasSwitch(switches::kEnableInternalMediaSession) ||
- command_line->HasSwitch(switches::kEnableAudioFocus);
-#endif
-}
-
-} // anonymous namespace
-
MediaSessionControllersManager::MediaSessionControllersManager(
MediaWebContentsObserver* media_web_contents_observer)
: media_web_contents_observer_(media_web_contents_observer) {}
@@ -34,7 +17,7 @@ MediaSessionControllersManager::~MediaSessionControllersManager() = default;
void MediaSessionControllersManager::RenderFrameDeleted(
RenderFrameHost* render_frame_host) {
- if (!IsMediaSessionEnabled())
+ if (!media_session::IsMediaSessionEnabled())
return;
for (auto it = controllers_map_.begin(); it != controllers_map_.end();) {
@@ -50,7 +33,7 @@ bool MediaSessionControllersManager::RequestPlay(
bool has_audio,
bool is_remote,
media::MediaContentType media_content_type) {
- if (!IsMediaSessionEnabled())
+ if (!media_session::IsMediaSessionEnabled())
return true;
// Since we don't remove session instances on pause, there may be an existing
@@ -78,7 +61,7 @@ bool MediaSessionControllersManager::RequestPlay(
}
void MediaSessionControllersManager::OnPause(const MediaPlayerId& id) {
- if (!IsMediaSessionEnabled())
+ if (!media_session::IsMediaSessionEnabled())
return;
auto it = controllers_map_.find(id);
@@ -89,9 +72,17 @@ void MediaSessionControllersManager::OnPause(const MediaPlayerId& id) {
}
void MediaSessionControllersManager::OnEnd(const MediaPlayerId& id) {
- if (!IsMediaSessionEnabled())
+ if (!media_session::IsMediaSessionEnabled())
return;
controllers_map_.erase(id);
}
+void MediaSessionControllersManager::WebContentsMutedStateChanged(bool muted) {
+ if (!media_session::IsMediaSessionEnabled())
+ return;
+
+ for (auto& entry : controllers_map_)
+ entry.second->WebContentsMutedStateChanged(muted);
+}
+
} // namespace content
diff --git a/chromium/content/browser/media/session/media_session_controllers_manager.h b/chromium/content/browser/media/session/media_session_controllers_manager.h
index cf991cc3cb9..f15c96e11b5 100644
--- a/chromium/content/browser/media/session/media_session_controllers_manager.h
+++ b/chromium/content/browser/media/session/media_session_controllers_manager.h
@@ -54,6 +54,9 @@ class CONTENT_EXPORT MediaSessionControllersManager {
// Called when the given player |id| has ended.
void OnEnd(const MediaPlayerId& id);
+ // Called when the WebContents was muted or unmuted.
+ void WebContentsMutedStateChanged(bool muted);
+
private:
friend class MediaSessionControllersManagerTest;
diff --git a/chromium/content/browser/media/session/media_session_controllers_manager_unittest.cc b/chromium/content/browser/media/session/media_session_controllers_manager_unittest.cc
index e8e18e1f400..0c8afb247db 100644
--- a/chromium/content/browser/media/session/media_session_controllers_manager_unittest.cc
+++ b/chromium/content/browser/media/session/media_session_controllers_manager_unittest.cc
@@ -10,7 +10,7 @@
#include "content/test/test_render_view_host.h"
#include "content/test/test_web_contents.h"
#include "media/base/media_content_type.h"
-#include "media/base/media_switches.h"
+#include "services/media_session/public/cpp/switches.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -46,11 +46,11 @@ class MediaSessionControllersManagerTest
#if !defined(OS_ANDROID)
if (IsInternalMediaSessionEnabled()) {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kEnableInternalMediaSession);
+ media_session::switches::kEnableInternalMediaSession);
}
if (IsAudioFocusEnabled()) {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kEnableAudioFocus);
+ media_session::switches::kEnableAudioFocus);
}
#endif
diff --git a/chromium/content/browser/media/session/media_session_impl.cc b/chromium/content/browser/media/session/media_session_impl.cc
index a66c5d02e07..15bab907e47 100644
--- a/chromium/content/browser/media/session/media_session_impl.cc
+++ b/chromium/content/browser/media/session/media_session_impl.cc
@@ -5,8 +5,10 @@
#include "content/browser/media/session/media_session_impl.h"
#include <algorithm>
+#include <utility>
#include "base/numerics/ranges.h"
+#include "base/strings/string_util.h"
#include "content/browser/media/session/audio_focus_delegate.h"
#include "content/browser/media/session/media_session_controller.h"
#include "content/browser/media/session/media_session_player_observer.h"
@@ -17,6 +19,7 @@
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents.h"
#include "media/base/media_content_type.h"
+#include "services/media_session/public/mojom/audio_focus.mojom.h"
#include "third_party/blink/public/platform/modules/mediasession/media_session.mojom.h"
#if defined(OS_ANDROID)
@@ -32,6 +35,12 @@ namespace {
const double kUnduckedVolumeMultiplier = 1.0;
const double kDefaultDuckingVolumeMultiplier = 0.2;
+const char kDebugInfoOwnerSeparator[] = " - ";
+const char kDebugInfoDucked[] = "Ducked";
+const char kDebugInfoActive[] = "Active";
+const char kDebugInfoInactive[] = "Inactive";
+const char kDebugInfoStateSeparator[] = " ";
+
using MapRenderFrameHostToDepth = std::map<RenderFrameHost*, size_t>;
size_t ComputeFrameDepth(RenderFrameHost* rfh,
@@ -72,13 +81,20 @@ MediaSessionUserAction MediaSessionActionToUserAction(
return MediaSessionUserAction::Count;
}
+// If the string is not empty then push it to the back of a vector.
+void MaybePushBackString(std::vector<std::string>& vector,
+ const std::string& str) {
+ if (!str.empty())
+ vector.push_back(str);
+}
+
} // anonymous namespace
+using media_session::mojom::AudioFocusType;
+
using MediaSessionSuspendedSource =
MediaSessionUmaHelper::MediaSessionSuspendedSource;
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(MediaSessionImpl);
-
MediaSessionImpl::PlayerIdentifier::PlayerIdentifier(
MediaSessionPlayerObserver* observer,
int player_id)
@@ -195,23 +211,23 @@ bool MediaSessionImpl::AddPlayer(MediaSessionPlayerObserver* observer,
observer->OnSetVolumeMultiplier(player_id, GetVolumeMultiplier());
- AudioFocusManager::AudioFocusType required_audio_focus_type;
- if (media_content_type == media::MediaContentType::Persistent) {
- required_audio_focus_type = AudioFocusManager::AudioFocusType::Gain;
- } else {
- required_audio_focus_type =
- AudioFocusManager::AudioFocusType::GainTransientMayDuck;
- }
+ AudioFocusType required_audio_focus_type;
+ if (media_content_type == media::MediaContentType::Persistent)
+ required_audio_focus_type = AudioFocusType::kGain;
+ else
+ required_audio_focus_type = AudioFocusType::kGainTransientMayDuck;
// If the audio focus is already granted and is of type Content, there is
// nothing to do. If it is granted of type Transient the requested type is
// also transient, there is also nothing to do. Otherwise, the session needs
// to request audio focus again.
- if (audio_focus_state_ == State::ACTIVE &&
- (audio_focus_type_ == AudioFocusManager::AudioFocusType::Gain ||
- audio_focus_type_ == required_audio_focus_type)) {
- normal_players_.insert(PlayerIdentifier(observer, player_id));
- return true;
+ if (audio_focus_state_ == State::ACTIVE) {
+ AudioFocusType current_focus_type = delegate_->GetCurrentFocusType();
+ if (current_focus_type == AudioFocusType::kGain ||
+ current_focus_type == required_audio_focus_type) {
+ normal_players_.insert(PlayerIdentifier(observer, player_id));
+ return true;
+ }
}
State old_audio_focus_state = audio_focus_state_;
@@ -346,7 +362,7 @@ void MediaSessionImpl::Resume(SuspendType suspend_type) {
if (suspend_type != SuspendType::SYSTEM) {
// Request audio focus again in case we lost it because another app started
// playing while the playback was paused.
- State audio_focus_state = RequestSystemAudioFocus(audio_focus_type_)
+ State audio_focus_state = RequestSystemAudioFocus(desired_audio_focus_type_)
? State::ACTIVE
: State::INACTIVE;
SetAudioFocusState(audio_focus_state);
@@ -410,7 +426,7 @@ bool MediaSessionImpl::IsControllable() const {
// inactive. Also, the session will be uncontrollable if it contains one-shot
// players.
return audio_focus_state_ != State::INACTIVE &&
- audio_focus_type_ == AudioFocusManager::AudioFocusType::Gain &&
+ desired_audio_focus_type_ == AudioFocusType::kGain &&
one_shot_players_.empty();
}
@@ -560,8 +576,7 @@ void MediaSessionImpl::OnResumeInternal(SuspendType suspend_type) {
MediaSessionImpl::MediaSessionImpl(WebContents* web_contents)
: WebContentsObserver(web_contents),
audio_focus_state_(State::INACTIVE),
- audio_focus_type_(
- AudioFocusManager::AudioFocusType::GainTransientMayDuck),
+ desired_audio_focus_type_(AudioFocusType::kGainTransientMayDuck),
is_ducking_(false),
ducking_volume_multiplier_(kDefaultDuckingVolumeMultiplier),
routed_service_(nullptr) {
@@ -575,7 +590,7 @@ void MediaSessionImpl::Initialize() {
}
bool MediaSessionImpl::RequestSystemAudioFocus(
- AudioFocusManager::AudioFocusType audio_focus_type) {
+ AudioFocusType audio_focus_type) {
bool result = delegate_->RequestAudioFocus(audio_focus_type);
uma_helper_.RecordRequestAudioFocusResult(result);
@@ -586,10 +601,41 @@ bool MediaSessionImpl::RequestSystemAudioFocus(
// MediaSessionImpl must change its state & audio focus type AFTER requesting
// audio focus.
SetAudioFocusState(result ? State::ACTIVE : State::INACTIVE);
- audio_focus_type_ = audio_focus_type;
+ desired_audio_focus_type_ = audio_focus_type;
return result;
}
+const MediaSessionImpl::DebugInfo MediaSessionImpl::GetDebugInfo() {
+ MediaSessionImpl::DebugInfo debug_info;
+
+ // Convert the address of |this| to a string and use it as the name.
+ std::stringstream stream;
+ stream << this;
+ debug_info.name = stream.str();
+
+ // Add the title and the url to the owner.
+ std::vector<std::string> owner_parts;
+ MaybePushBackString(owner_parts,
+ base::UTF16ToUTF8(web_contents()->GetTitle()));
+ MaybePushBackString(owner_parts,
+ web_contents()->GetLastCommittedURL().spec());
+ debug_info.owner = base::JoinString(owner_parts, kDebugInfoOwnerSeparator);
+
+ // Add the ducking state to state.
+ std::vector<std::string> state_parts;
+ MaybePushBackString(state_parts,
+ IsActive() ? kDebugInfoActive : kDebugInfoInactive);
+ MaybePushBackString(state_parts, is_ducking_ ? kDebugInfoDucked : "");
+ debug_info.state = base::JoinString(state_parts, kDebugInfoStateSeparator);
+
+ return debug_info;
+}
+
+void MediaSessionImpl::BindToMojoRequest(
+ mojo::InterfaceRequest<media_session::mojom::MediaSession> request) {
+ bindings_.AddBinding(this, std::move(request));
+}
+
void MediaSessionImpl::AbandonSystemAudioFocusIfNeeded() {
if (audio_focus_state_ == State::INACTIVE || !normal_players_.empty() ||
!pepper_players_.empty() || !one_shot_players_.empty()) {
@@ -630,8 +676,7 @@ void MediaSessionImpl::SetAudioFocusState(State audio_focus_state) {
bool MediaSessionImpl::AddPepperPlayer(MediaSessionPlayerObserver* observer,
int player_id) {
- bool success =
- RequestSystemAudioFocus(AudioFocusManager::AudioFocusType::Gain);
+ bool success = RequestSystemAudioFocus(AudioFocusType::kGain);
DCHECK(success);
pepper_players_.insert(PlayerIdentifier(observer, player_id));
@@ -644,7 +689,7 @@ bool MediaSessionImpl::AddPepperPlayer(MediaSessionPlayerObserver* observer,
bool MediaSessionImpl::AddOneShotPlayer(MediaSessionPlayerObserver* observer,
int player_id) {
- if (!RequestSystemAudioFocus(AudioFocusManager::AudioFocusType::Gain))
+ if (!RequestSystemAudioFocus(AudioFocusType::kGain))
return false;
one_shot_players_.insert(PlayerIdentifier(observer, player_id));
diff --git a/chromium/content/browser/media/session/media_session_impl.h b/chromium/content/browser/media/session/media_session_impl.h
index 637acb6dfcf..42f85c71133 100644
--- a/chromium/content/browser/media/session/media_session_impl.h
+++ b/chromium/content/browser/media/session/media_session_impl.h
@@ -23,6 +23,9 @@
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "content/public/common/media_metadata.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/media_session/public/mojom/audio_focus.mojom.h"
#if defined(OS_ANDROID)
#include "base/android/scoped_java_ref.h"
@@ -34,6 +37,12 @@ namespace media {
enum class MediaContentType;
} // namespace media
+namespace media_session {
+namespace mojom {
+enum class AudioFocusType;
+} // namespace mojom
+} // namespace media_session
+
namespace content {
class AudioFocusDelegate;
@@ -161,12 +170,6 @@ class MediaSessionImpl : public MediaSession,
// Returns if the session is currently suspended.
CONTENT_EXPORT bool IsSuspended() const;
- // Returns the audio focus type. The type is updated everytime after the
- // session requests audio focus.
- CONTENT_EXPORT AudioFocusManager::AudioFocusType audio_focus_type() const {
- return audio_focus_type_;
- }
-
// Returns whether the session has Pepper instances.
bool HasPepper() const;
@@ -202,7 +205,24 @@ class MediaSessionImpl : public MediaSession,
// Requests audio focus to the AudioFocusDelegate.
// Returns whether the request was granted.
CONTENT_EXPORT bool RequestSystemAudioFocus(
- AudioFocusManager::AudioFocusType audio_focus_type);
+ media_session::mojom::AudioFocusType audio_focus_type);
+
+ // Returns debugging information to be displayed on chrome://media-internals.
+ struct DebugInfo {
+ // A unique name for the MediaSession.
+ std::string name;
+
+ // The title and URL of the owning WebContents.
+ std::string owner;
+
+ // State information stored in a string e.g. Ducked.
+ std::string state;
+ };
+ const DebugInfo GetDebugInfo();
+
+ // Creates a binding between |this| and |request|.
+ void BindToMojoRequest(
+ mojo::InterfaceRequest<media_session::mojom::MediaSession> request);
private:
friend class content::WebContentsUserData<MediaSessionImpl>;
@@ -212,6 +232,7 @@ class MediaSessionImpl : public MediaSession,
friend class content::MediaSessionImplServiceRoutingTest;
friend class content::MediaSessionImplStateObserver;
friend class content::MediaSessionServiceImplBrowserTest;
+ friend class MediaInternalsAudioFocusTest;
CONTENT_EXPORT void SetDelegateForTests(
std::unique_ptr<AudioFocusDelegate> delegate);
@@ -294,9 +315,12 @@ class MediaSessionImpl : public MediaSession,
PlayersMap pepper_players_;
PlayersMap one_shot_players_;
- State audio_focus_state_;
+ State audio_focus_state_ = State::INACTIVE;
MediaSession::SuspendType suspend_type_;
- AudioFocusManager::AudioFocusType audio_focus_type_;
+
+ // The |desired_audio_focus_type_| is the AudioFocusType we will request when
+ // we request system audio focus.
+ media_session::mojom::AudioFocusType desired_audio_focus_type_;
MediaSessionUmaHelper uma_helper_;
@@ -309,7 +333,7 @@ class MediaSessionImpl : public MediaSession,
base::CallbackList<void(State)> media_session_state_listeners_;
- base::ObserverList<MediaSessionObserver> observers_;
+ base::ObserverList<MediaSessionObserver>::Unchecked observers_;
#if defined(OS_ANDROID)
std::unique_ptr<MediaSessionAndroid> session_android_;
@@ -325,6 +349,9 @@ class MediaSessionImpl : public MediaSession,
// The currently routed service (non-owned pointer).
MediaSessionServiceImpl* routed_service_;
+ // Bindings for Mojo pointers to |this| held by media route providers.
+ mojo::BindingSet<media_session::mojom::MediaSession> bindings_;
+
DISALLOW_COPY_AND_ASSIGN(MediaSessionImpl);
};
diff --git a/chromium/content/browser/media/session/media_session_impl_browsertest.cc b/chromium/content/browser/media/session/media_session_impl_browsertest.cc
index f423db1ed37..a39d86d6a83 100644
--- a/chromium/content/browser/media/session/media_session_impl_browsertest.cc
+++ b/chromium/content/browser/media/session/media_session_impl_browsertest.cc
@@ -24,6 +24,7 @@
#include "content/public/test/content_browser_test.h"
#include "content/shell/browser/shell.h"
#include "media/base/media_content_type.h"
+#include "services/media_session/public/mojom/audio_focus.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
using content::WebContents;
@@ -35,6 +36,8 @@ using content::MediaSessionPlayerObserver;
using content::MediaSessionUmaHelper;
using content::MockMediaSessionPlayerObserver;
+using media_session::mojom::AudioFocusType;
+
using ::testing::Eq;
using ::testing::Expectation;
using ::testing::NiceMock;
@@ -48,13 +51,22 @@ const double kDifferentDuckingVolumeMultiplier = 0.018;
class MockAudioFocusDelegate : public AudioFocusDelegate {
public:
- MockAudioFocusDelegate() {
- ON_CALL(*this, RequestAudioFocus(_)).WillByDefault(::testing::Return(true));
- }
+ MockAudioFocusDelegate() {}
- MOCK_METHOD1(RequestAudioFocus,
- bool(content::AudioFocusManager::AudioFocusType));
MOCK_METHOD0(AbandonAudioFocus, void());
+
+ bool RequestAudioFocus(AudioFocusType audio_focus_type) {
+ audio_focus_type_ = audio_focus_type;
+ return true;
+ }
+
+ AudioFocusType GetCurrentFocusType() const {
+ DCHECK(audio_focus_type_.has_value());
+ return audio_focus_type_.value();
+ }
+
+ private:
+ base::Optional<AudioFocusType> audio_focus_type_;
};
class MockMediaSessionServiceImpl : public content::MediaSessionServiceImpl {
@@ -121,8 +133,8 @@ class MediaSessionImplBrowserTest : public content::ContentBrowserTest {
bool IsActive() { return media_session_->IsActive(); }
- content::AudioFocusManager::AudioFocusType GetSessionAudioFocusType() {
- return media_session_->audio_focus_type();
+ AudioFocusType GetSessionAudioFocusType() {
+ return mock_audio_focus_delegate_->GetCurrentFocusType();
}
bool IsControllable() { return media_session_->IsControllable(); }
@@ -356,8 +368,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionImplBrowserTest,
CanRequestFocusBeforePlayerCreation) {
auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
- media_session_->RequestSystemAudioFocus(
- content::AudioFocusManager::AudioFocusType::Gain);
+ media_session_->RequestSystemAudioFocus(AudioFocusType::kGain);
EXPECT_TRUE(IsActive());
StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
@@ -542,23 +553,19 @@ IN_PROC_BROWSER_TEST_F(MediaSessionImplBrowserTest, AudioFocusType) {
// Starting a player with a given type should set the session to that type.
StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
- EXPECT_EQ(content::AudioFocusManager::AudioFocusType::GainTransientMayDuck,
- GetSessionAudioFocusType());
+ EXPECT_EQ(AudioFocusType::kGainTransientMayDuck, GetSessionAudioFocusType());
// Adding a player of the same type should have no effect on the type.
StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
- EXPECT_EQ(content::AudioFocusManager::AudioFocusType::GainTransientMayDuck,
- GetSessionAudioFocusType());
+ EXPECT_EQ(AudioFocusType::kGainTransientMayDuck, GetSessionAudioFocusType());
// Adding a player of Content type should override the current type.
StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
- EXPECT_EQ(content::AudioFocusManager::AudioFocusType::Gain,
- GetSessionAudioFocusType());
+ EXPECT_EQ(AudioFocusType::kGain, GetSessionAudioFocusType());
// Adding a player of the Transient type should have no effect on the type.
StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
- EXPECT_EQ(content::AudioFocusManager::AudioFocusType::Gain,
- GetSessionAudioFocusType());
+ EXPECT_EQ(AudioFocusType::kGain, GetSessionAudioFocusType());
EXPECT_TRUE(player_observer->IsPlaying(0));
EXPECT_TRUE(player_observer->IsPlaying(1));
@@ -572,8 +579,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionImplBrowserTest, AudioFocusType) {
EXPECT_FALSE(player_observer->IsPlaying(2));
EXPECT_FALSE(player_observer->IsPlaying(3));
- EXPECT_EQ(content::AudioFocusManager::AudioFocusType::Gain,
- GetSessionAudioFocusType());
+ EXPECT_EQ(AudioFocusType::kGain, GetSessionAudioFocusType());
SystemResume();
@@ -582,8 +588,7 @@ IN_PROC_BROWSER_TEST_F(MediaSessionImplBrowserTest, AudioFocusType) {
EXPECT_TRUE(player_observer->IsPlaying(2));
EXPECT_TRUE(player_observer->IsPlaying(3));
- EXPECT_EQ(content::AudioFocusManager::AudioFocusType::Gain,
- GetSessionAudioFocusType());
+ EXPECT_EQ(AudioFocusType::kGain, GetSessionAudioFocusType());
}
IN_PROC_BROWSER_TEST_F(MediaSessionImplBrowserTest, ControlsShowForContent) {
@@ -1075,17 +1080,12 @@ IN_PROC_BROWSER_TEST_F(MediaSessionImplBrowserTest, ResumeSuspendFromSystem) {
IN_PROC_BROWSER_TEST_F(MediaSessionImplBrowserTest, OneShotTakesGainFocus) {
auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
- EXPECT_CALL(
- *mock_audio_focus_delegate(),
- RequestAudioFocus(content::AudioFocusManager::AudioFocusType::Gain))
- .Times(1);
- EXPECT_CALL(*mock_audio_focus_delegate(),
- RequestAudioFocus(::testing::Ne(
- content::AudioFocusManager::AudioFocusType::Gain)))
- .Times(0);
StartNewPlayer(player_observer.get(), media::MediaContentType::OneShot);
StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+
+ EXPECT_EQ(AudioFocusType::kGain,
+ mock_audio_focus_delegate()->GetCurrentFocusType());
}
IN_PROC_BROWSER_TEST_F(MediaSessionImplBrowserTest, RemovingOneShotDropsFocus) {
diff --git a/chromium/content/browser/media/session/media_session_impl_visibility_browsertest.cc b/chromium/content/browser/media/session/media_session_impl_visibility_browsertest.cc
index 05bbdb6c355..d25f4fad6b8 100644
--- a/chromium/content/browser/media/session/media_session_impl_visibility_browsertest.cc
+++ b/chromium/content/browser/media/session/media_session_impl_visibility_browsertest.cc
@@ -20,6 +20,7 @@
#include "content/public/test/test_navigation_observer.h"
#include "content/shell/browser/shell.h"
#include "media/base/media_switches.h"
+#include "services/media_session/public/cpp/switches.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
@@ -107,7 +108,7 @@ class MediaSessionImplVisibilityBrowserTest
switches::kAutoplayPolicy,
switches::autoplay::kNoUserGestureRequiredPolicy);
#if !defined(OS_ANDROID)
- command_line->AppendSwitch(switches::kEnableAudioFocus);
+ command_line->AppendSwitch(media_session::switches::kEnableAudioFocus);
#endif // !defined(OS_ANDROID)
VisibilityTestData params = GetVisibilityTestData();
diff --git a/chromium/content/browser/media/session/pepper_playback_observer.cc b/chromium/content/browser/media/session/pepper_playback_observer.cc
index ab55c60796a..c8e7cd3d2a2 100644
--- a/chromium/content/browser/media/session/pepper_playback_observer.cc
+++ b/chromium/content/browser/media/session/pepper_playback_observer.cc
@@ -11,7 +11,7 @@
#include "content/common/frame_messages.h"
#include "ipc/ipc_message_macros.h"
#include "media/base/media_content_type.h"
-#include "media/base/media_switches.h"
+#include "services/media_session/public/cpp/switches.h"
namespace content {
@@ -75,8 +75,9 @@ void PepperPlaybackObserver::PepperStartsPlayback(
MediaSessionImpl::Get(contents_)->AddPlayer(
players_map_[id].get(), PepperPlayerDelegate::kPlayerId,
- media::IsAudioFocusDuckFlashEnabled() ? media::MediaContentType::Pepper
- : media::MediaContentType::OneShot);
+ media_session::IsAudioFocusDuckFlashEnabled()
+ ? media::MediaContentType::Pepper
+ : media::MediaContentType::OneShot);
}
void PepperPlaybackObserver::PepperStopsPlayback(
diff --git a/chromium/content/browser/media/session/pepper_player_delegate.cc b/chromium/content/browser/media/session/pepper_player_delegate.cc
index d3e23c458a5..a662cca2f2a 100644
--- a/chromium/content/browser/media/session/pepper_player_delegate.cc
+++ b/chromium/content/browser/media/session/pepper_player_delegate.cc
@@ -8,7 +8,7 @@
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/media/session/pepper_playback_observer.h"
#include "content/common/frame_messages.h"
-#include "media/base/media_switches.h"
+#include "services/media_session/public/cpp/switches.h"
namespace content {
@@ -28,7 +28,7 @@ PepperPlayerDelegate::PepperPlayerDelegate(
PepperPlayerDelegate::~PepperPlayerDelegate() = default;
void PepperPlayerDelegate::OnSuspend(int player_id) {
- if (!media::IsAudioFocusDuckFlashEnabled())
+ if (!media_session::IsAudioFocusDuckFlashEnabled())
return;
// Pepper player cannot be really suspended. Duck the volume instead.
@@ -37,7 +37,7 @@ void PepperPlayerDelegate::OnSuspend(int player_id) {
}
void PepperPlayerDelegate::OnResume(int player_id) {
- if (!media::IsAudioFocusDuckFlashEnabled())
+ if (!media_session::IsAudioFocusDuckFlashEnabled())
return;
DCHECK_EQ(player_id, kPlayerId);
@@ -56,7 +56,7 @@ void PepperPlayerDelegate::OnSeekBackward(int player_id,
void PepperPlayerDelegate::OnSetVolumeMultiplier(int player_id,
double volume_multiplier) {
- if (!media::IsAudioFocusDuckFlashEnabled())
+ if (!media_session::IsAudioFocusDuckFlashEnabled())
return;
DCHECK_EQ(player_id, kPlayerId);
diff --git a/chromium/content/browser/media/video_decoder_proxy.cc b/chromium/content/browser/media/video_decoder_proxy.cc
new file mode 100644
index 00000000000..ea252f0c806
--- /dev/null
+++ b/chromium/content/browser/media/video_decoder_proxy.cc
@@ -0,0 +1,96 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/video_decoder_proxy.h"
+
+#include "base/logging.h"
+#include "content/public/common/service_manager_connection.h"
+#include "media/mojo/interfaces/constants.mojom.h"
+#include "media/mojo/interfaces/media_service.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
+
+namespace content {
+
+VideoDecoderProxy::VideoDecoderProxy() {
+ DVLOG(1) << __func__;
+}
+
+VideoDecoderProxy::~VideoDecoderProxy() {
+ DVLOG(1) << __func__;
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+}
+
+void VideoDecoderProxy::Add(media::mojom::InterfaceFactoryRequest request) {
+ DVLOG(1) << __func__;
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ bindings_.AddBinding(this, std::move(request));
+}
+
+void VideoDecoderProxy::CreateAudioDecoder(
+ media::mojom::AudioDecoderRequest request) {}
+
+void VideoDecoderProxy::CreateVideoDecoder(
+ media::mojom::VideoDecoderRequest request) {
+ DVLOG(2) << __func__;
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ InterfaceFactory* factory = GetMediaInterfaceFactory();
+ if (factory)
+ factory->CreateVideoDecoder(std::move(request));
+}
+
+void VideoDecoderProxy::CreateRenderer(media::mojom::HostedRendererType type,
+ const std::string& type_specific_id,
+ media::mojom::RendererRequest request) {}
+
+void VideoDecoderProxy::CreateCdm(
+ const std::string& key_system,
+ media::mojom::ContentDecryptionModuleRequest request) {}
+
+void VideoDecoderProxy::CreateDecryptor(
+ int cdm_id,
+ media::mojom::DecryptorRequest request) {}
+
+void VideoDecoderProxy::CreateCdmProxy(const std::string& cdm_guid,
+ media::mojom::CdmProxyRequest request) {}
+
+media::mojom::InterfaceFactory* VideoDecoderProxy::GetMediaInterfaceFactory() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ if (!interface_factory_ptr_)
+ ConnectToMediaService();
+
+ return interface_factory_ptr_.get();
+}
+
+void VideoDecoderProxy::ConnectToMediaService() {
+ DVLOG(1) << __func__;
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(!interface_factory_ptr_);
+
+ media::mojom::MediaServicePtr media_service;
+ // TODO(slan): Use the BrowserContext Connector instead.
+ // See https://crbug.com/638950.
+ service_manager::Connector* connector =
+ ServiceManagerConnection::GetForProcess()->GetConnector();
+ connector->BindInterface(media::mojom::kMediaServiceName, &media_service);
+
+ // TODO(sandersd): Do we need to bind an empty |interfaces| implementation?
+ service_manager::mojom::InterfaceProviderPtr interfaces;
+ media_service->CreateInterfaceFactory(MakeRequest(&interface_factory_ptr_),
+ std::move(interfaces));
+
+ interface_factory_ptr_.set_connection_error_handler(
+ base::BindOnce(&VideoDecoderProxy::OnMediaServiceConnectionError,
+ base::Unretained(this)));
+}
+
+void VideoDecoderProxy::OnMediaServiceConnectionError() {
+ DVLOG(1) << __func__;
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ interface_factory_ptr_.reset();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/video_decoder_proxy.h b/chromium/content/browser/media/video_decoder_proxy.h
new file mode 100644
index 00000000000..35052a5d7fb
--- /dev/null
+++ b/chromium/content/browser/media/video_decoder_proxy.h
@@ -0,0 +1,58 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_MEDIA_VIDEO_DECODER_PROXY_H_
+#define CONTENT_BROWSER_MEDIA_VIDEO_DECODER_PROXY_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "media/mojo/interfaces/interface_factory.mojom.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+
+namespace content {
+
+// This implements the media::mojom::InterfaceFactory interface for a
+// RenderProcessHostImpl. Unlike MediaInterfaceProxy, only
+// CreateVideoDecoder() is implemented. This allows WebRTC to create
+// MojoVideoDecoder instances without a RenderFrame.
+class VideoDecoderProxy : public media::mojom::InterfaceFactory {
+ public:
+ VideoDecoderProxy();
+ ~VideoDecoderProxy() final;
+
+ void Add(media::mojom::InterfaceFactoryRequest request);
+
+ // media::mojom::InterfaceFactory implementation.
+ void CreateAudioDecoder(media::mojom::AudioDecoderRequest request) final;
+ void CreateVideoDecoder(media::mojom::VideoDecoderRequest request) final;
+ void CreateRenderer(media::mojom::HostedRendererType type,
+ const std::string& type_specific_id,
+ media::mojom::RendererRequest request) final;
+ void CreateCdm(const std::string& key_system,
+ media::mojom::ContentDecryptionModuleRequest request) final;
+ void CreateDecryptor(int cdm_id,
+ media::mojom::DecryptorRequest request) final;
+ void CreateCdmProxy(const std::string& cdm_guid,
+ media::mojom::CdmProxyRequest request) final;
+
+ private:
+ media::mojom::InterfaceFactory* GetMediaInterfaceFactory();
+ void ConnectToMediaService();
+ void OnMediaServiceConnectionError();
+
+ // Connection to the remote media InterfaceFactory.
+ media::mojom::InterfaceFactoryPtr interface_factory_ptr_;
+
+ // Connections to the renderer.
+ mojo::BindingSet<media::mojom::InterfaceFactory> bindings_;
+
+ THREAD_CHECKER(thread_checker_);
+ DISALLOW_COPY_AND_ASSIGN(VideoDecoderProxy);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_VIDEO_DECODER_PROXY_H_
diff --git a/chromium/content/browser/media/webaudio/OWNERS b/chromium/content/browser/media/webaudio/OWNERS
new file mode 100644
index 00000000000..5f297b8bf52
--- /dev/null
+++ b/chromium/content/browser/media/webaudio/OWNERS
@@ -0,0 +1,4 @@
+hongchan@chromium.org
+rtoy@chromium.org
+
+# COMPONENT: Blink>WebAudio \ No newline at end of file
diff --git a/chromium/content/browser/media/webaudio/audio_context_manager_browsertest.cc b/chromium/content/browser/media/webaudio/audio_context_manager_browsertest.cc
new file mode 100644
index 00000000000..9ab3e351ae6
--- /dev/null
+++ b/chromium/content/browser/media/webaudio/audio_context_manager_browsertest.cc
@@ -0,0 +1,75 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/shell/browser/shell.h"
+
+namespace content {
+
+namespace {
+// Test for audible playback message.
+class WaitForAudioContextAudible : WebContentsObserver {
+ public:
+ explicit WaitForAudioContextAudible(WebContents* web_contents)
+ : WebContentsObserver(web_contents) {
+ run_loop_.Run();
+ }
+
+ void AudioContextPlaybackStarted(const AudioContextId&) final {
+ // Stop the run loop when we get the message
+ run_loop_.Quit();
+ }
+
+ private:
+ base::RunLoop run_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(WaitForAudioContextAudible);
+};
+
+// Test for silent playback started (audible playback stopped).
+class WaitForAudioContextSilent : WebContentsObserver {
+ public:
+ explicit WaitForAudioContextSilent(WebContents* web_contents)
+ : WebContentsObserver(web_contents) {
+ run_loop_.Run();
+ }
+
+ void AudioContextPlaybackStopped(const AudioContextId&) final {
+ // Stop the run loop when we get the message
+ run_loop_.Quit();
+ }
+
+ private:
+ base::RunLoop run_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(WaitForAudioContextSilent);
+};
+
+} // namespace
+
+class AudioContextManagerTest : public ContentBrowserTest {};
+
+IN_PROC_BROWSER_TEST_F(AudioContextManagerTest, AudioContextPlaybackRecorded) {
+ NavigateToURL(shell(),
+ content::GetTestUrl("media/webaudio/", "playback-test.html"));
+
+ // Set gain to 1 to start audible audio and verify we got the
+ // playback started message.
+ {
+ ASSERT_TRUE(ExecuteScript(shell()->web_contents(), "gain.gain.value = 1;"));
+ WaitForAudioContextAudible wait(shell()->web_contents());
+ }
+
+ // Set gain to 0 to stop audible audio and verify we got the
+ // playback stopped message.
+ {
+ ASSERT_TRUE(ExecuteScript(shell()->web_contents(), "gain.gain.value = 0;"));
+ WaitForAudioContextSilent wait(shell()->web_contents());
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/webaudio/audio_context_manager_impl.cc b/chromium/content/browser/media/webaudio/audio_context_manager_impl.cc
new file mode 100644
index 00000000000..889ccb0026a
--- /dev/null
+++ b/chromium/content/browser/media/webaudio/audio_context_manager_impl.cc
@@ -0,0 +1,50 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/webaudio/audio_context_manager_impl.h"
+
+#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+
+namespace content {
+
+void AudioContextManagerImpl::Create(
+ RenderFrameHost* render_frame_host,
+ blink::mojom::AudioContextManagerRequest request) {
+ DCHECK(render_frame_host);
+
+ // The object is bound to the lifetime of |render_frame_host| and the mojo
+ // connection. See FrameServiceBase for details.
+ new AudioContextManagerImpl(render_frame_host, std::move(request));
+}
+
+AudioContextManagerImpl::AudioContextManagerImpl(
+ RenderFrameHost* render_frame_host,
+ blink::mojom::AudioContextManagerRequest request)
+ : FrameServiceBase(render_frame_host, std::move(request)),
+ render_frame_host_impl_(
+ static_cast<RenderFrameHostImpl*>(render_frame_host)) {
+ DCHECK(render_frame_host);
+}
+
+AudioContextManagerImpl::~AudioContextManagerImpl() = default;
+
+void AudioContextManagerImpl::AudioContextAudiblePlaybackStarted(
+ int32_t audio_context_id) {
+ // Notify observers that audible audio started playing from a WebAudio
+ // AudioContext.
+ render_frame_host_impl_->AudioContextPlaybackStarted(audio_context_id);
+}
+
+void AudioContextManagerImpl::AudioContextAudiblePlaybackStopped(
+ int32_t audio_context_id) {
+ // Notify observers that audible audio stopped playing from a WebAudio
+ // AudioContext.
+ render_frame_host_impl_->AudioContextPlaybackStopped(audio_context_id);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/webaudio/audio_context_manager_impl.h b/chromium/content/browser/media/webaudio/audio_context_manager_impl.h
new file mode 100644
index 00000000000..06d1c6b4220
--- /dev/null
+++ b/chromium/content/browser/media/webaudio/audio_context_manager_impl.h
@@ -0,0 +1,44 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_MEDIA_WEBAUDIO_AUDIO_CONTEXT_MANAGER_IMPL_H_
+#define CONTENT_BROWSER_MEDIA_WEBAUDIO_AUDIO_CONTEXT_MANAGER_IMPL_H_
+
+#include "content/common/content_export.h"
+#include "content/public/browser/frame_service_base.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "third_party/blink/public/mojom/webaudio/audio_context_manager.mojom.h"
+
+namespace content {
+
+class RenderFrameHost;
+class RenderFrameHostImpl;
+
+// Implements the mojo interface between WebAudio and the browser so that
+// WebAudio can report when audible sounds from an AudioContext starts and
+// stops.
+class CONTENT_EXPORT AudioContextManagerImpl final
+ : public content::FrameServiceBase<blink::mojom::AudioContextManager> {
+ public:
+ explicit AudioContextManagerImpl(
+ RenderFrameHost* render_frame_host,
+ blink::mojom::AudioContextManagerRequest request);
+ ~AudioContextManagerImpl() override;
+
+ static void Create(RenderFrameHost* render_frame_host,
+ blink::mojom::AudioContextManagerRequest request);
+
+ // Called when AudioContext starts or stops playing audible audio.
+ void AudioContextAudiblePlaybackStarted(int32_t audio_context_id) final;
+ void AudioContextAudiblePlaybackStopped(int32_t audio_context_id) final;
+
+ private:
+ RenderFrameHostImpl* const render_frame_host_impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(AudioContextManagerImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_WEBAUDIO_AUDIO_CONTEXT_MANAGER_IMPL_H_
diff --git a/chromium/content/browser/net/quota_policy_cookie_store.cc b/chromium/content/browser/net/quota_policy_cookie_store.cc
index 116ce029657..ecf284fd0d9 100644
--- a/chromium/content/browser/net/quota_policy_cookie_store.cc
+++ b/chromium/content/browser/net/quota_policy_cookie_store.cc
@@ -13,7 +13,7 @@
#include "base/files/file_util.h"
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/cookie_store_factory.h"
#include "net/cookies/canonical_cookie.h"
@@ -67,12 +67,14 @@ CookieStoreConfig::~CookieStoreConfig() {
}
std::unique_ptr<net::CookieStore> CreateCookieStore(
- const CookieStoreConfig& config) {
+ const CookieStoreConfig& config,
+ net::NetLog* net_log) {
std::unique_ptr<net::CookieMonster> cookie_monster;
if (config.path.empty()) {
// Empty path means in-memory store.
- cookie_monster.reset(new net::CookieMonster(nullptr));
+ cookie_monster = std::make_unique<net::CookieMonster>(
+ nullptr /* store */, nullptr /* channel_id_service */, net_log);
} else {
scoped_refptr<base::SequencedTaskRunner> client_task_runner =
config.client_task_runner;
@@ -86,7 +88,7 @@ std::unique_ptr<net::CookieStore> CreateCookieStore(
if (!background_task_runner.get()) {
background_task_runner = base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::BACKGROUND,
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
}
@@ -100,8 +102,8 @@ std::unique_ptr<net::CookieStore> CreateCookieStore(
sqlite_store.get(),
config.storage_policy.get());
- cookie_monster.reset(new net::CookieMonster(persistent_store,
- config.channel_id_service));
+ cookie_monster = std::make_unique<net::CookieMonster>(
+ persistent_store, config.channel_id_service, net_log);
if (config.persist_session_cookies)
cookie_monster->SetPersistSessionCookies(true);
}
diff --git a/chromium/content/browser/net/quota_policy_cookie_store_unittest.cc b/chromium/content/browser/net/quota_policy_cookie_store_unittest.cc
index 2185402e450..e5189b1d7c9 100644
--- a/chromium/content/browser/net/quota_policy_cookie_store_unittest.cc
+++ b/chromium/content/browser/net/quota_policy_cookie_store_unittest.cc
@@ -10,11 +10,12 @@
#include "base/run_loop.h"
#include "base/sequenced_task_runner.h"
#include "base/synchronization/waitable_event.h"
-#include "base/task_scheduler/post_task.h"
-#include "base/task_scheduler/task_scheduler.h"
+#include "base/task/post_task.h"
+#include "base/task/task_scheduler/task_scheduler.h"
#include "base/time/time.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "net/cookies/cookie_util.h"
+#include "net/log/net_log_with_source.h"
#include "net/ssl/ssl_client_cert_type.h"
#include "net/test/cert_test_util.h"
#include "net/test/test_data_directory.h"
@@ -50,7 +51,8 @@ class QuotaPolicyCookieStoreTest : public testing::Test {
void Load(CanonicalCookieVector* cookies) {
EXPECT_FALSE(loaded_event_.IsSignaled());
store_->Load(base::Bind(&QuotaPolicyCookieStoreTest::OnLoaded,
- base::Unretained(this)));
+ base::Unretained(this)),
+ net::NetLogWithSource());
loaded_event_.Wait();
cookies->swap(cookies_);
}
diff --git a/chromium/content/browser/net/reporting_service_proxy.cc b/chromium/content/browser/net/reporting_service_proxy.cc
index 6f525514216..d207fa45341 100644
--- a/chromium/content/browser/net/reporting_service_proxy.cc
+++ b/chromium/content/browser/net/reporting_service_proxy.cc
@@ -105,6 +105,25 @@ class ReportingServiceProxyImpl : public blink::mojom::ReportingServiceProxy {
QueueReport(url, group, "csp", std::move(body));
}
+ void QueueFeaturePolicyViolationReport(
+ const GURL& url,
+ const std::string& policy,
+ const std::string& message,
+ const base::Optional<std::string>& source_file,
+ int line_number,
+ int column_number) override {
+ auto body = std::make_unique<base::DictionaryValue>();
+ body->SetString("policy", policy);
+ body->SetString("message", message);
+ if (source_file)
+ body->SetString("sourceFile", *source_file);
+ if (line_number)
+ body->SetInteger("lineNumber", line_number);
+ if (column_number)
+ body->SetInteger("columnNumber", column_number);
+ QueueReport(url, "default", "feature-policy", std::move(body));
+ }
+
private:
void QueueReport(const GURL& url,
const std::string& group,
diff --git a/chromium/content/browser/network_service_browsertest.cc b/chromium/content/browser/network_service_browsertest.cc
index e8e70eb852f..25c031a14ea 100644
--- a/chromium/content/browser/network_service_browsertest.cc
+++ b/chromium/content/browser/network_service_browsertest.cc
@@ -126,20 +126,19 @@ class NetworkServiceBrowserTest : public ContentBrowserTest {
bool FetchResource(const GURL& url) {
if (!url.is_valid())
return false;
- std::string script(
+ std::string script = JsReplace(
"var xhr = new XMLHttpRequest();"
- "xhr.open('GET', '");
- script += url.spec() +
- "', true);"
- "xhr.onload = function (e) {"
- " if (xhr.readyState === 4) {"
- " window.domAutomationController.send(xhr.status === 200);"
- " }"
- "};"
- "xhr.onerror = function () {"
- " window.domAutomationController.send(false);"
- "};"
- "xhr.send(null)";
+ "xhr.open('GET', $1, true);"
+ "xhr.onload = function (e) {"
+ " if (xhr.readyState === 4) {"
+ " window.domAutomationController.send(xhr.status === 200);"
+ " }"
+ "};"
+ "xhr.onerror = function () {"
+ " window.domAutomationController.send(false);"
+ "};"
+ "xhr.send(null);",
+ url);
return ExecuteScript(script);
}
diff --git a/chromium/content/browser/network_service_client.cc b/chromium/content/browser/network_service_client.cc
index afeafe636a5..81a0655e94e 100644
--- a/chromium/content/browser/network_service_client.cc
+++ b/chromium/content/browser/network_service_client.cc
@@ -5,7 +5,8 @@
#include "content/browser/network_service_client.h"
#include "base/optional.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
+#include "content/browser/browsing_data/clear_site_data_handler.h"
#include "content/browser/devtools/devtools_url_loader_interceptor.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/ssl/ssl_client_auth_handler.h"
@@ -425,4 +426,51 @@ void NetworkServiceClient::OnCookieChange(int process_id,
process_id, routing_id, url, first_party_url, cookie, blocked_by_policy);
}
+void NetworkServiceClient::OnLoadingStateUpdate(
+ std::vector<network::mojom::LoadInfoPtr> infos,
+ OnLoadingStateUpdateCallback callback) {
+ auto rdh_infos = std::make_unique<ResourceDispatcherHostImpl::LoadInfoList>();
+
+ // TODO(jam): once ResourceDispatcherHost is gone remove the translation
+ // (other than adding the WebContents callback).
+ for (auto& info : infos) {
+ ResourceDispatcherHostImpl::LoadInfo load_info;
+ load_info.host = std::move(info->host);
+ load_info.load_state.state = static_cast<net::LoadState>(info->load_state);
+ load_info.load_state.param = std::move(info->state_param);
+ load_info.upload_position = info->upload_position;
+ load_info.upload_size = info->upload_size;
+ load_info.web_contents_getter =
+ info->process_id
+ ? base::BindRepeating(WebContentsImpl::FromRenderFrameHostID,
+ info->process_id, info->routing_id)
+ : base::BindRepeating(WebContents::FromFrameTreeNodeId,
+ info->routing_id);
+ rdh_infos->push_back(std::move(load_info));
+ }
+
+ auto* rdh = ResourceDispatcherHostImpl::Get();
+ ResourceDispatcherHostImpl::UpdateLoadStateOnUI(rdh->loader_delegate_,
+ std::move(rdh_infos));
+
+ std::move(callback).Run();
+}
+
+void NetworkServiceClient::OnClearSiteData(int process_id,
+ int routing_id,
+ const GURL& url,
+ const std::string& header_value,
+ int load_flags,
+ OnClearSiteDataCallback callback) {
+ base::RepeatingCallback<WebContents*(void)> web_contents_getter =
+ process_id
+ ? base::BindRepeating(WebContentsImpl::FromRenderFrameHostID,
+ process_id, routing_id)
+ : base::BindRepeating(WebContents::FromFrameTreeNodeId, routing_id);
+
+ ClearSiteDataHandler::HandleHeader(std::move(web_contents_getter), url,
+ header_value, load_flags,
+ std::move(callback));
+}
+
} // namespace content
diff --git a/chromium/content/browser/network_service_client.h b/chromium/content/browser/network_service_client.h
index 68c0af0a499..1c0edbed8db 100644
--- a/chromium/content/browser/network_service_client.h
+++ b/chromium/content/browser/network_service_client.h
@@ -63,6 +63,14 @@ class CONTENT_EXPORT NetworkServiceClient
const GURL& first_party_url,
const net::CanonicalCookie& cookie,
bool blocked_by_policy) override;
+ void OnLoadingStateUpdate(std::vector<network::mojom::LoadInfoPtr> infos,
+ OnLoadingStateUpdateCallback callback) override;
+ void OnClearSiteData(int process_id,
+ int routing_id,
+ const GURL& url,
+ const std::string& header_value,
+ int load_flags,
+ OnClearSiteDataCallback callback) override;
private:
mojo::Binding<network::mojom::NetworkServiceClient> binding_;
diff --git a/chromium/content/browser/network_service_instance.cc b/chromium/content/browser/network_service_instance.cc
index 374ac6da02d..905301ab321 100644
--- a/chromium/content/browser/network_service_instance.cc
+++ b/chromium/content/browser/network_service_instance.cc
@@ -10,8 +10,12 @@
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/service_manager_connection.h"
#include "content/public/common/service_names.mojom.h"
+#include "net/log/net_log_util.h"
#include "services/network/network_service.h"
#include "services/network/public/cpp/features.h"
+#include "services/network/public/cpp/network_connection_tracker.h"
+#include "services/network/public/cpp/network_switches.h"
+#include "services/network/public/mojom/network_change_manager.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
namespace content {
@@ -19,6 +23,7 @@ namespace content {
namespace {
network::mojom::NetworkServicePtr* g_network_service_ptr = nullptr;
+network::NetworkConnectionTracker* g_network_connection_tracker;
network::NetworkService* g_network_service;
void CreateNetworkServiceOnIO(network::mojom::NetworkServiceRequest request) {
@@ -33,19 +38,32 @@ void CreateNetworkServiceOnIO(network::mojom::NetworkServiceRequest request) {
nullptr, std::move(request), GetContentClient()->browser()->GetNetLog());
}
+void BindNetworkChangeManagerRequest(
+ network::mojom::NetworkChangeManagerRequest request) {
+ GetNetworkService()->GetNetworkChangeManager(std::move(request));
+}
+
} // namespace
network::mojom::NetworkService* GetNetworkService() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ service_manager::Connector* connector =
+ base::FeatureList::IsEnabled(network::features::kNetworkService)
+ ? ServiceManagerConnection::GetForProcess()->GetConnector()
+ : nullptr;
+ return GetNetworkServiceFromConnector(connector);
+}
+CONTENT_EXPORT network::mojom::NetworkService* GetNetworkServiceFromConnector(
+ service_manager::Connector* connector) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!g_network_service_ptr)
g_network_service_ptr = new network::mojom::NetworkServicePtr;
static NetworkServiceClient* g_client;
if (!g_network_service_ptr->is_bound() ||
g_network_service_ptr->encountered_error()) {
if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
- ServiceManagerConnection::GetForProcess()->GetConnector()->BindInterface(
- mojom::kNetworkServiceName, g_network_service_ptr);
+ connector->BindInterface(mojom::kNetworkServiceName,
+ g_network_service_ptr);
} else {
DCHECK(!g_network_service_ptr->is_bound());
BrowserThread::PostTask(
@@ -59,6 +77,25 @@ network::mojom::NetworkService* GetNetworkService() {
g_client = new NetworkServiceClient(mojo::MakeRequest(&client_ptr));
(*g_network_service_ptr)->SetClient(std::move(client_ptr));
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(network::switches::kLogNetLog)) {
+ base::FilePath log_path =
+ command_line->GetSwitchValuePath(network::switches::kLogNetLog);
+
+ base::DictionaryValue client_constants =
+ GetContentClient()->GetNetLogConstants();
+
+ base::File file(
+ log_path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+ LOG_IF(ERROR, !file.IsValid())
+ << "Failed opening: " << log_path.value();
+ (*g_network_service_ptr)
+ ->StartNetLog(std::move(file), std::move(client_constants));
+ }
+ }
+
GetContentClient()->browser()->OnNetworkServiceCreated(
g_network_service_ptr->get());
}
@@ -83,4 +120,18 @@ void FlushNetworkServiceInstanceForTesting() {
g_network_service_ptr->FlushForTesting();
}
+network::NetworkConnectionTracker* GetNetworkConnectionTracker() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!g_network_connection_tracker) {
+ g_network_connection_tracker = new network::NetworkConnectionTracker(
+ base::BindRepeating(&BindNetworkChangeManagerRequest));
+ }
+ return g_network_connection_tracker;
+}
+
+void SetNetworkConnectionTrackerForTesting(
+ network::NetworkConnectionTracker* network_connection_tracker) {
+ g_network_connection_tracker = network_connection_tracker;
+}
+
} // namespace content
diff --git a/chromium/content/browser/network_service_restart_browsertest.cc b/chromium/content/browser/network_service_restart_browsertest.cc
index 96551970a99..a868b80d5c5 100644
--- a/chromium/content/browser/network_service_restart_browsertest.cc
+++ b/chromium/content/browser/network_service_restart_browsertest.cc
@@ -2,17 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/test/bind_test_util.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_timeouts.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/frame_host/render_frame_message_filter.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/storage_partition_impl.h"
#include "content/browser/url_loader_factory_getter.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/network_service_instance.h"
-#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h"
@@ -665,4 +667,42 @@ IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest,
EXPECT_FALSE(CheckContainsProcessID(network_usages, process_id2));
}
+// Make sure cookie access doesn't hang or fail after a network process crash.
+IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest, Cookies) {
+ auto* web_contents = shell()->web_contents();
+ NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
+ EXPECT_TRUE(ExecuteScript(web_contents, "document.cookie = 'foo=bar';"));
+
+ std::string cookie;
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ web_contents, "window.domAutomationController.send(document.cookie);",
+ &cookie));
+ EXPECT_EQ("foo=bar", cookie);
+
+ SimulateNetworkServiceCrash();
+
+ auto* process = web_contents->GetMainFrame()->GetProcess();
+ scoped_refptr<RenderFrameMessageFilter> filter(
+ static_cast<RenderProcessHostImpl*>(process)
+ ->render_frame_message_filter_for_testing());
+ // Need to use FlushAsyncForTesting instead of FlushForTesting because the IO
+ // thread doesn't support nested message loops.
+ base::RunLoop run_loop;
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::BindLambdaForTesting([&]() {
+ filter->GetCookieManager()->FlushAsyncForTesting(
+ run_loop.QuitClosure());
+ }));
+
+ // content_shell uses in-memory cookie database, so the value saved earlier
+ // won't persist across crashes. What matters is that new access works.
+ EXPECT_TRUE(ExecuteScript(web_contents, "document.cookie = 'foo=bar';"));
+
+ // This will hang without the fix.
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ web_contents, "window.domAutomationController.send(document.cookie);",
+ &cookie));
+ EXPECT_EQ("foo=bar", cookie);
+}
+
} // namespace content
diff --git a/chromium/content/browser/notification_service_impl.h b/chromium/content/browser/notification_service_impl.h
index bd04f74cbe0..e74801f3cc1 100644
--- a/chromium/content/browser/notification_service_impl.h
+++ b/chromium/content/browser/notification_service_impl.h
@@ -34,7 +34,8 @@ class CONTENT_EXPORT NotificationServiceImpl : public NotificationService {
private:
friend class NotificationRegistrar;
- typedef base::ObserverList<NotificationObserver> NotificationObserverList;
+ typedef base::ObserverList<NotificationObserver>::Unchecked
+ NotificationObserverList;
typedef std::map<uintptr_t, NotificationObserverList*> NotificationSourceMap;
typedef std::map<int, NotificationSourceMap> NotificationObserverMap;
typedef std::map<int, int> NotificationObserverCount;
diff --git a/chromium/content/browser/notifications/OWNERS b/chromium/content/browser/notifications/OWNERS
index c172d4bfa29..0d5ed95cb0a 100644
--- a/chromium/content/browser/notifications/OWNERS
+++ b/chromium/content/browser/notifications/OWNERS
@@ -4,7 +4,6 @@
# //content/renderer/notifications/
# //content/test/mock_platform_notification_service.*
-awdf@chromium.org
mkwst@chromium.org
peter@chromium.org
diff --git a/chromium/content/browser/notifications/blink_notification_service_impl.cc b/chromium/content/browser/notifications/blink_notification_service_impl.cc
index cbcd2b5369f..73c5d6b436e 100644
--- a/chromium/content/browser/notifications/blink_notification_service_impl.cc
+++ b/chromium/content/browser/notifications/blink_notification_service_impl.cc
@@ -171,7 +171,8 @@ void BlinkNotificationServiceImpl::DisplayPersistentNotificationOnIOThread(
DisplayPersistentNotificationCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- // TODO(awdf): Necessary to validate resources here?
+ // TODO(https://crbug.com/870258): Validate resources are not too big (either
+ // here or in the mojo struct traits).
NotificationDatabaseData database_data;
database_data.origin = origin_.GetURL();
@@ -179,7 +180,8 @@ void BlinkNotificationServiceImpl::DisplayPersistentNotificationOnIOThread(
database_data.notification_data = platform_notification_data;
notification_context_->WriteNotificationData(
- next_persistent_notification_id, origin_.GetURL(), database_data,
+ next_persistent_notification_id, service_worker_registration_id,
+ origin_.GetURL(), database_data,
base::AdaptCallbackForRepeating(base::BindOnce(
&BlinkNotificationServiceImpl::
DisplayPersistentNotificationWithIdOnIOThread,
diff --git a/chromium/content/browser/notifications/notification_database.cc b/chromium/content/browser/notifications/notification_database.cc
index 28ff2f47881..bc54e5a090f 100644
--- a/chromium/content/browser/notifications/notification_database.cc
+++ b/chromium/content/browser/notifications/notification_database.cc
@@ -98,7 +98,7 @@ NotificationDatabase::Status DeserializedNotificationData(
// Updates the time of the last click on the notification, and the first if
// necessary.
-void UpdateNotificationClickTimestamps(NotificationDatabaseData* data) {
+void UpdateNotificationTimestamps(NotificationDatabaseData* data) {
base::TimeDelta delta = base::Time::Now() - data->creation_time_millis;
if (!data->time_until_first_click_millis.has_value())
data->time_until_first_click_millis = delta;
@@ -107,8 +107,9 @@ void UpdateNotificationClickTimestamps(NotificationDatabaseData* data) {
} // namespace
-NotificationDatabase::NotificationDatabase(const base::FilePath& path)
- : path_(path) {}
+NotificationDatabase::NotificationDatabase(const base::FilePath& path,
+ UkmCallback callback)
+ : path_(path), record_notification_to_ukm_callback_(std::move(callback)) {}
NotificationDatabase::~NotificationDatabase() {
DCHECK(sequence_checker_.CalledOnValidSequence());
@@ -182,18 +183,20 @@ NotificationDatabase::ReadNotificationDataAndRecordInteraction(
// Update the appropriate fields for UKM logging purposes.
switch (interaction) {
case PlatformNotificationContext::Interaction::CLOSED:
+ notification_database_data->closed_reason =
+ NotificationDatabaseData::ClosedReason::USER;
notification_database_data->time_until_close_millis =
base::Time::Now() - notification_database_data->creation_time_millis;
break;
case PlatformNotificationContext::Interaction::NONE:
- return status;
+ break;
case PlatformNotificationContext::Interaction::ACTION_BUTTON_CLICKED:
notification_database_data->num_action_button_clicks += 1;
- UpdateNotificationClickTimestamps(notification_database_data);
+ UpdateNotificationTimestamps(notification_database_data);
break;
case PlatformNotificationContext::Interaction::CLICKED:
notification_database_data->num_clicks += 1;
- UpdateNotificationClickTimestamps(notification_database_data);
+ UpdateNotificationTimestamps(notification_database_data);
break;
}
@@ -262,6 +265,13 @@ NotificationDatabase::Status NotificationDatabase::DeleteNotificationData(
DCHECK(!notification_id.empty());
DCHECK(origin.is_valid());
+ NotificationDatabaseData data;
+ Status status = ReadNotificationData(notification_id, origin, &data);
+ if (status == STATUS_OK && record_notification_to_ukm_callback_) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(record_notification_to_ukm_callback_, data));
+ }
std::string key = CreateDataKey(origin, notification_id);
return LevelDBStatusToNotificationDatabaseStatus(
db_->Delete(leveldb::WriteOptions(), key));
@@ -381,6 +391,13 @@ NotificationDatabase::DeleteAllNotificationDataInternal(
continue;
}
+ if (record_notification_to_ukm_callback_) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(record_notification_to_ukm_callback_,
+ notification_database_data));
+ }
+
batch.Delete(iter->key());
DCHECK(!notification_database_data.notification_id.empty());
diff --git a/chromium/content/browser/notifications/notification_database.h b/chromium/content/browser/notifications/notification_database.h
index 5237a8e323c..6ed4658d998 100644
--- a/chromium/content/browser/notifications/notification_database.h
+++ b/chromium/content/browser/notifications/notification_database.h
@@ -14,8 +14,8 @@
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/sequence_checker.h"
-#include "content/browser/notifications/platform_notification_context_impl.h"
#include "content/common/content_export.h"
+#include "content/public/browser/platform_notification_context.h"
class GURL;
@@ -23,7 +23,7 @@ namespace leveldb {
class DB;
class Env;
class FilterPolicy;
-}
+} // namespace leveldb
namespace content {
@@ -40,6 +40,9 @@ struct NotificationDatabaseData;
// file I/O. The same thread or task runner must be used for all method calls.
class CONTENT_EXPORT NotificationDatabase {
public:
+ using UkmCallback =
+ base::RepeatingCallback<void(const NotificationDatabaseData&)>;
+
// Result status codes for interations with the database. Will be used for
// UMA, so the assigned ids must remain stable.
enum Status {
@@ -69,7 +72,8 @@ class CONTENT_EXPORT NotificationDatabase {
STATUS_COUNT = 7
};
- explicit NotificationDatabase(const base::FilePath& path);
+ NotificationDatabase(const base::FilePath& path, UkmCallback callback);
+
~NotificationDatabase();
// Opens the database. If |path| is non-empty, it will be created on the given
@@ -212,6 +216,9 @@ class CONTENT_EXPORT NotificationDatabase {
base::SequenceChecker sequence_checker_;
+ // Callback to use for recording UKM metrics. Must be posted to the UI thread.
+ UkmCallback record_notification_to_ukm_callback_;
+
DISALLOW_COPY_AND_ASSIGN(NotificationDatabase);
};
diff --git a/chromium/content/browser/notifications/notification_database_data_conversions.cc b/chromium/content/browser/notifications/notification_database_data_conversions.cc
index 656108caa62..904963094eb 100644
--- a/chromium/content/browser/notifications/notification_database_data_conversions.cc
+++ b/chromium/content/browser/notifications/notification_database_data_conversions.cc
@@ -34,12 +34,19 @@ bool DeserializeNotificationDatabaseData(const std::string& input,
output->num_action_button_clicks = message.num_action_button_clicks();
output->creation_time_millis = base::Time::FromDeltaSinceWindowsEpoch(
base::TimeDelta::FromMicroseconds(message.creation_time_millis()));
- output->time_until_first_click_millis = base::TimeDelta::FromMilliseconds(
- message.time_until_first_click_millis());
- output->time_until_last_click_millis =
- base::TimeDelta::FromMilliseconds(message.time_until_last_click_millis());
- output->time_until_close_millis =
- base::TimeDelta::FromMilliseconds(message.time_until_close_millis());
+
+ if (message.has_time_until_close_millis()) {
+ output->time_until_close_millis =
+ base::TimeDelta::FromMilliseconds(message.time_until_close_millis());
+ }
+ if (message.has_time_until_first_click_millis()) {
+ output->time_until_first_click_millis = base::TimeDelta::FromMilliseconds(
+ message.time_until_first_click_millis());
+ }
+ if (message.has_time_until_last_click_millis()) {
+ output->time_until_last_click_millis = base::TimeDelta::FromMilliseconds(
+ message.time_until_last_click_millis());
+ }
switch (message.closed_reason()) {
case NotificationDatabaseDataProto::USER:
diff --git a/chromium/content/browser/notifications/notification_database_unittest.cc b/chromium/content/browser/notifications/notification_database_unittest.cc
index f6fdef1f358..fb0d6cb80fe 100644
--- a/chromium/content/browser/notifications/notification_database_unittest.cc
+++ b/chromium/content/browser/notifications/notification_database_unittest.cc
@@ -14,6 +14,7 @@
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/notification_database_data.h"
#include "content/public/common/platform_notification_data.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/leveldatabase/src/include/leveldb/db.h"
#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
@@ -39,15 +40,19 @@ const struct {
{"https://chrome.com", "foo" /* tag */, 0}};
class NotificationDatabaseTest : public ::testing::Test {
+ public:
+ NotificationDatabaseTest()
+ : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
+
protected:
// Creates a new NotificationDatabase instance in memory.
NotificationDatabase* CreateDatabaseInMemory() {
- return new NotificationDatabase(base::FilePath());
+ return new NotificationDatabase(base::FilePath(), callback());
}
// Creates a new NotificationDatabase instance in |path|.
NotificationDatabase* CreateDatabaseOnFileSystem(const base::FilePath& path) {
- return new NotificationDatabase(path);
+ return new NotificationDatabase(path, callback());
}
// Creates a new notification for |service_worker_registration_id| belonging
@@ -108,6 +113,12 @@ class NotificationDatabaseTest : public ::testing::Test {
// Generates a random notification ID. The format of the ID is opaque.
std::string GenerateNotificationId() { return base::GenerateGUID(); }
+
+ NotificationDatabase::UkmCallback callback() { return callback_; }
+
+ TestBrowserThreadBundle thread_bundle_; // Must be first member.
+
+ NotificationDatabase::UkmCallback callback_;
};
TEST_F(NotificationDatabaseTest, OpenCloseMemory) {
diff --git a/chromium/content/browser/notifications/notification_event_dispatcher_impl.cc b/chromium/content/browser/notifications/notification_event_dispatcher_impl.cc
index 879ab76c96d..d8acb3229bf 100644
--- a/chromium/content/browser/notifications/notification_event_dispatcher_impl.cc
+++ b/chromium/content/browser/notifications/notification_event_dispatcher_impl.cc
@@ -13,11 +13,11 @@
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_storage.h"
-#include "content/common/platform_notification_param_traits.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/storage_partition.h"
+#include "content/public/common/persistent_notification_status.h"
#include "content/public/common/platform_notification_data.h"
namespace content {
@@ -58,13 +58,13 @@ void ServiceWorkerNotificationEventFinished(
<< blink::ServiceWorkerStatusToString(service_worker_status);
#endif
- PersistentNotificationStatus status = PERSISTENT_NOTIFICATION_STATUS_SUCCESS;
+ PersistentNotificationStatus status = PersistentNotificationStatus::kSuccess;
switch (service_worker_status) {
case blink::ServiceWorkerStatusCode::kOk:
// Success status was initialized above.
break;
case blink::ServiceWorkerStatusCode::kErrorEventWaitUntilRejected:
- status = PERSISTENT_NOTIFICATION_STATUS_EVENT_WAITUNTIL_REJECTED;
+ status = PersistentNotificationStatus::kWaitUntilRejected;
break;
case blink::ServiceWorkerStatusCode::kErrorFailed:
case blink::ServiceWorkerStatusCode::kErrorAbort:
@@ -83,7 +83,8 @@ void ServiceWorkerNotificationEventFinished(
case blink::ServiceWorkerStatusCode::kErrorDiskCache:
case blink::ServiceWorkerStatusCode::kErrorRedundant:
case blink::ServiceWorkerStatusCode::kErrorDisallowed:
- status = PERSISTENT_NOTIFICATION_STATUS_SERVICE_WORKER_ERROR;
+ case blink::ServiceWorkerStatusCode::kErrorInvalidArguments:
+ status = PersistentNotificationStatus::kServiceWorkerError;
break;
}
NotificationEventFinished(dispatch_complete_callback, status);
@@ -115,10 +116,10 @@ void DispatchNotificationEventOnRegistration(
return;
}
- PersistentNotificationStatus status = PERSISTENT_NOTIFICATION_STATUS_SUCCESS;
+ PersistentNotificationStatus status = PersistentNotificationStatus::kSuccess;
switch (service_worker_status) {
case blink::ServiceWorkerStatusCode::kErrorNotFound:
- status = PERSISTENT_NOTIFICATION_STATUS_NO_SERVICE_WORKER;
+ status = PersistentNotificationStatus::kServiceWorkerMissing;
break;
case blink::ServiceWorkerStatusCode::kErrorFailed:
case blink::ServiceWorkerStatusCode::kErrorAbort:
@@ -137,7 +138,8 @@ void DispatchNotificationEventOnRegistration(
case blink::ServiceWorkerStatusCode::kErrorDiskCache:
case blink::ServiceWorkerStatusCode::kErrorRedundant:
case blink::ServiceWorkerStatusCode::kErrorDisallowed:
- status = PERSISTENT_NOTIFICATION_STATUS_SERVICE_WORKER_ERROR;
+ case blink::ServiceWorkerStatusCode::kErrorInvalidArguments:
+ status = PersistentNotificationStatus::kServiceWorkerError;
break;
case blink::ServiceWorkerStatusCode::kOk:
NOTREACHED();
@@ -170,7 +172,7 @@ void FindServiceWorkerRegistration(
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::BindOnce(dispatch_error_callback,
- PERSISTENT_NOTIFICATION_STATUS_DATABASE_ERROR));
+ PersistentNotificationStatus::kDatabaseError));
return;
}
@@ -260,10 +262,10 @@ void OnPersistentNotificationDataDeleted(
service_worker_status);
return;
}
- NotificationEventFinished(
- dispatch_complete_callback,
- success ? PERSISTENT_NOTIFICATION_STATUS_SUCCESS
- : PERSISTENT_NOTIFICATION_STATUS_DATABASE_ERROR);
+ NotificationEventFinished(dispatch_complete_callback,
+ success
+ ? PersistentNotificationStatus::kSuccess
+ : PersistentNotificationStatus::kDatabaseError);
}
// Called when the persistent notification close event has been handled
diff --git a/chromium/content/browser/notifications/notification_storage.cc b/chromium/content/browser/notifications/notification_storage.cc
new file mode 100644
index 00000000000..8c6053999e7
--- /dev/null
+++ b/chromium/content/browser/notifications/notification_storage.cc
@@ -0,0 +1,153 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/notifications/notification_storage.h"
+
+#include "base/metrics/histogram_macros.h"
+#include "base/time/time.h"
+#include "content/browser/notifications/notification_database_data_conversions.h"
+
+namespace content {
+
+namespace {
+
+// Schema is as follows:
+// KEY: NOTIFICATION_<|data.notification_id|>
+// VALUE: <serialized content::proto::NotificationDatabaseData>
+
+const char kNotificationPrefix[] = "NOTIFICATION_";
+
+// Create the key that will be used for the service worker database.
+std::string CreateDataKey(const std::string& notification_id) {
+ DCHECK(!notification_id.empty());
+ return kNotificationPrefix + notification_id;
+}
+
+// Updates the time of the last click on the notification, and the first if
+// necessary.
+void UpdateNotificationClickTimestamps(NotificationDatabaseData* data) {
+ base::TimeDelta delta = base::Time::Now() - data->creation_time_millis;
+ if (!data->time_until_first_click_millis.has_value())
+ data->time_until_first_click_millis = delta;
+ data->time_until_last_click_millis = delta;
+}
+
+} // namespace
+
+NotificationStorage::NotificationStorage(
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context)
+ : service_worker_context_(std::move(service_worker_context)),
+ weak_ptr_factory_(this) {}
+
+NotificationStorage::~NotificationStorage() = default;
+
+void NotificationStorage::WriteNotificationData(
+ const NotificationDatabaseData& data,
+ const PlatformNotificationContext::WriteResultCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ std::string serialized_data;
+ if (!SerializeNotificationDatabaseData(data, &serialized_data)) {
+ DLOG(ERROR) << "Unable to serialize data for a notification belonging "
+ << "to: " << data.origin;
+ callback.Run(/* success= */ false, std::string());
+ return;
+ }
+
+ service_worker_context_->StoreRegistrationUserData(
+ data.service_worker_registration_id, data.origin,
+ {{CreateDataKey(data.notification_id), std::move(serialized_data)}},
+ base::BindOnce(&NotificationStorage::OnWriteComplete,
+ weak_ptr_factory_.GetWeakPtr(), data, callback));
+}
+
+void NotificationStorage::OnWriteComplete(
+ const NotificationDatabaseData& data,
+ const PlatformNotificationContext::WriteResultCallback& callback,
+ blink::ServiceWorkerStatusCode status) {
+ if (status == blink::ServiceWorkerStatusCode::kOk) {
+ callback.Run(/* success= */ true, data.notification_id);
+ } else {
+ callback.Run(/* success= */ false,
+ /* notification_id= */ std::string());
+ }
+}
+
+void NotificationStorage::ReadNotificationDataAndRecordInteraction(
+ int64_t service_worker_registration_id,
+ const std::string& notification_id,
+ PlatformNotificationContext::Interaction interaction,
+ const PlatformNotificationContext::ReadResultCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ service_worker_context_->GetRegistrationUserData(
+ service_worker_registration_id, {CreateDataKey(notification_id)},
+ base::BindOnce(&NotificationStorage::OnReadCompleteUpdateInteraction,
+ weak_ptr_factory_.GetWeakPtr(),
+ service_worker_registration_id, interaction, callback));
+}
+
+void NotificationStorage::OnReadCompleteUpdateInteraction(
+ int64_t service_worker_registration_id,
+ PlatformNotificationContext::Interaction interaction,
+ const PlatformNotificationContext::ReadResultCallback& callback,
+ const std::vector<std::string>& database_data,
+ blink::ServiceWorkerStatusCode status) {
+ if (status != blink::ServiceWorkerStatusCode::kOk || database_data.empty()) {
+ callback.Run(/* success= */ false, NotificationDatabaseData());
+ return;
+ }
+
+ auto data = std::make_unique<NotificationDatabaseData>();
+ if (!DeserializeNotificationDatabaseData(database_data[0], data.get())) {
+ DLOG(ERROR) << "Unable to deserialize data for a notification belonging "
+ << "to: " << data->origin;
+ callback.Run(/* success= */ false, NotificationDatabaseData());
+ return;
+ }
+
+ switch (interaction) {
+ case PlatformNotificationContext::Interaction::CLOSED:
+ data->time_until_close_millis =
+ base::Time::Now() - data->creation_time_millis;
+ break;
+ case PlatformNotificationContext::Interaction::NONE:
+ break;
+ case PlatformNotificationContext::Interaction::ACTION_BUTTON_CLICKED:
+ data->num_action_button_clicks += 1;
+ UpdateNotificationClickTimestamps(data.get());
+ break;
+ case PlatformNotificationContext::Interaction::CLICKED:
+ data->num_clicks += 1;
+ UpdateNotificationClickTimestamps(data.get());
+ break;
+ }
+ std::string serialized_data;
+ if (!SerializeNotificationDatabaseData(*data, &serialized_data)) {
+ DLOG(ERROR) << "Unable to serialize data for a notification belonging "
+ << "to: " << data->origin;
+ callback.Run(/* success= */ false, NotificationDatabaseData());
+ return;
+ }
+
+ GURL origin = data->origin;
+ std::string notification_id = data->notification_id;
+ service_worker_context_->StoreRegistrationUserData(
+ service_worker_registration_id, origin,
+ {{CreateDataKey(notification_id), std::move(serialized_data)}},
+ base::BindOnce(&NotificationStorage::OnInteractionUpdateComplete,
+ weak_ptr_factory_.GetWeakPtr(), std::move(data),
+ callback));
+}
+
+void NotificationStorage::OnInteractionUpdateComplete(
+ std::unique_ptr<NotificationDatabaseData> data,
+ const PlatformNotificationContext::ReadResultCallback& callback,
+ blink::ServiceWorkerStatusCode status) {
+ DCHECK(data);
+ if (status == blink::ServiceWorkerStatusCode::kOk)
+ callback.Run(/* success= */ true, *data);
+ else
+ callback.Run(/* success= */ false, NotificationDatabaseData());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/notifications/notification_storage.h b/chromium/content/browser/notifications/notification_storage.h
new file mode 100644
index 00000000000..1a24c48bb05
--- /dev/null
+++ b/chromium/content/browser/notifications/notification_storage.h
@@ -0,0 +1,59 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_NOTIFICATIONS_NOTIFICATION_STORAGE_H_
+#define CONTENT_BROWSER_NOTIFICATIONS_NOTIFICATION_STORAGE_H_
+
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/public/browser/platform_notification_context.h"
+#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
+
+namespace content {
+
+// The NotificationStorage class is a wrapper around persistent storage, the
+// Service Worker database, exposing APIs for read and write queries relating to
+// persistent notifications.
+class CONTENT_EXPORT NotificationStorage {
+ public:
+ explicit NotificationStorage(
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context);
+ ~NotificationStorage();
+
+ void WriteNotificationData(
+ const NotificationDatabaseData& data,
+ const PlatformNotificationContext::WriteResultCallback& callback);
+
+ void ReadNotificationDataAndRecordInteraction(
+ int64_t service_worker_registration_id,
+ const std::string& notification_id,
+ PlatformNotificationContext::Interaction interaction,
+ const PlatformNotificationContext::ReadResultCallback& callback);
+
+ private:
+ void OnWriteComplete(
+ const NotificationDatabaseData& data,
+ const PlatformNotificationContext::WriteResultCallback& callback,
+ blink::ServiceWorkerStatusCode status);
+
+ void OnReadCompleteUpdateInteraction(
+ int64_t service_worker_registration_id,
+ PlatformNotificationContext::Interaction interaction,
+ const PlatformNotificationContext::ReadResultCallback& callback,
+ const std::vector<std::string>& database_data,
+ blink::ServiceWorkerStatusCode status);
+
+ void OnInteractionUpdateComplete(
+ std::unique_ptr<NotificationDatabaseData> data,
+ const PlatformNotificationContext::ReadResultCallback& callback,
+ blink::ServiceWorkerStatusCode status);
+
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
+
+ base::WeakPtrFactory<NotificationStorage>
+ weak_ptr_factory_; // Must be last member.
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_NOTIFICATIONS_NOTIFICATION_STORAGE_H_
diff --git a/chromium/content/browser/notifications/notification_storage_unittest.cc b/chromium/content/browser/notifications/notification_storage_unittest.cc
new file mode 100644
index 00000000000..bb8a4e8b8e6
--- /dev/null
+++ b/chromium/content/browser/notifications/notification_storage_unittest.cc
@@ -0,0 +1,253 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/notifications/notification_storage.h"
+
+#include "base/bind.h"
+#include "base/guid.h"
+#include "base/run_loop.h"
+#include "content/browser/service_worker/embedded_worker_test_helper.h"
+#include "content/browser/service_worker/service_worker_registration.h"
+#include "content/common/service_worker/service_worker_types.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class NotificationStorageTest : public ::testing::Test {
+ public:
+ NotificationStorageTest()
+ : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
+ origin_(GURL("https://example.com")),
+ success_(false),
+ service_worker_registration_id_(
+ blink::mojom::kInvalidServiceWorkerRegistrationId) {
+ helper_ = std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath());
+ storage_ =
+ std::make_unique<NotificationStorage>(helper_->context_wrapper());
+ }
+
+ void DidRegisterServiceWorker(base::OnceClosure quit_closure,
+ blink::ServiceWorkerStatusCode status,
+ const std::string& status_message,
+ int64_t service_worker_registration_id) {
+ DCHECK(service_worker_registration_id_);
+ EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status) << status_message;
+
+ service_worker_registration_id_ = service_worker_registration_id;
+
+ std::move(quit_closure).Run();
+ }
+
+ void DidFindServiceWorkerRegistration(
+ scoped_refptr<ServiceWorkerRegistration>* out_service_worker_registration,
+ base::OnceClosure quit_closure,
+ blink::ServiceWorkerStatusCode status,
+ scoped_refptr<ServiceWorkerRegistration> service_worker_registration) {
+ DCHECK(out_service_worker_registration);
+ EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status)
+ << blink::ServiceWorkerStatusToString(status);
+
+ *out_service_worker_registration = service_worker_registration;
+
+ std::move(quit_closure).Run();
+ }
+
+ // Registers a Service Worker for the testing origin and returns its
+ // |service_worker_registration_id|. If registration failed, this will be
+ // blink::mojom::kInvalidServiceWorkerRegistrationId. The
+ // ServiceWorkerRegistration will be kept alive for the test's lifetime.
+ int64_t RegisterServiceWorker() {
+ GURL script_url = origin_;
+
+ {
+ blink::mojom::ServiceWorkerRegistrationOptions options;
+ options.scope = origin_;
+ base::RunLoop run_loop;
+ helper_->context()->RegisterServiceWorker(
+ script_url, options,
+ base::BindOnce(&NotificationStorageTest::DidRegisterServiceWorker,
+ base::Unretained(this), run_loop.QuitClosure()));
+ run_loop.Run();
+ }
+
+ if (service_worker_registration_id_ ==
+ blink::mojom::kInvalidServiceWorkerRegistrationId) {
+ ADD_FAILURE() << "Could not obtain a valid Service Worker registration";
+ return blink::mojom::kInvalidServiceWorkerRegistrationId;
+ }
+
+ scoped_refptr<ServiceWorkerRegistration> service_worker_registration;
+
+ {
+ base::RunLoop run_loop;
+ helper_->context()->storage()->FindRegistrationForId(
+ service_worker_registration_id_, origin_,
+ base::BindOnce(
+ &NotificationStorageTest::DidFindServiceWorkerRegistration,
+ base::Unretained(this), &service_worker_registration,
+ run_loop.QuitClosure()));
+ run_loop.Run();
+ }
+
+ // Wait for the worker to be activated.
+ thread_bundle_.RunUntilIdle();
+
+ if (!service_worker_registration) {
+ ADD_FAILURE() << "Could not find the new Service Worker registration.";
+ return blink::mojom::kInvalidServiceWorkerRegistrationId;
+ }
+
+ service_worker_registrations_.push_back(
+ std::move(service_worker_registration));
+
+ return service_worker_registration_id_;
+ }
+
+ void DidWriteNotificationDataSynchronous(base::OnceClosure quit_closure,
+ bool success,
+ const std::string& notification_id) {
+ success_ = success;
+ notification_id_ = notification_id;
+ std::move(quit_closure).Run();
+ }
+
+ void WriteNotificationDataSynchronous(const NotificationDatabaseData& data) {
+ base::RunLoop run_loop;
+ storage_->WriteNotificationData(
+ data, base::Bind(
+ &NotificationStorageTest::DidWriteNotificationDataSynchronous,
+ base::Unretained(this), run_loop.QuitClosure()));
+ run_loop.Run();
+ }
+
+ void DidReadNotificationDataAndRecordInteractionSynchronous(
+ base::OnceClosure quit_closure,
+ bool success,
+ const NotificationDatabaseData& data) {
+ success_ = success;
+ out_data_ = data;
+ std::move(quit_closure).Run();
+ }
+
+ NotificationDatabaseData ReadNotificationDataAndRecordInteractionSynchronous(
+ int64_t service_worker_registration_id,
+ const std::string& notification_id,
+ PlatformNotificationContext::Interaction interaction) {
+ base::RunLoop run_loop;
+ storage_->ReadNotificationDataAndRecordInteraction(
+ service_worker_registration_id, notification_id, interaction,
+ base::Bind(&NotificationStorageTest::
+ DidReadNotificationDataAndRecordInteractionSynchronous,
+ base::Unretained(this), run_loop.QuitClosure()));
+ run_loop.Run();
+ return out_data_;
+ }
+
+ // Generates a random notification ID. The format of the ID is opaque.
+ std::string GenerateNotificationId() { return base::GenerateGUID(); }
+
+ protected:
+ TestBrowserThreadBundle thread_bundle_; // Must be first member
+ std::unique_ptr<EmbeddedWorkerTestHelper> helper_;
+ GURL origin_;
+ TestBrowserContext browser_context_;
+ bool success_;
+ int64_t service_worker_registration_id_;
+ NotificationDatabaseData out_data_;
+
+ private:
+ std::unique_ptr<NotificationStorage> storage_;
+ std::string notification_id_;
+
+ // Vector of ServiceWorkerRegistration instances that have to be kept alive
+ // for the lifetime of this test.
+ std::vector<scoped_refptr<ServiceWorkerRegistration>>
+ service_worker_registrations_;
+};
+
+TEST_F(NotificationStorageTest, WriteReadNotification) {
+ NotificationDatabaseData data;
+ data.notification_id = GenerateNotificationId();
+ data.origin = origin_;
+ data.service_worker_registration_id = RegisterServiceWorker();
+ ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId,
+ data.service_worker_registration_id);
+ WriteNotificationDataSynchronous(data);
+ ASSERT_TRUE(success_);
+
+ NotificationDatabaseData read_data =
+ ReadNotificationDataAndRecordInteractionSynchronous(
+ data.service_worker_registration_id, data.notification_id,
+ PlatformNotificationContext::Interaction::NONE);
+ ASSERT_TRUE(success_);
+ EXPECT_EQ(data.origin, read_data.origin);
+ EXPECT_EQ(data.notification_id, read_data.notification_id);
+ EXPECT_EQ(data.service_worker_registration_id,
+ read_data.service_worker_registration_id);
+}
+
+TEST_F(NotificationStorageTest, ReadInvalidNotification) {
+ int64_t service_worker_registration_id = RegisterServiceWorker();
+ ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId,
+ service_worker_registration_id);
+ ReadNotificationDataAndRecordInteractionSynchronous(
+ service_worker_registration_id, "bad_id",
+ PlatformNotificationContext::Interaction::NONE);
+ ASSERT_FALSE(success_);
+}
+
+TEST_F(NotificationStorageTest, ReadAndUpdateInteraction) {
+ NotificationDatabaseData data, read_data;
+ data.notification_id = GenerateNotificationId();
+ data.origin = origin_;
+ data.service_worker_registration_id = RegisterServiceWorker();
+ ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId,
+ data.service_worker_registration_id);
+
+ WriteNotificationDataSynchronous(data);
+ ASSERT_TRUE(success_);
+
+ // Check that the time deltas have not yet been set.
+ EXPECT_FALSE(read_data.time_until_first_click_millis.has_value());
+ EXPECT_FALSE(read_data.time_until_last_click_millis.has_value());
+ EXPECT_FALSE(read_data.time_until_close_millis.has_value());
+
+ // Check that when a notification has an interaction, the appropriate field is
+ // updated on the read.
+ read_data = ReadNotificationDataAndRecordInteractionSynchronous(
+ data.service_worker_registration_id, data.notification_id,
+ PlatformNotificationContext::Interaction::CLICKED);
+ ASSERT_TRUE(success_);
+ EXPECT_EQ(1, read_data.num_clicks);
+
+ read_data = ReadNotificationDataAndRecordInteractionSynchronous(
+ data.service_worker_registration_id, data.notification_id,
+ PlatformNotificationContext::Interaction::ACTION_BUTTON_CLICKED);
+ ASSERT_TRUE(success_);
+ EXPECT_EQ(1, read_data.num_action_button_clicks);
+
+ read_data = ReadNotificationDataAndRecordInteractionSynchronous(
+ data.service_worker_registration_id, data.notification_id,
+ PlatformNotificationContext::Interaction::ACTION_BUTTON_CLICKED);
+ ASSERT_TRUE(success_);
+ EXPECT_EQ(2, read_data.num_action_button_clicks);
+
+ // Check that the click timestamps are correctly updated.
+ EXPECT_TRUE(read_data.time_until_first_click_millis.has_value());
+ EXPECT_TRUE(read_data.time_until_last_click_millis.has_value());
+
+ // Check that when a read with a CLOSED interaction occurs, the correct
+ // field is updated.
+ read_data = ReadNotificationDataAndRecordInteractionSynchronous(
+ data.service_worker_registration_id, data.notification_id,
+ PlatformNotificationContext::Interaction::CLOSED);
+ ASSERT_TRUE(success_);
+ EXPECT_EQ(true, read_data.time_until_close_millis.has_value());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/notifications/platform_notification_context_impl.cc b/chromium/content/browser/notifications/platform_notification_context_impl.cc
index 627e8dbd251..13ece81608b 100644
--- a/chromium/content/browser/notifications/platform_notification_context_impl.cc
+++ b/chromium/content/browser/notifications/platform_notification_context_impl.cc
@@ -8,7 +8,7 @@
#include "base/files/file_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "content/browser/notifications/blink_notification_service_impl.h"
#include "content/browser/notifications/notification_database.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
@@ -66,6 +66,10 @@ void PlatformNotificationContextImpl::Initialize() {
browser_context_,
base::Bind(&PlatformNotificationContextImpl::DidGetNotificationsOnUI,
this));
+
+ ukm_callback_ = base::BindRepeating(
+ &PlatformNotificationService::RecordNotificationUkmEvent,
+ base::Unretained(service), browser_context_);
}
void PlatformNotificationContextImpl::DidGetNotificationsOnUI(
@@ -309,18 +313,20 @@ void PlatformNotificationContextImpl::
void PlatformNotificationContextImpl::WriteNotificationData(
int64_t persistent_notification_id,
+ int64_t service_worker_registration_id,
const GURL& origin,
const NotificationDatabaseData& database_data,
const WriteResultCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
LazyInitialize(
base::Bind(&PlatformNotificationContextImpl::DoWriteNotificationData,
- this, persistent_notification_id, origin, database_data,
- callback),
+ this, service_worker_registration_id,
+ persistent_notification_id, origin, database_data, callback),
base::Bind(callback, false /* success */, "" /* notification_id */));
}
void PlatformNotificationContextImpl::DoWriteNotificationData(
+ int64_t service_worker_registration_id,
int64_t persistent_notification_id,
const GURL& origin,
const NotificationDatabaseData& database_data,
@@ -472,7 +478,7 @@ void PlatformNotificationContextImpl::LazyInitialize(
if (!task_runner_) {
task_runner_ = base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::BACKGROUND});
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
}
task_runner_->PostTask(
@@ -490,7 +496,7 @@ void PlatformNotificationContextImpl::OpenDatabase(
return;
}
- database_.reset(new NotificationDatabase(GetDatabasePath()));
+ database_.reset(new NotificationDatabase(GetDatabasePath(), ukm_callback_));
NotificationDatabase::Status status =
database_->Open(true /* create_if_missing */);
@@ -502,7 +508,7 @@ void PlatformNotificationContextImpl::OpenDatabase(
prune_database_on_open_ = false;
DestroyDatabase();
- database_.reset(new NotificationDatabase(GetDatabasePath()));
+ database_.reset(new NotificationDatabase(GetDatabasePath(), ukm_callback_));
status = database_->Open(true /* create_if_missing */);
// TODO(peter): Find the appropriate UMA to cover in regards to
@@ -513,7 +519,8 @@ void PlatformNotificationContextImpl::OpenDatabase(
// away the contents of the directory and try re-opening the database.
if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED) {
if (DestroyDatabase()) {
- database_.reset(new NotificationDatabase(GetDatabasePath()));
+ database_.reset(
+ new NotificationDatabase(GetDatabasePath(), ukm_callback_));
status = database_->Open(true /* create_if_missing */);
UMA_HISTOGRAM_ENUMERATION(
diff --git a/chromium/content/browser/notifications/platform_notification_context_impl.h b/chromium/content/browser/notifications/platform_notification_context_impl.h
index 7ea92b62620..653f487b0b0 100644
--- a/chromium/content/browser/notifications/platform_notification_context_impl.h
+++ b/chromium/content/browser/notifications/platform_notification_context_impl.h
@@ -16,6 +16,7 @@
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "content/browser/notifications/notification_database.h"
#include "content/browser/notifications/notification_id_generator.h"
#include "content/browser/service_worker/service_worker_context_core_observer.h"
#include "content/common/content_export.h"
@@ -37,7 +38,6 @@ namespace content {
class BlinkNotificationServiceImpl;
class BrowserContext;
-class NotificationDatabase;
struct NotificationDatabaseData;
class ServiceWorkerContextWrapper;
@@ -84,6 +84,7 @@ class CONTENT_EXPORT PlatformNotificationContextImpl
Interaction interaction,
const ReadResultCallback& callback) override;
void WriteNotificationData(int64_t persistent_notification_id,
+ int64_t service_worker_registration_id,
const GURL& origin,
const NotificationDatabaseData& database_data,
const WriteResultCallback& callback) override;
@@ -166,6 +167,7 @@ class CONTENT_EXPORT PlatformNotificationContextImpl
// called on the |task_runner_| thread. |callback| will be invoked on the
// IO thread when the operation has completed.
void DoWriteNotificationData(int64_t persistent_notification_id,
+ int64_t service_worker_registration_id,
const GURL& origin,
const NotificationDatabaseData& database_data,
const WriteResultCallback& callback);
@@ -212,6 +214,8 @@ class CONTENT_EXPORT PlatformNotificationContextImpl
// removed when either this class is destroyed or the Mojo pipe disconnects.
std::vector<std::unique_ptr<BlinkNotificationServiceImpl>> services_;
+ NotificationDatabase::UkmCallback ukm_callback_;
+
DISALLOW_COPY_AND_ASSIGN(PlatformNotificationContextImpl);
};
diff --git a/chromium/content/browser/notifications/platform_notification_context_unittest.cc b/chromium/content/browser/notifications/platform_notification_context_unittest.cc
index ffe0ebb1681..1e566931611 100644
--- a/chromium/content/browser/notifications/platform_notification_context_unittest.cc
+++ b/chromium/content/browser/notifications/platform_notification_context_unittest.cc
@@ -101,13 +101,13 @@ class PlatformNotificationContextTest : public ::testing::Test {
protected:
// Creates a new PlatformNotificationContextImpl instance. When using this
// method, the underlying database will always be created in memory.
- PlatformNotificationContextImpl* CreatePlatformNotificationContext() {
- PlatformNotificationContextImpl* context =
- new PlatformNotificationContextImpl(base::FilePath(), &browser_context_,
- nullptr);
+ scoped_refptr<PlatformNotificationContextImpl>
+ CreatePlatformNotificationContext() {
+ auto context = base::MakeRefCounted<PlatformNotificationContextImpl>(
+ base::FilePath(), &browser_context_, nullptr);
context->Initialize();
- OverrideTaskRunnerForTesting(context);
+ OverrideTaskRunnerForTesting(context.get());
return context;
}
@@ -172,7 +172,8 @@ TEST_F(PlatformNotificationContextTest, WriteReadNotification) {
notification_database_data.origin = origin;
context->WriteNotificationData(
- next_persistent_notification_id(), origin, notification_database_data,
+ next_persistent_notification_id(), kFakeServiceWorkerRegistrationId,
+ origin, notification_database_data,
base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData,
base::Unretained(this)));
@@ -213,7 +214,8 @@ TEST_F(PlatformNotificationContextTest, WriteReadReplacedNotification) {
// Write the first notification with the given |tag|.
context->WriteNotificationData(
- next_persistent_notification_id(), origin, notification_database_data,
+ next_persistent_notification_id(), kFakeServiceWorkerRegistrationId,
+ origin, notification_database_data,
base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData,
base::Unretained(this)));
base::RunLoop().RunUntilIdle();
@@ -229,7 +231,8 @@ TEST_F(PlatformNotificationContextTest, WriteReadReplacedNotification) {
// Write the second notification with the given |tag|.
context->WriteNotificationData(
- next_persistent_notification_id(), origin, notification_database_data,
+ next_persistent_notification_id(), kFakeServiceWorkerRegistrationId,
+ origin, notification_database_data,
base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData,
base::Unretained(this)));
@@ -283,7 +286,8 @@ TEST_F(PlatformNotificationContextTest, DeleteNotification) {
NotificationDatabaseData notification_database_data;
context->WriteNotificationData(
- next_persistent_notification_id(), origin, notification_database_data,
+ next_persistent_notification_id(), kFakeServiceWorkerRegistrationId,
+ origin, notification_database_data,
base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData,
base::Unretained(this)));
@@ -351,7 +355,8 @@ TEST_F(PlatformNotificationContextTest, ServiceWorkerUnregistered) {
// Create a notification for that Service Worker registration.
notification_context->WriteNotificationData(
- next_persistent_notification_id(), origin, notification_database_data,
+ next_persistent_notification_id(), kFakeServiceWorkerRegistrationId,
+ origin, notification_database_data,
base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData,
base::Unretained(this)));
@@ -390,7 +395,8 @@ TEST_F(PlatformNotificationContextTest, DestroyDatabaseOnStorageWiped) {
NotificationDatabaseData notification_database_data;
context->WriteNotificationData(
- next_persistent_notification_id(), origin, notification_database_data,
+ next_persistent_notification_id(), kFakeServiceWorkerRegistrationId,
+ origin, notification_database_data,
base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData,
base::Unretained(this)));
@@ -483,7 +489,8 @@ TEST_F(PlatformNotificationContextTest, ReadAllServiceWorkerDataFilled) {
// test Service Worker Registration id.
for (int i = 0; i < 10; ++i) {
context->WriteNotificationData(
- next_persistent_notification_id(), origin, notification_database_data,
+ next_persistent_notification_id(), kFakeServiceWorkerRegistrationId,
+ origin, notification_database_data,
base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData,
base::Unretained(this)));
@@ -527,7 +534,8 @@ TEST_F(PlatformNotificationContextTest, SynchronizeNotifications) {
content::NotificationResources notification_resources;
context->WriteNotificationData(
- next_persistent_notification_id(), origin, notification_database_data,
+ next_persistent_notification_id(), kFakeServiceWorkerRegistrationId,
+ origin, notification_database_data,
base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData,
base::Unretained(this)));
diff --git a/chromium/content/browser/oop_browsertest.cc b/chromium/content/browser/oop_browsertest.cc
index 390c73409e9..eaf658ca213 100644
--- a/chromium/content/browser/oop_browsertest.cc
+++ b/chromium/content/browser/oop_browsertest.cc
@@ -38,7 +38,7 @@ class OOPBrowserTest : public ContentBrowserTest {
command_line->AppendSwitch(switches::kEnablePixelOutputInTests);
command_line->AppendSwitch(switches::kEnableOopRasterization);
- const bool use_gpu_in_tests = features::IsAshInBrowserProcess();
+ const bool use_gpu_in_tests = !features::IsUsingWindowService();
if (use_gpu_in_tests)
command_line->AppendSwitch(switches::kUseGpuInTests);
}
diff --git a/chromium/content/browser/payments/payment_app_browsertest.cc b/chromium/content/browser/payments/payment_app_browsertest.cc
index 0c837e8f51b..00e36951e35 100644
--- a/chromium/content/browser/payments/payment_app_browsertest.cc
+++ b/chromium/content/browser/payments/payment_app_browsertest.cc
@@ -17,8 +17,8 @@
#include "content/shell/browser/shell.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/payments/payment_app.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
-#include "third_party/blink/public/platform/modules/payments/payment_app.mojom.h"
namespace content {
namespace {
@@ -234,8 +234,16 @@ class PaymentAppBrowserTest : public ContentBrowserTest {
DISALLOW_COPY_AND_ASSIGN(PaymentAppBrowserTest);
};
+// TODO(crbug.com/869790) Flakes on linux-chromeos-dbg
+#if defined(OS_CHROMEOS) && !defined(NDEBUG)
+#define MAYBE_AbortPaymentWithInvalidRegistrationId \
+ DISABLED_AbortPaymentWithInvalidRegistrationId
+#else
+#define MAYBE_AbortPaymentWithInvalidRegistrationId \
+ AbortPaymentWithInvalidRegistrationId
+#endif
IN_PROC_BROWSER_TEST_F(PaymentAppBrowserTest,
- AbortPaymentWithInvalidRegistrationId) {
+ MAYBE_AbortPaymentWithInvalidRegistrationId) {
RegisterPaymentApp();
std::vector<int64_t> registrationIds = GetAllPaymentAppRegistrationIDs();
@@ -248,7 +256,13 @@ IN_PROC_BROWSER_TEST_F(PaymentAppBrowserTest,
ClearStoragePartitionData();
}
-IN_PROC_BROWSER_TEST_F(PaymentAppBrowserTest, AbortPayment) {
+// TODO(crbug.com/869790) Flakes on linux-chromeos-dbg
+#if defined(OS_CHROMEOS) && !defined(NDEBUG)
+#define MAYBE_AbortPayment DISABLED_AbortPayment
+#else
+#define MAYBE_AbortPayment AbortPayment
+#endif
+IN_PROC_BROWSER_TEST_F(PaymentAppBrowserTest, MAYBE_AbortPayment) {
RegisterPaymentApp();
std::vector<int64_t> registrationIds = GetAllPaymentAppRegistrationIDs();
@@ -260,7 +274,13 @@ IN_PROC_BROWSER_TEST_F(PaymentAppBrowserTest, AbortPayment) {
ClearStoragePartitionData();
}
-IN_PROC_BROWSER_TEST_F(PaymentAppBrowserTest, CanMakePayment) {
+// TODO(crbug.com/869790) Flakes on linux-chromeos-dbg
+#if defined(OS_CHROMEOS) && !defined(NDEBUG)
+#define MAYBE_CanMakePayment DISABLED_CanMakePayment
+#else
+#define MAYBE_CanMakePayment CanMakePayment
+#endif
+IN_PROC_BROWSER_TEST_F(PaymentAppBrowserTest, MAYBE_CanMakePayment) {
RegisterPaymentApp();
std::vector<int64_t> registrationIds = GetAllPaymentAppRegistrationIDs();
@@ -285,7 +305,15 @@ IN_PROC_BROWSER_TEST_F(PaymentAppBrowserTest, CanMakePayment) {
PopConsoleString() /* modifiers */);
}
-IN_PROC_BROWSER_TEST_F(PaymentAppBrowserTest, PaymentAppInvocationAndFailed) {
+// TODO(crbug.com/869790) Flakes on linux-chromeos-dbg
+#if defined(OS_CHROMEOS) && !defined(NDEBUG)
+#define MAYBE_PaymentAppInvocationAndFailed \
+ DISABLED_PaymentAppInvocationAndFailed
+#else
+#define MAYBE_PaymentAppInvocationAndFailed PaymentAppInvocationAndFailed
+#endif
+IN_PROC_BROWSER_TEST_F(PaymentAppBrowserTest,
+ MAYBE_PaymentAppInvocationAndFailed) {
RegisterPaymentApp();
std::vector<int64_t> registrationIds = GetAllPaymentAppRegistrationIDs();
@@ -301,7 +329,13 @@ IN_PROC_BROWSER_TEST_F(PaymentAppBrowserTest, PaymentAppInvocationAndFailed) {
ClearStoragePartitionData();
}
-IN_PROC_BROWSER_TEST_F(PaymentAppBrowserTest, PaymentAppInvocation) {
+// TODO(crbug.com/869790) Flakes on linux-chromeos-dbg
+#if defined(OS_CHROMEOS) && !defined(NDEBUG)
+#define MAYBE_PaymentAppInvocation DISABLED_PaymentAppInvocation
+#else
+#define MAYBE_PaymentAppInvocation PaymentAppInvocation
+#endif
+IN_PROC_BROWSER_TEST_F(PaymentAppBrowserTest, MAYBE_PaymentAppInvocation) {
RegisterPaymentApp();
std::vector<int64_t> registrationIds = GetAllPaymentAppRegistrationIDs();
@@ -336,7 +370,14 @@ IN_PROC_BROWSER_TEST_F(PaymentAppBrowserTest, PaymentAppInvocation) {
PopConsoleString() /* instrumentKey */);
}
-IN_PROC_BROWSER_TEST_F(PaymentAppBrowserTest, PaymentAppOpenWindowFailed) {
+// TODO(crbug.com/869790) Flakes on linux-chromeos-dbg
+#if defined(OS_CHROMEOS) && !defined(NDEBUG)
+#define MAYBE_PaymentAppOpenWindowFailed DISABLED_PaymentAppOpenWindowFailed
+#else
+#define MAYBE_PaymentAppOpenWindowFailed PaymentAppOpenWindowFailed
+#endif
+IN_PROC_BROWSER_TEST_F(PaymentAppBrowserTest,
+ MAYBE_PaymentAppOpenWindowFailed) {
RegisterPaymentApp();
std::vector<int64_t> registrationIds = GetAllPaymentAppRegistrationIDs();
diff --git a/chromium/content/browser/payments/payment_app_content_unittest_base.h b/chromium/content/browser/payments/payment_app_content_unittest_base.h
index 12a82842839..c09dd080903 100644
--- a/chromium/content/browser/payments/payment_app_content_unittest_base.h
+++ b/chromium/content/browser/payments/payment_app_content_unittest_base.h
@@ -13,7 +13,7 @@
#include "base/memory/ref_counted.h"
#include "content/browser/payments/payment_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/modules/payments/payment_app.mojom.h"
+#include "third_party/blink/public/mojom/payments/payment_app.mojom.h"
#include "url/gurl.h"
namespace content {
diff --git a/chromium/content/browser/payments/payment_app_context_impl.h b/chromium/content/browser/payments/payment_app_context_impl.h
index 8c8ce926912..e79119e7f30 100644
--- a/chromium/content/browser/payments/payment_app_context_impl.h
+++ b/chromium/content/browser/payments/payment_app_context_impl.h
@@ -15,7 +15,7 @@
#include "content/browser/payments/payment_app_database.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_thread.h"
-#include "third_party/blink/public/platform/modules/payments/payment_app.mojom.h"
+#include "third_party/blink/public/mojom/payments/payment_app.mojom.h"
namespace content {
diff --git a/chromium/content/browser/payments/payment_app_database.cc b/chromium/content/browser/payments/payment_app_database.cc
index 924d36591cc..043c5b038e7 100644
--- a/chromium/content/browser/payments/payment_app_database.cc
+++ b/chromium/content/browser/payments/payment_app_database.cc
@@ -19,7 +19,7 @@
#include "content/public/browser/browser_thread.h"
#include "third_party/blink/public/common/manifest/manifest.h"
#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/image/image.h"
+#include "ui/gfx/codec/png_codec.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -106,12 +106,13 @@ std::unique_ptr<StoredPaymentApp> ToStoredPaymentApp(const std::string& input) {
if (!app_proto.icon().empty()) {
std::string icon_raw_data;
base::Base64Decode(app_proto.icon(), &icon_raw_data);
+ app->icon = std::make_unique<SkBitmap>();
// Note that the icon has been decoded to PNG raw data regardless of the
// original icon format that was downloaded.
- gfx::Image icon_image = gfx::Image::CreateFrom1xPNGBytes(
+ bool success = gfx::PNGCodec::Decode(
reinterpret_cast<const unsigned char*>(icon_raw_data.data()),
- icon_raw_data.size());
- app->icon = std::make_unique<SkBitmap>(icon_image.AsBitmap());
+ icon_raw_data.size(), app->icon.get());
+ DCHECK(success);
}
return app;
diff --git a/chromium/content/browser/payments/payment_app_database.h b/chromium/content/browser/payments/payment_app_database.h
index 07bb2e8c310..2652f8eca97 100644
--- a/chromium/content/browser/payments/payment_app_database.h
+++ b/chromium/content/browser/payments/payment_app_database.h
@@ -19,7 +19,7 @@
#include "content/public/browser/stored_payment_app.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
-#include "third_party/blink/public/platform/modules/payments/payment_app.mojom.h"
+#include "third_party/blink/public/mojom/payments/payment_app.mojom.h"
namespace content {
diff --git a/chromium/content/browser/payments/payment_app_info_fetcher.cc b/chromium/content/browser/payments/payment_app_info_fetcher.cc
index 5ba89bcdda3..c1714b4cfe6 100644
--- a/chromium/content/browser/payments/payment_app_info_fetcher.cc
+++ b/chromium/content/browser/payments/payment_app_info_fetcher.cc
@@ -4,16 +4,19 @@
#include "content/browser/payments/payment_app_info_fetcher.h"
+#include <utility>
+
#include "base/base64.h"
#include "base/bind_helpers.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/manifest_icon_downloader.h"
#include "content/public/common/console_message_level.h"
#include "third_party/blink/public/common/manifest/manifest_icon_selector.h"
-#include "ui/gfx/image/image.h"
+#include "ui/gfx/codec/png_codec.h"
#include "url/origin.h"
namespace content {
@@ -28,7 +31,7 @@ void PaymentAppInfoFetcher::Start(
PaymentAppInfoFetchCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- std::unique_ptr<std::vector<std::pair<int, int>>> provider_hosts =
+ std::unique_ptr<std::vector<GlobalFrameRoutingId>> provider_hosts =
service_worker_context->GetProviderHostIds(context_url.GetOrigin());
BrowserThread::PostTask(
@@ -39,7 +42,7 @@ void PaymentAppInfoFetcher::Start(
void PaymentAppInfoFetcher::StartOnUI(
const GURL& context_url,
- const std::unique_ptr<std::vector<std::pair<int, int>>>& provider_hosts,
+ const std::unique_ptr<std::vector<GlobalFrameRoutingId>>& provider_hosts,
PaymentAppInfoFetchCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -70,7 +73,7 @@ PaymentAppInfoFetcher::SelfDeleteFetcher::~SelfDeleteFetcher() {
void PaymentAppInfoFetcher::SelfDeleteFetcher::Start(
const GURL& context_url,
- const std::unique_ptr<std::vector<std::pair<int, int>>>& provider_hosts) {
+ const std::unique_ptr<std::vector<GlobalFrameRoutingId>>& provider_hosts) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (provider_hosts->size() == 0U) {
@@ -81,7 +84,7 @@ void PaymentAppInfoFetcher::SelfDeleteFetcher::Start(
for (const auto& frame : *provider_hosts) {
// Find out the render frame host registering the payment app.
RenderFrameHostImpl* render_frame_host =
- RenderFrameHostImpl::FromID(frame.first, frame.second);
+ RenderFrameHostImpl::FromID(frame.child_id, frame.frame_routing_id);
if (!render_frame_host ||
context_url.spec().compare(
render_frame_host->GetLastCommittedURL().spec()) != 0) {
@@ -259,10 +262,12 @@ void PaymentAppInfoFetcher::SelfDeleteFetcher::OnIconFetched(
return;
}
- gfx::Image decoded_image = gfx::Image::CreateFrom1xBitmap(icon);
- scoped_refptr<base::RefCountedMemory> raw_data = decoded_image.As1xPNGBytes();
+ std::vector<unsigned char> bitmap_data;
+ bool success = gfx::PNGCodec::EncodeBGRASkBitmap(icon, false, &bitmap_data);
+ DCHECK(success);
base::Base64Encode(
- base::StringPiece(raw_data->front_as<char>(), raw_data->size()),
+ base::StringPiece(reinterpret_cast<const char*>(&bitmap_data[0]),
+ bitmap_data.size()),
&(fetched_payment_app_info_->icon));
RunCallbackAndDestroy();
}
diff --git a/chromium/content/browser/payments/payment_app_info_fetcher.h b/chromium/content/browser/payments/payment_app_info_fetcher.h
index 73dd74fcd45..756622eb5c7 100644
--- a/chromium/content/browser/payments/payment_app_info_fetcher.h
+++ b/chromium/content/browser/payments/payment_app_info_fetcher.h
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/stored_payment_app.h"
#include "content/public/browser/web_contents_observer.h"
#include "third_party/blink/public/common/manifest/manifest.h"
@@ -41,7 +42,7 @@ class PaymentAppInfoFetcher {
// Only accessed on the UI thread.
static void StartOnUI(
const GURL& context_url,
- const std::unique_ptr<std::vector<std::pair<int, int>>>& provider_hosts,
+ const std::unique_ptr<std::vector<GlobalFrameRoutingId>>& provider_hosts,
PaymentAppInfoFetchCallback callback);
// Keeps track of the web contents.
@@ -59,7 +60,7 @@ class PaymentAppInfoFetcher {
~SelfDeleteFetcher();
void Start(const GURL& context_url,
- const std::unique_ptr<std::vector<std::pair<int, int>>>&
+ const std::unique_ptr<std::vector<GlobalFrameRoutingId>>&
provider_hosts);
private:
diff --git a/chromium/content/browser/payments/payment_app_provider_impl_unittest.cc b/chromium/content/browser/payments/payment_app_provider_impl_unittest.cc
index 4ed0f9bb1ad..42bf14809dc 100644
--- a/chromium/content/browser/payments/payment_app_provider_impl_unittest.cc
+++ b/chromium/content/browser/payments/payment_app_provider_impl_unittest.cc
@@ -15,7 +15,7 @@
#include "content/public/test/test_browser_context.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/modules/payments/payment_app.mojom.h"
+#include "third_party/blink/public/mojom/payments/payment_app.mojom.h"
#include "third_party/blink/public/platform/modules/permissions/permission_status.mojom.h"
#include "url/gurl.h"
diff --git a/chromium/content/browser/payments/payment_instrument_icon_fetcher.cc b/chromium/content/browser/payments/payment_instrument_icon_fetcher.cc
index 8ef0de4e991..3bb8cffa724 100644
--- a/chromium/content/browser/payments/payment_instrument_icon_fetcher.cc
+++ b/chromium/content/browser/payments/payment_instrument_icon_fetcher.cc
@@ -4,6 +4,8 @@
#include "content/browser/payments/payment_instrument_icon_fetcher.h"
+#include <utility>
+
#include "base/base64.h"
#include "base/bind_helpers.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
@@ -13,8 +15,7 @@
#include "content/public/browser/manifest_icon_downloader.h"
#include "third_party/blink/public/common/manifest/manifest_icon_selector.h"
#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/image/image.h"
+#include "ui/gfx/codec/png_codec.h"
namespace content {
namespace {
@@ -52,11 +53,13 @@ void OnIconFetched(
return;
}
- gfx::Image decoded_image = gfx::Image::CreateFrom1xBitmap(bitmap);
- scoped_refptr<base::RefCountedMemory> raw_data = decoded_image.As1xPNGBytes();
+ std::vector<unsigned char> bitmap_data;
+ bool success = gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &bitmap_data);
+ DCHECK(success);
std::string encoded_data;
base::Base64Encode(
- base::StringPiece(raw_data->front_as<char>(), raw_data->size()),
+ base::StringPiece(reinterpret_cast<const char*>(&bitmap_data[0]),
+ bitmap_data.size()),
&encoded_data);
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::BindOnce(std::move(callback), encoded_data));
@@ -99,12 +102,12 @@ void DownloadBestMatchingIcon(
WebContents* GetWebContentsFromProviderHostIds(
const GURL& scope,
- std::unique_ptr<std::vector<std::pair<int, int>>> provider_hosts) {
+ std::unique_ptr<std::vector<GlobalFrameRoutingId>> provider_hosts) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
for (const auto& host : *provider_hosts) {
RenderFrameHostImpl* render_frame_host =
- RenderFrameHostImpl::FromID(host.first, host.second);
+ RenderFrameHostImpl::FromID(host.child_id, host.frame_routing_id);
if (!render_frame_host)
continue;
@@ -122,7 +125,7 @@ WebContents* GetWebContentsFromProviderHostIds(
void StartOnUI(
const GURL& scope,
- std::unique_ptr<std::vector<std::pair<int, int>>> provider_hosts,
+ std::unique_ptr<std::vector<GlobalFrameRoutingId>> provider_hosts,
const std::vector<blink::Manifest::ImageResource>& icons,
PaymentInstrumentIconFetcher::PaymentInstrumentIconFetcherCallback
callback) {
@@ -138,7 +141,7 @@ void StartOnUI(
// static
void PaymentInstrumentIconFetcher::Start(
const GURL& scope,
- std::unique_ptr<std::vector<std::pair<int, int>>> provider_hosts,
+ std::unique_ptr<std::vector<GlobalFrameRoutingId>> provider_hosts,
const std::vector<blink::Manifest::ImageResource>& icons,
PaymentInstrumentIconFetcherCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
diff --git a/chromium/content/browser/payments/payment_instrument_icon_fetcher.h b/chromium/content/browser/payments/payment_instrument_icon_fetcher.h
index c31d531fcc7..80dd3af3ba0 100644
--- a/chromium/content/browser/payments/payment_instrument_icon_fetcher.h
+++ b/chromium/content/browser/payments/payment_instrument_icon_fetcher.h
@@ -5,14 +5,16 @@
#ifndef CONTENT_BROWSER_PAYMENTS_PAYMENT_INSTRUMENT_ICON_FETCHER_H_
#define CONTENT_BROWSER_PAYMENTS_PAYMENT_INSTRUMENT_ICON_FETCHER_H_
+#include <memory>
#include <string>
#include <vector>
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "content/public/browser/global_routing_id.h"
#include "third_party/blink/public/common/manifest/manifest.h"
-#include "third_party/blink/public/platform/modules/payments/payment_app.mojom.h"
+#include "third_party/blink/public/mojom/payments/payment_app.mojom.h"
namespace content {
@@ -24,7 +26,7 @@ class PaymentInstrumentIconFetcher {
// Should be called on IO thread.
static void Start(
const GURL& scope,
- std::unique_ptr<std::vector<std::pair<int, int>>> provider_hosts,
+ std::unique_ptr<std::vector<GlobalFrameRoutingId>> provider_hosts,
const std::vector<blink::Manifest::ImageResource>& icons,
PaymentInstrumentIconFetcherCallback callback);
diff --git a/chromium/content/browser/payments/payment_manager.h b/chromium/content/browser/payments/payment_manager.h
index 87a63ae300c..bb37eca5113 100644
--- a/chromium/content/browser/payments/payment_manager.h
+++ b/chromium/content/browser/payments/payment_manager.h
@@ -11,7 +11,7 @@
#include "base/memory/weak_ptr.h"
#include "content/common/content_export.h"
#include "mojo/public/cpp/bindings/binding.h"
-#include "third_party/blink/public/platform/modules/payments/payment_app.mojom.h"
+#include "third_party/blink/public/mojom/payments/payment_app.mojom.h"
#include "url/gurl.h"
namespace content {
diff --git a/chromium/content/browser/payments/payment_manager_unittest.cc b/chromium/content/browser/payments/payment_manager_unittest.cc
index b1320ce7ad5..6a19821a54c 100644
--- a/chromium/content/browser/payments/payment_manager_unittest.cc
+++ b/chromium/content/browser/payments/payment_manager_unittest.cc
@@ -8,7 +8,7 @@
#include "base/run_loop.h"
#include "content/browser/payments/payment_app_content_unittest_base.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/modules/payments/payment_app.mojom.h"
+#include "third_party/blink/public/mojom/payments/payment_app.mojom.h"
#include "url/gurl.h"
namespace content {
diff --git a/chromium/content/browser/permissions/permission_controller_impl.cc b/chromium/content/browser/permissions/permission_controller_impl.cc
index 75ccdf0efb4..b182e8de0bf 100644
--- a/chromium/content/browser/permissions/permission_controller_impl.cc
+++ b/chromium/content/browser/permissions/permission_controller_impl.cc
@@ -9,12 +9,27 @@
#include "content/common/content_export.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/permission_controller_delegate.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
#include "third_party/blink/public/platform/modules/permissions/permission_status.mojom.h"
class GURL;
namespace content {
+namespace {
+
+blink::mojom::PermissionStatus GetPermissionOverrideStatus(
+ const PermissionControllerImpl::PermissionOverrides& permission_overrides,
+ const PermissionType& permission) {
+ if (permission_overrides.find(permission) == permission_overrides.end())
+ return blink::mojom::PermissionStatus::DENIED;
+ return blink::mojom::PermissionStatus::GRANTED;
+}
+
+} // namespace
+
PermissionControllerImpl::PermissionControllerImpl(
BrowserContext* browser_context)
: browser_context_(browser_context) {}
@@ -26,7 +41,78 @@ PermissionControllerImpl* PermissionControllerImpl::FromBrowserContext(
BrowserContext::GetPermissionController(browser_context));
}
-PermissionControllerImpl::~PermissionControllerImpl() = default;
+struct PermissionControllerImpl::Subscription {
+ PermissionType permission;
+ GURL requesting_origin;
+ GURL embedding_origin;
+ int render_frame_id = -1;
+ int render_process_id = -1;
+ base::Callback<void(blink::mojom::PermissionStatus)> callback;
+ int delegate_subscription_id;
+};
+
+PermissionControllerImpl::~PermissionControllerImpl() {
+ // Ideally we need to unsubscribe from delegate subscriptions here,
+ // but browser_context_ is already destroyed by this point, so
+ // we can't fetch our delegate.
+}
+
+blink::mojom::PermissionStatus
+PermissionControllerImpl::GetSubscriptionCurrentValue(
+ const Subscription& subscription) {
+ // The RFH may be null if the request is for a worker.
+ content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
+ subscription.render_process_id, subscription.render_frame_id);
+ if (rfh) {
+ return GetPermissionStatusForFrame(subscription.permission, rfh,
+ subscription.requesting_origin);
+ }
+ return GetPermissionStatus(subscription.permission,
+ subscription.requesting_origin,
+ subscription.embedding_origin);
+}
+
+void PermissionControllerImpl::SetPermissionOverridesForDevTools(
+ const GURL& origin,
+ const PermissionOverrides& overrides) {
+ std::vector<base::Closure> callbacks;
+ for (SubscriptionsMap::iterator iter(&subscriptions_); !iter.IsAtEnd();
+ iter.Advance()) {
+ Subscription* subscription = iter.GetCurrentValue();
+ if (subscription->requesting_origin != origin)
+ continue;
+ blink::mojom::PermissionStatus current_value =
+ GetSubscriptionCurrentValue(*subscription);
+ blink::mojom::PermissionStatus new_value =
+ GetPermissionOverrideStatus(overrides, subscription->permission);
+ if (current_value != new_value)
+ callbacks.push_back(base::Bind(subscription->callback, new_value));
+ }
+ devtools_permission_overrides_[origin] = overrides;
+ for (const auto& callback : callbacks)
+ callback.Run();
+}
+
+void PermissionControllerImpl::ResetPermissionOverridesForDevTools() {
+ std::map<GURL, PermissionOverrides> old_overrides;
+ old_overrides.swap(devtools_permission_overrides_);
+ std::vector<base::Closure> callbacks;
+ for (SubscriptionsMap::iterator iter(&subscriptions_); !iter.IsAtEnd();
+ iter.Advance()) {
+ Subscription* subscription = iter.GetCurrentValue();
+ auto overrides_it = old_overrides.find(subscription->requesting_origin);
+ if (overrides_it == old_overrides.end())
+ continue;
+ blink::mojom::PermissionStatus current_value = GetPermissionOverrideStatus(
+ overrides_it->second, subscription->permission);
+ blink::mojom::PermissionStatus new_value =
+ GetSubscriptionCurrentValue(*subscription);
+ if (current_value != new_value)
+ callbacks.push_back(base::Bind(subscription->callback, new_value));
+ }
+ for (const auto& callback : callbacks)
+ callback.Run();
+}
int PermissionControllerImpl::RequestPermission(
PermissionType permission,
@@ -34,6 +120,12 @@ int PermissionControllerImpl::RequestPermission(
const GURL& requesting_origin,
bool user_gesture,
const base::Callback<void(blink::mojom::PermissionStatus)>& callback) {
+ auto it = devtools_permission_overrides_.find(requesting_origin.GetOrigin());
+ if (it != devtools_permission_overrides_.end()) {
+ callback.Run(GetPermissionOverrideStatus(it->second, permission));
+ return kNoPendingOperation;
+ }
+
PermissionControllerDelegate* delegate =
browser_context_->GetPermissionControllerDelegate();
if (!delegate) {
@@ -51,6 +143,15 @@ int PermissionControllerImpl::RequestPermissions(
bool user_gesture,
const base::Callback<
void(const std::vector<blink::mojom::PermissionStatus>&)>& callback) {
+ auto it = devtools_permission_overrides_.find(requesting_origin.GetOrigin());
+ if (it != devtools_permission_overrides_.end()) {
+ std::vector<blink::mojom::PermissionStatus> result;
+ for (auto& permission : permissions)
+ result.push_back(GetPermissionOverrideStatus(it->second, permission));
+ callback.Run(result);
+ return kNoPendingOperation;
+ }
+
PermissionControllerDelegate* delegate =
browser_context_->GetPermissionControllerDelegate();
if (!delegate) {
@@ -68,6 +169,10 @@ blink::mojom::PermissionStatus PermissionControllerImpl::GetPermissionStatus(
PermissionType permission,
const GURL& requesting_origin,
const GURL& embedding_origin) {
+ auto it = devtools_permission_overrides_.find(requesting_origin.GetOrigin());
+ if (it != devtools_permission_overrides_.end())
+ return GetPermissionOverrideStatus(it->second, permission);
+
PermissionControllerDelegate* delegate =
browser_context_->GetPermissionControllerDelegate();
if (!delegate)
@@ -81,6 +186,10 @@ PermissionControllerImpl::GetPermissionStatusForFrame(
PermissionType permission,
RenderFrameHost* render_frame_host,
const GURL& requesting_origin) {
+ auto it = devtools_permission_overrides_.find(requesting_origin.GetOrigin());
+ if (it != devtools_permission_overrides_.end())
+ return GetPermissionOverrideStatus(it->second, permission);
+
PermissionControllerDelegate* delegate =
browser_context_->GetPermissionControllerDelegate();
if (!delegate)
@@ -99,26 +208,67 @@ void PermissionControllerImpl::ResetPermission(PermissionType permission,
delegate->ResetPermission(permission, requesting_origin, embedding_origin);
}
+void PermissionControllerImpl::OnDelegatePermissionStatusChange(
+ Subscription* subscription,
+ blink::mojom::PermissionStatus status) {
+ auto overrides_it =
+ devtools_permission_overrides_.find(subscription->requesting_origin);
+ if (overrides_it == devtools_permission_overrides_.end())
+ subscription->callback.Run(status);
+}
+
int PermissionControllerImpl::SubscribePermissionStatusChange(
PermissionType permission,
+ RenderFrameHost* render_frame_host,
const GURL& requesting_origin,
- const GURL& embedding_origin,
const base::Callback<void(blink::mojom::PermissionStatus)>& callback) {
+ auto subscription = std::make_unique<Subscription>();
+ subscription->permission = permission;
+ subscription->callback = callback;
+ subscription->requesting_origin = requesting_origin;
+
+ // The RFH may be null if the request is for a worker.
+ if (render_frame_host) {
+ content::WebContents* web_contents =
+ content::WebContents::FromRenderFrameHost(render_frame_host);
+ subscription->embedding_origin =
+ web_contents->GetLastCommittedURL().GetOrigin();
+ subscription->render_frame_id = render_frame_host->GetRoutingID();
+ subscription->render_process_id = render_frame_host->GetProcess()->GetID();
+ } else {
+ subscription->embedding_origin = requesting_origin;
+ subscription->render_frame_id = -1;
+ subscription->render_process_id = -1;
+ }
+
PermissionControllerDelegate* delegate =
browser_context_->GetPermissionControllerDelegate();
- if (!delegate)
- return kNoPendingOperation;
- return delegate->SubscribePermissionStatusChange(
- permission, requesting_origin, embedding_origin, callback);
+ if (delegate) {
+ subscription->delegate_subscription_id =
+ delegate->SubscribePermissionStatusChange(
+ permission, render_frame_host, requesting_origin,
+ base::Bind(
+ &PermissionControllerImpl::OnDelegatePermissionStatusChange,
+ base::Unretained(this), subscription.get()));
+ } else {
+ subscription->delegate_subscription_id = kNoPendingOperation;
+ }
+ return subscriptions_.Add(std::move(subscription));
}
void PermissionControllerImpl::UnsubscribePermissionStatusChange(
int subscription_id) {
+ Subscription* subscription = subscriptions_.Lookup(subscription_id);
+ if (!subscription)
+ return;
PermissionControllerDelegate* delegate =
browser_context_->GetPermissionControllerDelegate();
- if (!delegate)
- return;
- delegate->UnsubscribePermissionStatusChange(subscription_id);
+ if (delegate &&
+ subscription->delegate_subscription_id != kNoPendingOperation) {
+ delegate->UnsubscribePermissionStatusChange(
+ subscription->delegate_subscription_id);
+ }
+ subscriptions_.Remove(subscription_id);
}
} // namespace content
diff --git a/chromium/content/browser/permissions/permission_controller_impl.h b/chromium/content/browser/permissions/permission_controller_impl.h
index 460f033513a..f6f0c2cec62 100644
--- a/chromium/content/browser/permissions/permission_controller_impl.h
+++ b/chromium/content/browser/permissions/permission_controller_impl.h
@@ -5,8 +5,10 @@
#ifndef CONTENT_BROWSER_PERMISSIONS_PERMISSION_CONTROLLER_IMPL_H_
#define CONTENT_BROWSER_PERMISSIONS_PERMISSION_CONTROLLER_IMPL_H_
+#include "base/containers/id_map.h"
#include "content/common/content_export.h"
#include "content/public/browser/permission_controller.h"
+#include "url/gurl.h"
namespace content {
@@ -23,6 +25,13 @@ class CONTENT_EXPORT PermissionControllerImpl : public PermissionController {
static PermissionControllerImpl* FromBrowserContext(
BrowserContext* browser_context);
+ using PermissionOverrides = std::set<PermissionType>;
+ // For the given |origin|, grant permissions that belong to |overrides|
+ // and reject all others.
+ void SetPermissionOverridesForDevTools(const GURL& origin,
+ const PermissionOverrides& overrides);
+ void ResetPermissionOverridesForDevTools();
+
// PermissionController implementation.
blink::mojom::PermissionStatus GetPermissionStatus(
PermissionType permission,
@@ -55,13 +64,23 @@ class CONTENT_EXPORT PermissionControllerImpl : public PermissionController {
int SubscribePermissionStatusChange(
PermissionType permission,
+ RenderFrameHost* render_frame_host,
const GURL& requesting_origin,
- const GURL& embedding_origin,
const base::Callback<void(blink::mojom::PermissionStatus)>& callback);
void UnsubscribePermissionStatusChange(int subscription_id);
private:
+ struct Subscription;
+ using SubscriptionsMap = base::IDMap<std::unique_ptr<Subscription>>;
+
+ blink::mojom::PermissionStatus GetSubscriptionCurrentValue(
+ const Subscription& subscription);
+ void OnDelegatePermissionStatusChange(Subscription* subscription,
+ blink::mojom::PermissionStatus status);
+
+ std::map<GURL, PermissionOverrides> devtools_permission_overrides_;
+ SubscriptionsMap subscriptions_;
BrowserContext* browser_context_;
DISALLOW_COPY_AND_ASSIGN(PermissionControllerImpl);
diff --git a/chromium/content/browser/permissions/permission_service_context.cc b/chromium/content/browser/permissions/permission_service_context.cc
index 05cd21bd9ec..e644dd07580 100644
--- a/chromium/content/browser/permissions/permission_service_context.cc
+++ b/chromium/content/browser/permissions/permission_service_context.cc
@@ -97,15 +97,10 @@ void PermissionServiceContext::CreateSubscription(
auto subscription =
std::make_unique<PermissionSubscription>(this, std::move(observer));
GURL requesting_origin(origin.Serialize());
- GURL embedding_origin = GetEmbeddingOrigin();
int subscription_id =
PermissionControllerImpl::FromBrowserContext(browser_context)
->SubscribePermissionStatusChange(
- permission_type, requesting_origin,
- // If the embedding_origin is empty, we'll use the |origin|
- // instead.
- embedding_origin.is_empty() ? requesting_origin
- : embedding_origin,
+ permission_type, render_frame_host_, requesting_origin,
base::Bind(&PermissionSubscription::OnPermissionStatusChanged,
base::Unretained(subscription.get())));
subscription->set_id(subscription_id);
diff --git a/chromium/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc b/chromium/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
index 2dfc189cf09..ba0270dd8d3 100644
--- a/chromium/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
+++ b/chromium/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
@@ -16,8 +16,6 @@
namespace content {
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(PictureInPictureWindowControllerImpl);
-
// static
PictureInPictureWindowController*
PictureInPictureWindowController::GetOrCreateForWebContents(
@@ -48,7 +46,8 @@ PictureInPictureWindowControllerImpl::~PictureInPictureWindowControllerImpl() {
return;
initiator_->SetHasPictureInPictureVideo(false);
- OnLeavingPictureInPicture(true /* should_pause_video */);
+ OnLeavingPictureInPicture(true /* should_pause_video */,
+ true /* should_reset_pip_player */);
}
PictureInPictureWindowControllerImpl::PictureInPictureWindowControllerImpl(
@@ -82,18 +81,26 @@ void PictureInPictureWindowControllerImpl::ClickCustomControl(
media_player_id_->delegate_id, control_id));
}
-void PictureInPictureWindowControllerImpl::Close(bool should_pause_video) {
+void PictureInPictureWindowControllerImpl::SetPictureInPictureCustomControls(
+ const std::vector<blink::PictureInPictureControlInfo>& controls) {
+ DCHECK(window_);
+ window_->SetPictureInPictureCustomControls(controls);
+}
+
+void PictureInPictureWindowControllerImpl::Close(bool should_pause_video,
+ bool should_reset_pip_player) {
if (!window_ || !window_->IsVisible())
return;
window_->Hide();
- CloseInternal(should_pause_video);
+ CloseInternal(should_pause_video, should_reset_pip_player);
}
void PictureInPictureWindowControllerImpl::OnWindowDestroyed() {
window_ = nullptr;
embedder_ = nullptr;
- CloseInternal(true /* should_pause_video */);
+ CloseInternal(true /* should_pause_video */,
+ true /* should_reset_pip_player */);
}
void PictureInPictureWindowControllerImpl::EmbedSurface(
@@ -125,7 +132,7 @@ OverlayWindow* PictureInPictureWindowControllerImpl::GetWindowForTesting() {
}
void PictureInPictureWindowControllerImpl::UpdateLayerBounds() {
- if (window_ && window_->IsVisible()) {
+ if (media_player_id_.has_value() && window_ && window_->IsVisible()) {
media_web_contents_observer_->OnPictureInPictureWindowResize(
window_->GetBounds().size());
}
@@ -183,7 +190,8 @@ bool PictureInPictureWindowControllerImpl::TogglePlayPause() {
}
void PictureInPictureWindowControllerImpl::OnLeavingPictureInPicture(
- bool should_pause_video) {
+ bool should_pause_video,
+ bool should_reset_pip_player) {
if (IsPlayerActive() && should_pause_video) {
// Pause the current video so there is only one video playing at a time.
media_player_id_->render_frame_host->Send(new MediaPlayerDelegateMsg_Pause(
@@ -196,18 +204,21 @@ void PictureInPictureWindowControllerImpl::OnLeavingPictureInPicture(
new MediaPlayerDelegateMsg_EndPictureInPictureMode(
media_player_id_->render_frame_host->GetRoutingID(),
media_player_id_->delegate_id));
+ if (should_reset_pip_player)
+ media_web_contents_observer_->ResetPictureInPictureVideoMediaPlayerId();
}
}
void PictureInPictureWindowControllerImpl::CloseInternal(
- bool should_pause_video) {
+ bool should_pause_video,
+ bool should_reset_pip_player) {
if (initiator_->IsBeingDestroyed())
return;
surface_id_ = viz::SurfaceId();
initiator_->SetHasPictureInPictureVideo(false);
- OnLeavingPictureInPicture(should_pause_video);
+ OnLeavingPictureInPicture(should_pause_video, should_reset_pip_player);
}
void PictureInPictureWindowControllerImpl::EnsureWindow() {
diff --git a/chromium/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h b/chromium/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h
index 7ce6d853fc4..a5c6499509e 100644
--- a/chromium/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h
+++ b/chromium/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h
@@ -35,10 +35,13 @@ class PictureInPictureWindowControllerImpl
// PictureInPictureWindowController:
CONTENT_EXPORT gfx::Size Show() override;
- CONTENT_EXPORT void Close(bool should_pause_video) override;
+ CONTENT_EXPORT void Close(bool should_pause_video,
+ bool should_reset_pip_player) override;
CONTENT_EXPORT void OnWindowDestroyed() override;
CONTENT_EXPORT void ClickCustomControl(
const std::string& control_id) override;
+ CONTENT_EXPORT void SetPictureInPictureCustomControls(
+ const std::vector<blink::PictureInPictureControlInfo>& controls) override;
CONTENT_EXPORT void EmbedSurface(const viz::SurfaceId& surface_id,
const gfx::Size& natural_size) override;
CONTENT_EXPORT OverlayWindow* GetWindowForTesting() override;
@@ -58,11 +61,12 @@ class PictureInPictureWindowControllerImpl
WebContents* initiator);
// Signal to the media player that |this| is leaving Picture-in-Picture mode.
- void OnLeavingPictureInPicture(bool should_pause_video);
+ void OnLeavingPictureInPicture(bool should_pause_video,
+ bool should_reset_pip_player);
// Internal method to set the states after the window was closed, whether via
// the system or Chromium.
- void CloseInternal(bool should_pause_video);
+ void CloseInternal(bool should_pause_video, bool should_reset_pip_player);
// Creates a new window if the previous one was destroyed. It can happen
// because of the system control of the window.
diff --git a/chromium/content/browser/plugin_data_remover_impl.cc b/chromium/content/browser/plugin_data_remover_impl.cc
index 9e6ef2a6610..fefc248ddbb 100644
--- a/chromium/content/browser/plugin_data_remover_impl.cc
+++ b/chromium/content/browser/plugin_data_remover_impl.cc
@@ -98,7 +98,7 @@ class PluginDataRemoverImpl::Context
base::FilePath plugin_path = plugins[0].path;
- PepperPluginInfo* pepper_info =
+ const PepperPluginInfo* pepper_info =
plugin_service->GetRegisteredPpapiPluginInfo(plugin_path);
if (!pepper_info) {
event_->Signal();
diff --git a/chromium/content/browser/plugin_service_impl.cc b/chromium/content/browser/plugin_service_impl.cc
index e4e5a87af7e..3a6480c7177 100644
--- a/chromium/content/browser/plugin_service_impl.cc
+++ b/chromium/content/browser/plugin_service_impl.cc
@@ -6,6 +6,7 @@
#include <stddef.h>
+#include <string>
#include <utility>
#include "base/bind.h"
@@ -18,8 +19,8 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
+#include "base/task/post_task.h"
#include "base/task_runner_util.h"
-#include "base/task_scheduler/post_task.h"
#include "base/threading/thread.h"
#include "build/build_config.h"
#include "content/browser/ppapi_plugin_process_host.h"
@@ -40,6 +41,7 @@
#include "content/public/common/content_switches.h"
#include "content/public/common/process_type.h"
#include "content/public/common/webplugininfo.h"
+#include "ppapi/shared_impl/ppapi_permissions.h"
#include "services/metrics/public/cpp/ukm_builders.h"
namespace content {
@@ -172,13 +174,28 @@ PpapiPluginProcessHost* PluginServiceImpl::FindOrStartPpapiPluginProcess(
}
// Validate that the plugin is actually registered.
- PepperPluginInfo* info = GetRegisteredPpapiPluginInfo(plugin_path);
+ const PepperPluginInfo* info = GetRegisteredPpapiPluginInfo(plugin_path);
if (!info) {
VLOG(1) << "Unable to find ppapi plugin registration for: "
<< plugin_path.MaybeAsASCII();
return nullptr;
}
+ // Flash has its own flavour of CORS, so CORB needs to allow all responses
+ // and rely on Flash to enforce same-origin policy. See also
+ // https://crbug.com/874515 and https://crbug.com/816318#c5.
+ //
+ // Note that ppapi::PERMISSION_FLASH is present not only in the Flash plugin.
+ // This permission is also present in plugins added from the cmdline and so
+ // will be also present for "PPAPI Tests" plugin used for
+ // OutOfProcessPPAPITest.URLLoaderTrusted and related tests.
+ //
+ // TODO(lukasza, laforge): https://crbug.com/702995: Remove the code below
+ // once Flash support is removed from Chromium (probably around 2020 - see
+ // https://www.chromium.org/flash-roadmap).
+ if (info->permissions & ppapi::PERMISSION_FLASH)
+ RenderProcessHostImpl::AddCorbExceptionForPlugin(render_process_id);
+
PpapiPluginProcessHost* plugin_host =
FindPpapiPluginProcess(plugin_path, profile_data_directory, origin_lock);
if (plugin_host)
@@ -224,12 +241,11 @@ PpapiPluginProcessHost* PluginServiceImpl::FindOrStartPpapiBrokerProcess(
return plugin_host;
// Validate that the plugin is actually registered.
- PepperPluginInfo* info = GetRegisteredPpapiPluginInfo(plugin_path);
+ const PepperPluginInfo* info = GetRegisteredPpapiPluginInfo(plugin_path);
if (!info)
return nullptr;
- // TODO(ddorwin): Uncomment once out of process is supported.
- // DCHECK(info->is_out_of_process);
+ DCHECK(info->is_out_of_process);
// This broker isn't loaded by any broker process, so create a new process.
return PpapiPluginProcessHost::CreateBrokerHost(*info);
@@ -317,11 +333,9 @@ bool PluginServiceImpl::GetPluginInfoByPath(const base::FilePath& plugin_path,
std::vector<WebPluginInfo> plugins;
PluginList::Singleton()->GetPluginsNoRefresh(&plugins);
- for (std::vector<WebPluginInfo>::iterator it = plugins.begin();
- it != plugins.end();
- ++it) {
- if (it->path == plugin_path) {
- *info = *it;
+ for (const WebPluginInfo& plugin : plugins) {
+ if (plugin.path == plugin_path) {
+ *info = plugin;
return true;
}
}
@@ -339,11 +353,11 @@ base::string16 PluginServiceImpl::GetPluginDisplayNameByPath(
#if defined(OS_MACOSX)
// Many plugins on the Mac have .plugin in the actual name, which looks
// terrible, so look for that and strip it off if present.
- const std::string kPluginExtension = ".plugin";
+ static const char kPluginExtension[] = ".plugin";
if (base::EndsWith(plugin_name, base::ASCIIToUTF16(kPluginExtension),
base::CompareCase::SENSITIVE))
- plugin_name.erase(plugin_name.length() - kPluginExtension.length());
-#endif // OS_MACOSX
+ plugin_name.erase(plugin_name.length() - strlen(kPluginExtension));
+#endif // defined(OS_MACOSX)
}
return plugin_name;
}
@@ -360,18 +374,18 @@ void PluginServiceImpl::GetPlugins(GetPluginsCallback callback) {
void PluginServiceImpl::RegisterPepperPlugins() {
ComputePepperPluginList(&ppapi_plugins_);
- for (size_t i = 0; i < ppapi_plugins_.size(); ++i) {
- RegisterInternalPlugin(ppapi_plugins_[i].ToWebPluginInfo(), true);
- }
+ for (const auto& plugin : ppapi_plugins_)
+ RegisterInternalPlugin(plugin.ToWebPluginInfo(), /*add_at_beginning=*/true);
}
// There should generally be very few plugins so a brute-force search is fine.
-PepperPluginInfo* PluginServiceImpl::GetRegisteredPpapiPluginInfo(
+const PepperPluginInfo* PluginServiceImpl::GetRegisteredPpapiPluginInfo(
const base::FilePath& plugin_path) {
- for (size_t i = 0; i < ppapi_plugins_.size(); ++i) {
- if (ppapi_plugins_[i].path == plugin_path)
- return &ppapi_plugins_[i];
+ for (auto& plugin : ppapi_plugins_) {
+ if (plugin.path == plugin_path)
+ return &plugin;
}
+
// We did not find the plugin in our list. But wait! the plugin can also
// be a latecomer, as it happens with pepper flash. This information
// can be obtained from the PluginList singleton and we can use it to
diff --git a/chromium/content/browser/plugin_service_impl.h b/chromium/content/browser/plugin_service_impl.h
index 4e11056a3dc..cb19abcd26b 100644
--- a/chromium/content/browser/plugin_service_impl.h
+++ b/chromium/content/browser/plugin_service_impl.h
@@ -35,14 +35,6 @@
#include "url/gurl.h"
#include "url/origin.h"
-#if defined(OS_WIN)
-#include "base/win/registry.h"
-#endif
-
-#if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID)
-#include "base/files/file_path_watcher.h"
-#endif
-
namespace content {
class BrowserContext;
class PluginServiceFilter;
@@ -76,7 +68,7 @@ class CONTENT_EXPORT PluginServiceImpl : public PluginService {
base::string16 GetPluginDisplayNameByPath(
const base::FilePath& path) override;
void GetPlugins(GetPluginsCallback callback) override;
- PepperPluginInfo* GetRegisteredPpapiPluginInfo(
+ const PepperPluginInfo* GetRegisteredPpapiPluginInfo(
const base::FilePath& plugin_path) override;
void SetFilter(PluginServiceFilter* filter) override;
PluginServiceFilter* GetFilter() override;
@@ -139,10 +131,6 @@ class CONTENT_EXPORT PluginServiceImpl : public PluginService {
PluginServiceImpl();
~PluginServiceImpl() override;
-#if defined(OS_WIN)
- void OnKeyChanged(base::win::RegKey* key);
-#endif
-
// Returns the plugin process host corresponding to the plugin process that
// has been started by this service. Returns NULL if no process has been
// started.
@@ -155,9 +143,6 @@ class CONTENT_EXPORT PluginServiceImpl : public PluginService {
void RegisterPepperPlugins();
- // Loads the plugins synchronously in a thread pool.
- std::vector<WebPluginInfo> GetPluginsInternal();
-
std::vector<PepperPluginInfo> ppapi_plugins_;
int max_ppapi_processes_per_profile_ = kDefaultMaxPpapiProcessesPerProfile;
diff --git a/chromium/content/browser/plugin_service_impl_unittest.cc b/chromium/content/browser/plugin_service_impl_unittest.cc
index ed9ec8c472b..6156e81e944 100644
--- a/chromium/content/browser/plugin_service_impl_unittest.cc
+++ b/chromium/content/browser/plugin_service_impl_unittest.cc
@@ -8,7 +8,6 @@
#include "build/build_config.h"
#include "components/ukm/test_ukm_recorder.h"
-#include "components/ukm/ukm_source.h"
#include "content/browser/ppapi_plugin_process_host.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_thread.h"
@@ -18,6 +17,7 @@
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/test_utils.h"
+#include "services/metrics/public/cpp/ukm_source.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
diff --git a/chromium/content/browser/pointer_lock_browsertest.cc b/chromium/content/browser/pointer_lock_browsertest.cc
index b4f10231ad3..d6eaf149a84 100644
--- a/chromium/content/browser/pointer_lock_browsertest.cc
+++ b/chromium/content/browser/pointer_lock_browsertest.cc
@@ -125,41 +125,27 @@ IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, PointerLock) {
FrameTreeNode* child = root->child_at(0);
// Request a pointer lock on the root frame's body.
- EXPECT_TRUE(ExecuteScript(root, "document.body.requestPointerLock()"));
+ EXPECT_TRUE(ExecJs(root, "document.body.requestPointerLock()"));
// Root frame should have been granted pointer lock.
- bool locked = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(root,
- "window.domAutomationController.send("
- "document.pointerLockElement == "
- "document.body);",
- &locked));
- EXPECT_TRUE(locked);
+ EXPECT_EQ(true, EvalJs(root, "document.pointerLockElement == document.body"));
// Request a pointer lock on the child frame's body.
- EXPECT_TRUE(ExecuteScript(child, "document.body.requestPointerLock()"));
+ EXPECT_TRUE(ExecJs(child, "document.body.requestPointerLock()"));
// Child frame should not be granted pointer lock since the root frame has it.
- EXPECT_TRUE(ExecuteScriptAndExtractBool(child,
- "window.domAutomationController.send("
- "document.pointerLockElement == "
- "document.body);",
- &locked));
- EXPECT_FALSE(locked);
+ EXPECT_EQ(false,
+ EvalJs(child, "document.pointerLockElement == document.body"));
// Release pointer lock on root frame.
- EXPECT_TRUE(ExecuteScript(root, "document.exitPointerLock()"));
+ EXPECT_TRUE(ExecJs(root, "document.exitPointerLock()"));
// Request a pointer lock on the child frame's body.
- EXPECT_TRUE(ExecuteScript(child, "document.body.requestPointerLock()"));
+ EXPECT_TRUE(ExecJs(child, "document.body.requestPointerLock()"));
// Child frame should have been granted pointer lock.
- EXPECT_TRUE(ExecuteScriptAndExtractBool(child,
- "window.domAutomationController.send("
- "document.pointerLockElement == "
- "document.body);",
- &locked));
- EXPECT_TRUE(locked);
+ EXPECT_EQ(true,
+ EvalJs(child, "document.pointerLockElement == document.body"));
}
IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, PointerLockEventRouting) {
@@ -179,19 +165,13 @@ IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, PointerLockEventRouting) {
WaitForHitTestDataOrChildSurfaceReady(child->current_frame_host());
// Request a pointer lock on the root frame's body.
- EXPECT_TRUE(ExecuteScript(root, "document.body.requestPointerLock()"));
+ EXPECT_TRUE(ExecJs(root, "document.body.requestPointerLock()"));
// Root frame should have been granted pointer lock.
- bool locked = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(root,
- "window.domAutomationController.send("
- "document.pointerLockElement == "
- "document.body);",
- &locked));
- EXPECT_TRUE(locked);
+ EXPECT_EQ(true, EvalJs(root, "document.pointerLockElement == document.body"));
// Add a mouse move event listener to the root frame.
- EXPECT_TRUE(ExecuteScript(
+ EXPECT_TRUE(ExecJs(
root,
"var x; var y; var mX; var mY; document.addEventListener('mousemove', "
"function(e) {x = e.x; y = e.y; mX = e.movementX; mY = e.movementY;});"));
@@ -208,36 +188,20 @@ IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, PointerLockEventRouting) {
MainThreadFrameObserver root_observer(root_view->GetRenderWidgetHost());
root_observer.Wait();
- int x, y, movementX, movementY;
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- root, "window.domAutomationController.send(x);", &x));
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- root, "window.domAutomationController.send(y);", &y));
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- root, "window.domAutomationController.send(mX);", &movementX));
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- root, "window.domAutomationController.send(mY);", &movementY));
- EXPECT_EQ(10, x);
- EXPECT_EQ(11, y);
- EXPECT_EQ(12, movementX);
- EXPECT_EQ(13, movementY);
+ EXPECT_EQ("[10,11,12,13]", EvalJs(root, "JSON.stringify([x,y,mX,mY])"));
// Release pointer lock on root frame.
- EXPECT_TRUE(ExecuteScript(root, "document.exitPointerLock()"));
+ EXPECT_TRUE(ExecJs(root, "document.exitPointerLock()"));
// Request a pointer lock on the child frame's body.
- EXPECT_TRUE(ExecuteScript(child, "document.body.requestPointerLock()"));
+ EXPECT_TRUE(ExecJs(child, "document.body.requestPointerLock()"));
// Child frame should have been granted pointer lock.
- EXPECT_TRUE(ExecuteScriptAndExtractBool(child,
- "window.domAutomationController.send("
- "document.pointerLockElement == "
- "document.body);",
- &locked));
- EXPECT_TRUE(locked);
+ EXPECT_EQ(true,
+ EvalJs(child, "document.pointerLockElement == document.body"));
// Add a mouse move event listener to the child frame.
- EXPECT_TRUE(ExecuteScript(
+ EXPECT_TRUE(ExecJs(
child,
"var x; var y; var mX; var mY; document.addEventListener('mousemove', "
"function(e) {x = e.x; y = e.y; mX = e.movementX; mY = e.movementY;});"));
@@ -259,18 +223,7 @@ IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, PointerLockEventRouting) {
MainThreadFrameObserver child_observer(child_view->GetRenderWidgetHost());
child_observer.Wait();
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- child, "window.domAutomationController.send(x);", &x));
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- child, "window.domAutomationController.send(y);", &y));
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- child, "window.domAutomationController.send(mX);", &movementX));
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- child, "window.domAutomationController.send(mY);", &movementY));
- EXPECT_EQ(14, x);
- EXPECT_EQ(15, y);
- EXPECT_EQ(16, movementX);
- EXPECT_EQ(17, movementY);
+ EXPECT_EQ("[14,15,16,17]", EvalJs(child, "JSON.stringify([x,y,mX,mY])"));
}
// Tests that the browser will not unlock the pointer if a RenderWidgetHostView
@@ -283,16 +236,10 @@ IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, PointerLockChildFrameDetached) {
FrameTreeNode* root = web_contents()->GetFrameTree()->root();
// Request a pointer lock on the root frame's body.
- EXPECT_TRUE(ExecuteScript(root, "document.body.requestPointerLock()"));
+ EXPECT_TRUE(ExecJs(root, "document.body.requestPointerLock()"));
// Root frame should have been granted pointer lock.
- bool locked = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(root,
- "window.domAutomationController.send("
- "document.pointerLockElement == "
- "document.body);",
- &locked));
- EXPECT_TRUE(locked);
+ EXPECT_EQ(true, EvalJs(root, "document.pointerLockElement == document.body"));
// Root (platform) RenderWidgetHostView should have the pointer locked.
EXPECT_TRUE(root->current_frame_host()->GetView()->IsMouseLocked());
@@ -300,7 +247,7 @@ IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, PointerLockChildFrameDetached) {
web_contents()->GetMouseLockWidget());
// Detach the child frame.
- EXPECT_TRUE(ExecuteScript(root, "document.querySelector('iframe').remove()"));
+ EXPECT_TRUE(ExecJs(root, "document.querySelector('iframe').remove()"));
// Root (platform) RenderWidgetHostView should still have the pointer locked.
EXPECT_TRUE(root->current_frame_host()->GetView()->IsMouseLocked());
@@ -333,21 +280,13 @@ IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest,
"c.com", "/cross_site_iframe_factory.html?c(d)")));
// Request a pointer lock to the inner WebContents's document.body.
- std::string result;
- EXPECT_TRUE(ExecuteScriptAndExtractString(inner_contents->GetMainFrame(), R"(
- (new Promise((resolve, reject) => {
+ EXPECT_EQ("success", EvalJs(inner_contents->GetMainFrame(), R"(
+ new Promise((resolve, reject) => {
document.addEventListener('pointerlockchange', resolve);
document.addEventListener('pointerlockerror', reject);
- }).then(() => {
- window.domAutomationController.send(
- (document.pointerLockElement == document.body) ?
- "success" : "error");
- }).catch(error => {
- window.domAutomationController.send("" + error);
- }));
- document.body.requestPointerLock();)",
- &result));
- EXPECT_EQ("success", result);
+ document.body.requestPointerLock();
+ }).then(() => 'success');
+ )"));
// Root (platform) RenderWidgetHostView should have the pointer locked.
EXPECT_TRUE(root->current_frame_host()->GetView()->IsMouseLocked());
@@ -397,21 +336,15 @@ IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, PointerLockWheelEventRouting) {
WaitForHitTestDataOrChildSurfaceReady(child->current_frame_host());
// Request a pointer lock on the root frame's body.
- EXPECT_TRUE(ExecuteScript(root, "document.body.requestPointerLock()"));
+ EXPECT_TRUE(ExecJs(root, "document.body.requestPointerLock()"));
// Root frame should have been granted pointer lock.
- bool locked = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(root,
- "window.domAutomationController.send("
- "document.pointerLockElement == "
- "document.body);",
- &locked));
- EXPECT_TRUE(locked);
+ EXPECT_EQ(true, EvalJs(root, "document.pointerLockElement == document.body"));
// Add a mouse move wheel event listener to the root frame.
- EXPECT_TRUE(ExecuteScript(
+ EXPECT_TRUE(ExecJs(
root,
- "var x; var y; var mX; var mY; document.addEventListener('mousewheel', "
+ "var x; var y; var dX; var dY; document.addEventListener('mousewheel', "
"function(e) {x = e.x; y = e.y; dX = e.deltaX; dY = e.deltaY;});"));
MainThreadFrameObserver root_observer(root_view->GetRenderWidgetHost());
root_observer.Wait();
@@ -439,38 +372,22 @@ IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, PointerLockWheelEventRouting) {
// Make sure that the renderer handled the input event.
root_observer.Wait();
- int x, y, deltaX, deltaY;
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- root, "window.domAutomationController.send(x);", &x));
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- root, "window.domAutomationController.send(y);", &y));
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- root, "window.domAutomationController.send(dX);", &deltaX));
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- root, "window.domAutomationController.send(dY);", &deltaY));
- EXPECT_EQ(10, x);
- EXPECT_EQ(11, y);
- EXPECT_EQ(12, deltaX);
- EXPECT_EQ(13, deltaY);
+ EXPECT_EQ("[10,11,12,13]", EvalJs(root, "JSON.stringify([x, y, dX, dY])"));
// Release pointer lock on root frame.
- EXPECT_TRUE(ExecuteScript(root, "document.exitPointerLock()"));
+ EXPECT_TRUE(ExecJs(root, "document.exitPointerLock()"));
// Request a pointer lock on the child frame's body.
- EXPECT_TRUE(ExecuteScript(child, "document.body.requestPointerLock()"));
+ EXPECT_TRUE(ExecJs(child, "document.body.requestPointerLock()"));
// Child frame should have been granted pointer lock.
- EXPECT_TRUE(ExecuteScriptAndExtractBool(child,
- "window.domAutomationController.send("
- "document.pointerLockElement == "
- "document.body);",
- &locked));
- EXPECT_TRUE(locked);
+ EXPECT_EQ(true,
+ EvalJs(child, "document.pointerLockElement == document.body"));
// Add a mouse move event listener to the child frame.
- EXPECT_TRUE(ExecuteScript(
+ EXPECT_TRUE(ExecJs(
child,
- "var x; var y; var mX; var mY; document.addEventListener('mousewheel', "
+ "var x; var y; var dX; var dY; document.addEventListener('mousewheel', "
"function(e) {x = e.x; y = e.y; dX = e.deltaX; dY = e.deltaY;});"));
MainThreadFrameObserver child_observer(child_view->GetRenderWidgetHost());
child_observer.Wait();
@@ -492,18 +409,7 @@ IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, PointerLockWheelEventRouting) {
// Make sure that the renderer handled the input event.
child_observer.Wait();
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- child, "window.domAutomationController.send(x);", &x));
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- child, "window.domAutomationController.send(y);", &y));
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- child, "window.domAutomationController.send(dX);", &deltaX));
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- child, "window.domAutomationController.send(dY);", &deltaY));
- EXPECT_EQ(14, x);
- EXPECT_EQ(15, y);
- EXPECT_EQ(16, deltaX);
- EXPECT_EQ(17, deltaY);
+ EXPECT_EQ("[14,15,16,17]", EvalJs(child, "JSON.stringify([x, y, dX, dY])"));
}
IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, PointerLockWidgetHidden) {
@@ -519,16 +425,11 @@ IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, PointerLockWidgetHidden) {
WaitForHitTestDataOrChildSurfaceReady(child->current_frame_host());
// Request a pointer lock on the child frame's body.
- EXPECT_TRUE(ExecuteScript(child, "document.body.requestPointerLock()"));
+ EXPECT_TRUE(ExecJs(child, "document.body.requestPointerLock()"));
// Child frame should have been granted pointer lock.
- bool locked = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(child,
- "window.domAutomationController.send("
- "document.pointerLockElement == "
- "document.body);",
- &locked));
- EXPECT_TRUE(locked);
+ EXPECT_EQ(true,
+ EvalJs(child, "document.pointerLockElement == document.body"));
EXPECT_TRUE(child_view->IsMouseLocked());
EXPECT_EQ(child_view->host(), web_contents()->GetMouseLockWidget());
diff --git a/chromium/content/browser/portal/portal.cc b/chromium/content/browser/portal/portal.cc
new file mode 100644
index 00000000000..14430222d47
--- /dev/null
+++ b/chromium/content/browser/portal/portal.cc
@@ -0,0 +1,77 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/portal/portal.h"
+
+#include "base/feature_list.h"
+#include "base/memory/ptr_util.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_switches.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "third_party/blink/public/common/features.h"
+
+namespace content {
+
+Portal::Portal(RenderFrameHostImpl* owner_render_frame_host)
+ : WebContentsObserver(
+ WebContents::FromRenderFrameHost(owner_render_frame_host)),
+ owner_render_frame_host_(owner_render_frame_host),
+ portal_token_(base::UnguessableToken::Create()) {}
+
+Portal::~Portal() {}
+
+// static
+bool Portal::IsEnabled() {
+ return base::FeatureList::IsEnabled(blink::features::kPortals) ||
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExperimentalWebPlatformFeatures);
+}
+
+// static
+Portal* Portal::Create(RenderFrameHostImpl* owner_render_frame_host,
+ blink::mojom::PortalRequest request) {
+ auto portal_ptr = base::WrapUnique(new Portal(owner_render_frame_host));
+ Portal* portal = portal_ptr.get();
+ portal->binding_ =
+ mojo::MakeStrongBinding(std::move(portal_ptr), std::move(request));
+ return portal;
+}
+
+// static
+std::unique_ptr<Portal> Portal::CreateForTesting(
+ RenderFrameHostImpl* owner_render_frame_host) {
+ return base::WrapUnique(new Portal(owner_render_frame_host));
+}
+
+void Portal::Init(
+ base::OnceCallback<void(const base::UnguessableToken&)> callback) {
+ std::move(callback).Run(portal_token_);
+ WebContents::CreateParams params(
+ WebContents::FromRenderFrameHost(owner_render_frame_host_)
+ ->GetBrowserContext());
+ portal_contents_ = WebContents::Create(params);
+}
+
+void Portal::Navigate(const GURL& url) {
+ NavigationController::LoadURLParams load_url_params(url);
+ portal_contents_->GetController().LoadURLWithParams(load_url_params);
+}
+
+void Portal::RenderFrameDeleted(RenderFrameHost* render_frame_host) {
+ if (render_frame_host == owner_render_frame_host_)
+ binding_->Close(); // Also deletes |this|.
+}
+
+WebContents* Portal::GetPortalContents() {
+ return portal_contents_.get();
+}
+
+void Portal::SetBindingForTesting(
+ mojo::StrongBindingPtr<blink::mojom::Portal> binding) {
+ binding_ = binding;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/portal/portal.h b/chromium/content/browser/portal/portal.h
new file mode 100644
index 00000000000..f894cb7d65c
--- /dev/null
+++ b/chromium/content/browser/portal/portal.h
@@ -0,0 +1,78 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_PORTAL_PORTAL_H_
+#define CONTENT_BROWSER_PORTAL_PORTAL_H_
+
+#include <memory>
+
+#include "content/common/content_export.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "third_party/blink/public/mojom/portal/portal.mojom.h"
+
+namespace content {
+
+class RenderFrameHostImpl;
+
+// A Portal provides a way to embed a WebContents inside a frame in another
+// WebContents. It also provides an API that the owning frame can interact with
+// the portal WebContents. The portal can be activated, where the portal
+// WebContents replaces the outer WebContents and inherit it as a new Portal.
+//
+// The Portal is owned by its mojo binding, so it is kept alive as long as the
+// other end of the pipe (typically in the renderer) exists.
+class CONTENT_EXPORT Portal : public blink::mojom::Portal,
+ public WebContentsObserver {
+ public:
+ ~Portal() override;
+
+ static bool IsEnabled();
+
+ // Creates a Portal and binds it to the pipe specified in the |request|. This
+ // function creates a strong binding, so the ownership of the Portal is
+ // delegated to the binding.
+ static Portal* Create(RenderFrameHostImpl* owner_render_frame_host,
+ blink::mojom::PortalRequest request);
+
+ // Creates a portal without binding it to any pipe. Only used in tests.
+ static std::unique_ptr<Portal> CreateForTesting(
+ RenderFrameHostImpl* owner_render_frame_host);
+
+ // blink::mojom::Portal implementation.
+ void Init(base::OnceCallback<void(const base::UnguessableToken&)> callback)
+ override;
+ void Navigate(const GURL& url) override;
+
+ // WebContentsObserver overrides.
+ void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
+
+ // Returns the Portal's WebContents.
+ WebContents* GetPortalContents();
+
+ // Gets/sets the mojo binding. Only used in tests.
+ mojo::StrongBindingPtr<blink::mojom::Portal> GetBindingForTesting() {
+ return binding_;
+ }
+ void SetBindingForTesting(
+ mojo::StrongBindingPtr<blink::mojom::Portal> binding);
+
+ private:
+ explicit Portal(RenderFrameHostImpl* owner_render_frame_host);
+
+ RenderFrameHostImpl* owner_render_frame_host_;
+
+ // Uniquely identifies the portal, this token is used by the browser process
+ // to reference this portal when communicating with the renderer.
+ base::UnguessableToken portal_token_;
+
+ // WeakPtr to StrongBinding.
+ mojo::StrongBindingPtr<blink::mojom::Portal> binding_;
+
+ std::unique_ptr<WebContents> portal_contents_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_PORTAL_PORTAL_H_
diff --git a/chromium/content/browser/portal/portal_browsertest.cc b/chromium/content/browser/portal/portal_browsertest.cc
new file mode 100644
index 00000000000..a9a661e8b7b
--- /dev/null
+++ b/chromium/content/browser/portal/portal_browsertest.cc
@@ -0,0 +1,255 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/test/scoped_feature_list.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/portal/portal.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/test_navigation_observer.h"
+#include "content/shell/browser/shell.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/mojom/portal/portal.mojom.h"
+#include "url/url_constants.h"
+
+namespace content {
+
+// The PortalInterceptorForTesting can be used in tests to inspect Portal IPCs.
+class PortalInterceptorForTesting final
+ : public blink::mojom::PortalInterceptorForTesting {
+ public:
+ static PortalInterceptorForTesting* Create(
+ RenderFrameHostImpl* render_frame_host_impl,
+ blink::mojom::PortalRequest request);
+ static PortalInterceptorForTesting* From(content::Portal* portal);
+
+ void Init(InitCallback callback) override {
+ portal_->Init(std::move(callback));
+
+ // Init should be called only once.
+ ASSERT_FALSE(portal_initialized_);
+ portal_initialized_ = true;
+
+ if (run_loop_)
+ run_loop_->Quit();
+ }
+
+ void WaitForInit() {
+ if (portal_initialized_)
+ return;
+
+ base::RunLoop run_loop;
+ run_loop_ = &run_loop;
+ run_loop.Run();
+ run_loop_ = nullptr;
+ }
+
+ // Test getters.
+ content::Portal* GetPortal() { return portal_.get(); }
+ WebContents* GetPortalContents() { return portal_->GetPortalContents(); }
+
+ private:
+ PortalInterceptorForTesting(RenderFrameHostImpl* render_frame_host_impl)
+ : portal_(content::Portal::CreateForTesting(render_frame_host_impl)) {}
+
+ blink::mojom::Portal* GetForwardingInterface() override {
+ return portal_.get();
+ }
+
+ std::unique_ptr<content::Portal> portal_;
+ bool portal_initialized_ = false;
+ base::RunLoop* run_loop_ = nullptr;
+};
+
+// static
+PortalInterceptorForTesting* PortalInterceptorForTesting::Create(
+ RenderFrameHostImpl* render_frame_host_impl,
+ blink::mojom::PortalRequest request) {
+ auto test_portal_ptr =
+ base::WrapUnique(new PortalInterceptorForTesting(render_frame_host_impl));
+ PortalInterceptorForTesting* test_portal = test_portal_ptr.get();
+ test_portal->GetPortal()->SetBindingForTesting(
+ mojo::MakeStrongBinding(std::move(test_portal_ptr), std::move(request)));
+ return test_portal;
+}
+
+// static
+PortalInterceptorForTesting* PortalInterceptorForTesting::From(
+ content::Portal* portal) {
+ blink::mojom::Portal* impl = portal->GetBindingForTesting()->impl();
+ auto* interceptor = static_cast<PortalInterceptorForTesting*>(impl);
+ CHECK_NE(static_cast<blink::mojom::Portal*>(portal), impl);
+ CHECK_EQ(interceptor->GetPortal(), portal);
+ return interceptor;
+}
+
+// The PortalCreatedObserver observes portal creations on
+// |render_frame_host_impl|. This observer can be used to monitor for multiple
+// Portal creations on the same RenderFrameHost, by repeatedly calling
+// WaitUntilPortalCreated().
+//
+// The PortalCreatedObserver replaces the Portal interface in the
+// RenderFrameHosts' BinderRegistry, so when the observer is destroyed the
+// RenderFrameHost is left without an interface and attempts to create the
+// interface will fail.
+class PortalCreatedObserver {
+ public:
+ explicit PortalCreatedObserver(RenderFrameHostImpl* render_frame_host_impl)
+ : render_frame_host_impl_(render_frame_host_impl) {
+ service_manager::BinderRegistry& registry =
+ render_frame_host_impl->BinderRegistryForTesting();
+
+ registry.AddInterface(base::BindRepeating(
+ [](PortalCreatedObserver* observer,
+ RenderFrameHostImpl* render_frame_host_impl,
+ blink::mojom::PortalRequest request) {
+ observer->portal_ = PortalInterceptorForTesting::Create(
+ render_frame_host_impl, std::move(request))
+ ->GetPortal();
+ if (observer->run_loop_)
+ observer->run_loop_->Quit();
+ },
+ base::Unretained(this), base::Unretained(render_frame_host_impl)));
+ }
+
+ ~PortalCreatedObserver() {
+ service_manager::BinderRegistry& registry =
+ render_frame_host_impl_->BinderRegistryForTesting();
+
+ registry.RemoveInterface<Portal>();
+ }
+
+ Portal* WaitUntilPortalCreated() {
+ Portal* portal = portal_;
+ if (portal) {
+ portal_ = nullptr;
+ return portal;
+ }
+
+ base::RunLoop run_loop;
+ run_loop_ = &run_loop;
+ run_loop.Run();
+ run_loop_ = nullptr;
+
+ portal = portal_;
+ portal_ = nullptr;
+ return portal;
+ }
+
+ private:
+ RenderFrameHostImpl* render_frame_host_impl_;
+ base::RunLoop* run_loop_ = nullptr;
+ Portal* portal_ = nullptr;
+};
+
+class PortalBrowserTest : public ContentBrowserTest {
+ protected:
+ PortalBrowserTest() {}
+
+ void SetUp() override {
+ scoped_feature_list_.InitAndEnableFeature(blink::features::kPortals);
+ ContentBrowserTest::SetUp();
+ }
+
+ void SetUpOnMainThread() override {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ContentBrowserTest::SetUpOnMainThread();
+ ASSERT_TRUE(embedded_test_server()->Start());
+ }
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+// Tests that the renderer can create a Portal.
+IN_PROC_BROWSER_TEST_F(PortalBrowserTest, CreatePortal) {
+ EXPECT_TRUE(NavigateToURL(
+ shell(), embedded_test_server()->GetURL("portal.test", "/title1.html")));
+ WebContentsImpl* web_contents_impl =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ RenderFrameHostImpl* main_frame = web_contents_impl->GetMainFrame();
+
+ PortalCreatedObserver portal_created_observer(main_frame);
+ EXPECT_TRUE(
+ ExecJs(main_frame,
+ "document.body.appendChild(document.createElement('portal'));"));
+ Portal* portal = portal_created_observer.WaitUntilPortalCreated();
+ EXPECT_NE(nullptr, portal);
+}
+
+// Tests the the renderer can navigate a Portal.
+IN_PROC_BROWSER_TEST_F(PortalBrowserTest, NavigatePortal) {
+ EXPECT_TRUE(NavigateToURL(
+ shell(), embedded_test_server()->GetURL("portal.test", "/title1.html")));
+ WebContentsImpl* web_contents_impl =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ RenderFrameHostImpl* main_frame = web_contents_impl->GetMainFrame();
+
+ PortalCreatedObserver portal_created_observer(main_frame);
+
+ // Tests that a portal can navigate by setting its src before appending it to
+ // the DOM.
+ GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
+ EXPECT_TRUE(
+ ExecJs(main_frame,
+ base::StringPrintf("var portal = document.createElement('portal');"
+ "portal.src = '%s';"
+ "document.body.appendChild(portal);",
+ a_url.spec().c_str())));
+
+ PortalInterceptorForTesting* portal_interceptor =
+ PortalInterceptorForTesting::From(
+ portal_created_observer.WaitUntilPortalCreated());
+ portal_interceptor->WaitForInit();
+ WebContents* portal_contents = portal_interceptor->GetPortalContents();
+ EXPECT_NE(nullptr, portal_contents);
+ EXPECT_NE(portal_contents->GetLastCommittedURL(), a_url);
+
+ // WaitForInit() above only waits for the Portal::Init call, which is when the
+ // Portal's WebContents is created. Portal::Navigate is a diffent IPC, so the
+ // portal should not have navigated yet, and we can observe the Portal's first
+ // navigation.
+ TestNavigationObserver navigation_observer(portal_contents);
+ navigation_observer.Wait();
+ EXPECT_EQ(navigation_observer.last_navigation_url(), a_url);
+ EXPECT_EQ(portal_contents->GetLastCommittedURL(), a_url);
+
+ // Tests that a portal can navigate by setting its src.
+ {
+ TestNavigationObserver navigation_observer(portal_contents);
+
+ GURL b_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
+ EXPECT_TRUE(ExecJs(
+ main_frame,
+ base::StringPrintf("document.querySelector('portal').src = '%s';",
+ b_url.spec().c_str())));
+ navigation_observer.Wait();
+ EXPECT_EQ(navigation_observer.last_navigation_url(), b_url);
+ EXPECT_EQ(portal_contents->GetLastCommittedURL(), b_url);
+ }
+
+ // Tests that a portal can navigating by attribute.
+ {
+ TestNavigationObserver navigation_observer(portal_contents);
+
+ GURL c_url(embedded_test_server()->GetURL("c.com", "/title1.html"));
+ EXPECT_TRUE(ExecJs(
+ main_frame,
+ base::StringPrintf(
+ "document.querySelector('portal').setAttribute('src', '%s');",
+ c_url.spec().c_str())));
+ navigation_observer.Wait();
+ EXPECT_EQ(navigation_observer.last_navigation_url(), c_url);
+ EXPECT_EQ(portal_contents->GetLastCommittedURL(), c_url);
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/portal/portal_unit_test.cc b/chromium/content/browser/portal/portal_unit_test.cc
new file mode 100644
index 00000000000..4f4aea46ada
--- /dev/null
+++ b/chromium/content/browser/portal/portal_unit_test.cc
@@ -0,0 +1,35 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/feature_list.h"
+#include "base/test/scoped_feature_list.h"
+#include "content/browser/portal/portal.h"
+#include "content/test/test_render_frame_host.h"
+#include "content/test/test_render_view_host.h"
+#include "content/test/test_web_contents.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
+
+namespace content {
+
+class PortalUnitTest : public RenderViewHostImplTestHarness {
+ protected:
+ void SetUp() override {
+ scoped_feature_list_.InitAndEnableFeature(blink::features::kPortals);
+ RenderViewHostImplTestHarness::SetUp();
+ }
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+TEST_F(PortalUnitTest, InterfaceExists) {
+ ASSERT_TRUE(base::FeatureList::IsEnabled(blink::features::kPortals));
+
+ ASSERT_TRUE(contents()->GetMainFrame()->binder_registry().CanBindInterface(
+ blink::mojom::Portal::Name_));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/ppapi_plugin_process_host.cc b/chromium/content/browser/ppapi_plugin_process_host.cc
index 3cf4e5d1f53..1df1149921b 100644
--- a/chromium/content/browser/ppapi_plugin_process_host.cc
+++ b/chromium/content/browser/ppapi_plugin_process_host.cc
@@ -509,8 +509,8 @@ void PpapiPluginProcessHost::OnRendererPluginChannelCreated(
sent_requests_.pop();
const ChildProcessData& data = process_->GetData();
- client->OnPpapiChannelOpened(channel_handle, base::GetProcId(data.handle),
- data.id);
+ client->OnPpapiChannelOpened(channel_handle,
+ base::GetProcId(data.GetHandle()), data.id);
}
} // namespace content
diff --git a/chromium/content/browser/presentation/OWNERS b/chromium/content/browser/presentation/OWNERS
index 4c81ef2dbac..1a85e3fd162 100644
--- a/chromium/content/browser/presentation/OWNERS
+++ b/chromium/content/browser/presentation/OWNERS
@@ -1,9 +1,4 @@
# Presentation API OWNERS
-#
-# This file also covers ownership of the following directories:
-# //content/common/presentation/
-# //content/renderer/presentation/
-
imcheng@chromium.org
mfoltz@chromium.org
mlamouri@chromium.org
diff --git a/chromium/content/browser/presentation/presentation_service_impl.cc b/chromium/content/browser/presentation/presentation_service_impl.cc
index 321adbda8a1..7d2bd5d9a73 100644
--- a/chromium/content/browser/presentation/presentation_service_impl.cc
+++ b/chromium/content/browser/presentation/presentation_service_impl.cc
@@ -21,7 +21,6 @@
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/frame_navigate_params.h"
-#include "content/public/common/presentation_connection_message.h"
using blink::mojom::PresentationConnectionState;
using blink::mojom::PresentationError;
@@ -46,7 +45,7 @@ int GetNextRequestId() {
void InvokeNewPresentationCallbackWithError(
PresentationServiceImpl::NewPresentationCallback callback) {
std::move(callback).Run(
- PresentationInfoPtr(),
+ /** PresentationConnectionResultPtr */ nullptr,
PresentationError::New(
PresentationErrorType::PREVIOUS_START_IN_PROGRESS,
"There is already an unsettled Promise from a previous call "
@@ -211,7 +210,7 @@ void PresentationServiceImpl::StartPresentation(
DVLOG(2) << "StartPresentation";
if (!controller_delegate_) {
std::move(callback).Run(
- PresentationInfoPtr(),
+ /** PresentationConnectionResultPtr */ nullptr,
PresentationError::New(PresentationErrorType::NO_AVAILABLE_SCREENS,
"No screens found."));
return;
@@ -247,7 +246,7 @@ void PresentationServiceImpl::ReconnectPresentation(
DVLOG(2) << "ReconnectPresentation";
if (!controller_delegate_) {
std::move(callback).Run(
- PresentationInfoPtr(),
+ /** PresentationConnectionResultPtr */ nullptr,
PresentationError::New(PresentationErrorType::NO_PRESENTATION_FOUND,
"Error joining route: No matching route"));
return;
@@ -296,14 +295,15 @@ void PresentationServiceImpl::ListenForConnectionStateChange(
void PresentationServiceImpl::OnStartPresentationSucceeded(
int request_id,
- const PresentationInfo& presentation_info) {
+ blink::mojom::PresentationConnectionResultPtr result) {
if (request_id != start_presentation_request_id_)
return;
- CHECK(pending_start_presentation_cb_.get());
+ auto presentation_info = *result->presentation_info;
+ DCHECK(pending_start_presentation_cb_.get());
DCHECK(presentation_info.id.length() <= kMaxPresentationIdLength);
- pending_start_presentation_cb_->Run(PresentationInfo::New(presentation_info),
- PresentationErrorPtr());
+ pending_start_presentation_cb_->Run(std::move(result),
+ /** PresentationErrorPtr */ nullptr);
ListenForConnectionStateChange(presentation_info);
pending_start_presentation_cb_.reset();
start_presentation_request_id_ = kInvalidRequestId;
@@ -316,19 +316,19 @@ void PresentationServiceImpl::OnStartPresentationError(
return;
CHECK(pending_start_presentation_cb_.get());
- pending_start_presentation_cb_->Run(PresentationInfoPtr(),
- PresentationError::New(error));
+ pending_start_presentation_cb_->Run(
+ /** PresentationConnectionResultPtr */ nullptr,
+ PresentationError::New(error));
pending_start_presentation_cb_.reset();
start_presentation_request_id_ = kInvalidRequestId;
}
void PresentationServiceImpl::OnReconnectPresentationSucceeded(
int request_id,
- const PresentationInfo& presentation_info) {
- DCHECK(presentation_info.id.length() <= kMaxPresentationIdLength);
+ blink::mojom::PresentationConnectionResultPtr result) {
+ auto presentation_info = *result->presentation_info;
if (RunAndEraseReconnectPresentationMojoCallback(
- request_id, PresentationInfo::New(presentation_info),
- PresentationErrorPtr())) {
+ request_id, std::move(result), /** PresentationErrorPtr */ nullptr)) {
ListenForConnectionStateChange(presentation_info);
}
}
@@ -337,19 +337,20 @@ void PresentationServiceImpl::OnReconnectPresentationError(
int request_id,
const blink::mojom::PresentationError& error) {
RunAndEraseReconnectPresentationMojoCallback(
- request_id, PresentationInfoPtr(), PresentationError::New(error));
+ request_id, blink::mojom::PresentationConnectionResultPtr(),
+ PresentationError::New(error));
}
bool PresentationServiceImpl::RunAndEraseReconnectPresentationMojoCallback(
int request_id,
- PresentationInfoPtr presentation_info,
- PresentationErrorPtr error) {
+ blink::mojom::PresentationConnectionResultPtr result,
+ blink::mojom::PresentationErrorPtr error) {
auto it = pending_reconnect_presentation_cbs_.find(request_id);
if (it == pending_reconnect_presentation_cbs_.end())
return false;
DCHECK(it->second.get());
- it->second->Run(std::move(presentation_info), std::move(error));
+ it->second->Run(std::move(result), std::move(error));
pending_reconnect_presentation_cbs_.erase(it);
return true;
}
@@ -428,21 +429,7 @@ PresentationServiceImpl::GetPresentationServiceDelegate() {
: static_cast<PresentationServiceDelegate*>(controller_delegate_);
}
-void PresentationServiceImpl::SetPresentationConnection(
- PresentationInfoPtr presentation_info,
- blink::mojom::PresentationConnectionPtr controller_connection_ptr,
- blink::mojom::PresentationConnectionRequest receiver_connection_request) {
- DVLOG(2) << "SetPresentationConnection";
-
- if (!controller_delegate_)
- return;
-
- controller_delegate_->ConnectToPresentation(
- render_process_id_, render_frame_id_, *presentation_info,
- std::move(controller_connection_ptr),
- std::move(receiver_connection_request));
-}
-
+// TODO(btolsch): Convert to PresentationConnectionResultPtr.
void PresentationServiceImpl::OnReceiverConnectionAvailable(
PresentationInfoPtr presentation_info,
PresentationConnectionPtr controller_connection_ptr,
@@ -503,12 +490,14 @@ void PresentationServiceImpl::OnDelegateDestroyed() {
}
void PresentationServiceImpl::OnDefaultPresentationStarted(
- const PresentationInfo& connection) {
+ blink::mojom::PresentationConnectionResultPtr result) {
+ auto presentation_info = *result->presentation_info;
if (controller_)
- controller_->OnDefaultPresentationStarted(
- PresentationInfo::New(connection));
+ controller_->OnDefaultPresentationStarted(std::move(result));
- ListenForConnectionStateChange(connection);
+ // TODO(btolsch): Remove the state-change API in favor of direct
+ // PresentationConnection state use.
+ ListenForConnectionStateChange(presentation_info);
}
PresentationServiceImpl::ScreenAvailabilityListenerImpl::
@@ -543,7 +532,7 @@ PresentationServiceImpl::NewPresentationCallbackWrapper::
~NewPresentationCallbackWrapper() {
if (!callback_.is_null()) {
std::move(callback_).Run(
- PresentationInfoPtr(),
+ /** PresentationConnectionResultPtr */ nullptr,
PresentationError::New(
PresentationErrorType::PRESENTATION_REQUEST_CANCELLED,
"The frame is navigating or being destroyed."));
@@ -551,10 +540,10 @@ PresentationServiceImpl::NewPresentationCallbackWrapper::
}
void PresentationServiceImpl::NewPresentationCallbackWrapper::Run(
- PresentationInfoPtr presentation_info,
- PresentationErrorPtr error) {
+ blink::mojom::PresentationConnectionResultPtr result,
+ blink::mojom::PresentationErrorPtr error) {
DCHECK(!callback_.is_null());
- std::move(callback_).Run(std::move(presentation_info), std::move(error));
+ std::move(callback_).Run(std::move(result), std::move(error));
}
} // namespace content
diff --git a/chromium/content/browser/presentation/presentation_service_impl.h b/chromium/content/browser/presentation/presentation_service_impl.h
index 333d2ac479c..a9cc97e4a12 100644
--- a/chromium/content/browser/presentation/presentation_service_impl.h
+++ b/chromium/content/browser/presentation/presentation_service_impl.h
@@ -24,12 +24,11 @@
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/frame_navigate_params.h"
#include "mojo/public/cpp/bindings/binding.h"
-#include "third_party/blink/public/platform/modules/presentation/presentation.mojom.h"
+#include "third_party/blink/public/mojom/presentation/presentation.mojom.h"
#include "url/gurl.h"
namespace content {
-struct PresentationConnectionMessage;
class RenderFrameHost;
// Implementation of Mojo PresentationService.
@@ -45,7 +44,6 @@ class RenderFrameHost;
// Create()
// SetClient()
// StartPresentation()
-// SetPresentationConnection()
// ...
// TODO(crbug.com/749327): Split the controller and receiver logic into separate
// classes so that each is easier to reason about.
@@ -55,7 +53,7 @@ class CONTENT_EXPORT PresentationServiceImpl
public PresentationServiceDelegate::Observer {
public:
using NewPresentationCallback =
- base::OnceCallback<void(blink::mojom::PresentationInfoPtr,
+ base::OnceCallback<void(blink::mojom::PresentationConnectionResultPtr,
blink::mojom::PresentationErrorPtr)>;
// Creates a PresentationServiceImpl using the given RenderFrameHost.
@@ -85,11 +83,6 @@ class CONTENT_EXPORT PresentationServiceImpl
const std::string& presentation_id) override;
void Terminate(const GURL& presentation_url,
const std::string& presentation_id) override;
- void SetPresentationConnection(
- blink::mojom::PresentationInfoPtr presentation_info,
- blink::mojom::PresentationConnectionPtr controller_connection_ptr,
- blink::mojom::PresentationConnectionRequest receiver_connection_request)
- override;
private:
friend class PresentationServiceImplTest;
@@ -113,9 +106,6 @@ class CONTENT_EXPORT PresentationServiceImpl
// Maximum number of pending ReconnectPresentation requests at any given time.
static const int kMaxQueuedRequests = 10;
- using ConnectionMessagesCallback =
- base::OnceCallback<void(std::vector<PresentationConnectionMessage>)>;
-
// Listener implementation owned by PresentationServiceImpl. An instance of
// this is created when PresentationRequest.getAvailability() is resolved.
// The instance receives screen availability results from the embedder and
@@ -144,7 +134,7 @@ class CONTENT_EXPORT PresentationServiceImpl
explicit NewPresentationCallbackWrapper(NewPresentationCallback callback);
~NewPresentationCallbackWrapper();
- void Run(blink::mojom::PresentationInfoPtr presentation_info,
+ void Run(blink::mojom::PresentationConnectionResultPtr result,
blink::mojom::PresentationErrorPtr error);
private:
@@ -178,16 +168,16 @@ class CONTENT_EXPORT PresentationServiceImpl
// Passed to embedder's implementation of PresentationServiceDelegate for
// later invocation when default presentation has started.
void OnDefaultPresentationStarted(
- const blink::mojom::PresentationInfo& presentation_info);
+ blink::mojom::PresentationConnectionResultPtr result);
// Finds the callback from |pending_reconnect_presentation_cbs_| using
// |request_id|.
- // If it exists, invoke it with |presentation_info| and |error|, then erase it
+ // If it exists, invoke it with |result| and |error|, then erase it
// from |pending_reconnect_presentation_cbs_|. Returns true if the callback
// was found.
bool RunAndEraseReconnectPresentationMojoCallback(
int request_id,
- blink::mojom::PresentationInfoPtr presentation_info,
+ blink::mojom::PresentationConnectionResultPtr result,
blink::mojom::PresentationErrorPtr error);
// Removes all listeners and resets default presentation URL on this instance
@@ -199,12 +189,12 @@ class CONTENT_EXPORT PresentationServiceImpl
// invocation.
void OnStartPresentationSucceeded(
int request_id,
- const blink::mojom::PresentationInfo& presentation_info);
+ blink::mojom::PresentationConnectionResultPtr result);
void OnStartPresentationError(int request_id,
const blink::mojom::PresentationError& error);
void OnReconnectPresentationSucceeded(
int request_id,
- const blink::mojom::PresentationInfo& presentation_info);
+ blink::mojom::PresentationConnectionResultPtr result);
void OnReconnectPresentationError(
int request_id,
const blink::mojom::PresentationError& error);
@@ -214,12 +204,6 @@ class CONTENT_EXPORT PresentationServiceImpl
void ListenForConnectionStateChange(
const blink::mojom::PresentationInfo& connection);
- // Passed to embedder's implementation of PresentationServiceDelegate for
- // later invocation when connection messages arrive.
- void OnConnectionMessages(
- const blink::mojom::PresentationInfo& presentation_info,
- std::vector<content::PresentationConnectionMessage> messages);
-
// A callback registered to LocalPresentationManager when
// the PresentationServiceImpl for the presentation receiver is initialized.
// Calls |receiver_| to create a new PresentationConnection on receiver page.
diff --git a/chromium/content/browser/presentation/presentation_service_impl_unittest.cc b/chromium/content/browser/presentation/presentation_service_impl_unittest.cc
index a635d4413a8..51fd39f10ab 100644
--- a/chromium/content/browser/presentation/presentation_service_impl_unittest.cc
+++ b/chromium/content/browser/presentation/presentation_service_impl_unittest.cc
@@ -17,16 +17,24 @@
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/presentation_request.h"
#include "content/public/browser/presentation_service_delegate.h"
-#include "content/public/common/presentation_connection_message.h"
#include "content/test/test_render_frame_host.h"
#include "content/test/test_render_view_host.h"
#include "content/test/test_web_contents.h"
#include "mojo/public/cpp/bindings/interface_ptr.h"
#include "testing/gmock/include/gmock/gmock.h"
+using blink::mojom::PresentationConnection;
using blink::mojom::PresentationConnectionCloseReason;
+using blink::mojom::PresentationConnectionMessagePtr;
+using blink::mojom::PresentationConnectionPtr;
+using blink::mojom::PresentationConnectionPtrInfo;
+using blink::mojom::PresentationConnectionResult;
+using blink::mojom::PresentationConnectionResultPtr;
using blink::mojom::PresentationConnectionState;
+using blink::mojom::PresentationController;
+using blink::mojom::PresentationControllerPtr;
using blink::mojom::PresentationError;
+using blink::mojom::PresentationErrorPtr;
using blink::mojom::PresentationErrorType;
using blink::mojom::PresentationInfo;
using blink::mojom::PresentationInfoPtr;
@@ -52,6 +60,11 @@ MATCHER_P(InfoEquals, expected, "") {
return expected.url == arg.url && expected.id == arg.id;
}
+// Matches blink::mojom::PresentationInfoPtr.
+MATCHER_P(InfoPtrEquals, expected, "") {
+ return expected.url == arg->url && expected.id == arg->id;
+}
+
ACTION_TEMPLATE(SaveArgByMove,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_1_VALUE_PARAMS(pointer)) {
@@ -73,7 +86,7 @@ class MockPresentationServiceDelegate
int render_frame_id,
PresentationServiceDelegate::Observer* observer));
MOCK_METHOD2(RemoveObserver,
- void(int render_process_id, int render_frame_id));
+ void(int render_process_id, int render_frame_id));
bool AddScreenAvailabilityListener(
int render_process_id,
@@ -88,41 +101,22 @@ class MockPresentationServiceDelegate
MOCK_METHOD0(AddScreenAvailabilityListener, bool());
MOCK_METHOD3(RemoveScreenAvailabilityListener,
- void(int render_process_id,
- int routing_id,
- PresentationScreenAvailabilityListener* listener));
- MOCK_METHOD2(Reset,
- void(int render_process_id,
- int routing_id));
+ void(int render_process_id,
+ int routing_id,
+ PresentationScreenAvailabilityListener* listener));
+ MOCK_METHOD2(Reset, void(int render_process_id, int routing_id));
MOCK_METHOD2(SetDefaultPresentationUrls,
void(const PresentationRequest& request,
DefaultPresentationConnectionCallback callback));
-
- // TODO(crbug.com/729950): Use MOCK_METHOD directly once GMock gets the
- // move-only type support.
- void StartPresentation(
- const PresentationRequest& request,
- PresentationConnectionCallback success_cb,
- PresentationConnectionErrorCallback error_cb) override {
- StartPresentationInternal(request, success_cb, error_cb);
- }
- MOCK_METHOD3(StartPresentationInternal,
+ MOCK_METHOD3(StartPresentation,
void(const PresentationRequest& request,
- PresentationConnectionCallback& success_cb,
- PresentationConnectionErrorCallback& error_cb));
- void ReconnectPresentation(
- const PresentationRequest& request,
- const std::string& presentation_id,
- PresentationConnectionCallback success_cb,
- PresentationConnectionErrorCallback error_cb) override {
- ReconnectPresentationInternal(request, presentation_id, success_cb,
- error_cb);
- }
- MOCK_METHOD4(ReconnectPresentationInternal,
+ PresentationConnectionCallback success_cb,
+ PresentationConnectionErrorCallback error_cb));
+ MOCK_METHOD4(ReconnectPresentation,
void(const PresentationRequest& request,
const std::string& presentation_id,
- PresentationConnectionCallback& success_cb,
- PresentationConnectionErrorCallback& error_cb));
+ PresentationConnectionCallback success_cb,
+ PresentationConnectionErrorCallback error_cb));
MOCK_METHOD3(CloseConnection,
void(int render_process_id,
int render_frame_id,
@@ -131,30 +125,17 @@ class MockPresentationServiceDelegate
void(int render_process_id,
int render_frame_id,
const std::string& presentation_id));
- MOCK_METHOD3(GetMediaController,
- std::unique_ptr<media::MediaController>(
+ MOCK_METHOD3(GetFlingingController,
+ std::unique_ptr<media::FlingingController>(
int render_process_id,
int render_frame_id,
const std::string& presentation_id));
-
- // PresentationConnectionMessage is move-only.
- // TODO(crbug.com/729950): Use MOCK_METHOD directly once GMock gets the
- // move-only type support.
- void SendMessage(int render_process_id,
- int render_frame_id,
- const PresentationInfo& presentation_info,
- PresentationConnectionMessage message,
- SendMessageCallback send_message_cb) {
- SendMessageInternal(render_process_id, render_frame_id, presentation_info,
- message, send_message_cb);
- }
- MOCK_METHOD5(SendMessageInternal,
+ MOCK_METHOD5(SendMessage,
void(int render_process_id,
int render_frame_id,
const PresentationInfo& presentation_info,
- const PresentationConnectionMessage& message,
+ PresentationConnectionMessagePtr message,
const SendMessageCallback& send_message_cb));
-
MOCK_METHOD4(
ListenForConnectionStateChange,
void(int render_process_id,
@@ -162,23 +143,6 @@ class MockPresentationServiceDelegate
const PresentationInfo& connection,
const PresentationConnectionStateChangedCallback& state_changed_cb));
- void ConnectToPresentation(
- int render_process_id,
- int render_frame_id,
- const PresentationInfo& presentation_info,
- PresentationConnectionPtr controller_conn_ptr,
- PresentationConnectionRequest receiver_conn_request) override {
- RegisterLocalPresentationConnectionRaw(render_process_id, render_frame_id,
- presentation_info,
- controller_conn_ptr.get());
- }
-
- MOCK_METHOD4(RegisterLocalPresentationConnectionRaw,
- void(int render_process_id,
- int render_frame_id,
- const PresentationInfo& presentation_info,
- blink::mojom::PresentationConnection* connection));
-
void set_screen_availability_listening_supported(bool value) {
screen_availability_listening_supported_ = value;
}
@@ -189,16 +153,10 @@ class MockPresentationServiceDelegate
class MockPresentationReceiver : public blink::mojom::PresentationReceiver {
public:
- void OnReceiverConnectionAvailable(
- PresentationInfoPtr info,
- blink::mojom::PresentationConnectionPtr controller_connection,
- blink::mojom::PresentationConnectionRequest receiver_connection_request)
- override {
- OnReceiverConnectionAvailable(*info);
- }
-
- MOCK_METHOD1(OnReceiverConnectionAvailable,
- void(const PresentationInfo& info));
+ MOCK_METHOD3(OnReceiverConnectionAvailable,
+ void(PresentationInfoPtr info,
+ PresentationConnectionPtr controller_connection,
+ PresentationConnectionRequest receiver_connection_request));
};
class MockReceiverPresentationServiceDelegate
@@ -215,16 +173,11 @@ class MockReceiverPresentationServiceDelegate
void(const ReceiverConnectionAvailableCallback&));
};
-class MockPresentationConnection : public blink::mojom::PresentationConnection {
+class MockPresentationConnection : public PresentationConnection {
public:
- // PresentationConnectionMessage is move-only.
- void OnMessage(PresentationConnectionMessage message,
- base::OnceCallback<void(bool)> send_message_cb) override {
- OnMessageInternal(message, send_message_cb);
- }
- MOCK_METHOD2(OnMessageInternal,
- void(const PresentationConnectionMessage& message,
- base::OnceCallback<void(bool)>& send_message_cb));
+ MOCK_METHOD2(OnMessage,
+ void(PresentationConnectionMessagePtr message,
+ base::OnceCallback<void(bool)> send_message_cb));
MOCK_METHOD1(DidChangeState, void(PresentationConnectionState state));
MOCK_METHOD0(RequestClose, void());
};
@@ -233,38 +186,19 @@ class MockPresentationController : public blink::mojom::PresentationController {
public:
MOCK_METHOD2(OnScreenAvailabilityUpdated,
void(const GURL& url, ScreenAvailability availability));
- void OnConnectionStateChanged(PresentationInfoPtr connection,
- PresentationConnectionState new_state) {
- OnConnectionStateChangedInternal(*connection, new_state);
- }
- MOCK_METHOD2(OnConnectionStateChangedInternal,
- void(const PresentationInfo& connection,
+ MOCK_METHOD2(OnConnectionStateChanged,
+ void(PresentationInfoPtr connection,
PresentationConnectionState new_state));
- void OnConnectionClosed(
- PresentationInfoPtr connection,
- blink::mojom::PresentationConnectionCloseReason reason,
- const std::string& message) {
- OnConnectionClosedInternal(*connection, reason, message);
- }
- MOCK_METHOD3(OnConnectionClosedInternal,
- void(const PresentationInfo& connection,
- blink::mojom::PresentationConnectionCloseReason reason,
+ MOCK_METHOD3(OnConnectionClosed,
+ void(PresentationInfoPtr connection,
+ PresentationConnectionCloseReason reason,
const std::string& message));
- // PresentationConnectionMessage is move-only.
- void OnConnectionMessagesReceived(
- PresentationInfoPtr presentation_info,
- std::vector<PresentationConnectionMessage> messages) {
- OnConnectionMessagesReceivedInternal(*presentation_info, messages);
- }
MOCK_METHOD2(
- OnConnectionMessagesReceivedInternal,
+ OnConnectionMessagesReceived,
void(const PresentationInfo& presentation_info,
- const std::vector<PresentationConnectionMessage>& messages));
- void OnDefaultPresentationStarted(PresentationInfoPtr presentation_info) {
- OnDefaultPresentationStartedInternal(*presentation_info);
- }
- MOCK_METHOD1(OnDefaultPresentationStartedInternal,
- void(const PresentationInfo& presentation_info));
+ const std::vector<PresentationConnectionMessagePtr>& messages));
+ MOCK_METHOD1(OnDefaultPresentationStarted,
+ void(PresentationConnectionResultPtr result));
};
class PresentationServiceImplTest : public RenderViewHostImplTestHarness {
@@ -286,10 +220,9 @@ class PresentationServiceImplTest : public RenderViewHostImplTestHarness {
service_impl_.reset(new PresentationServiceImpl(
render_frame_host, contents(), &mock_delegate_, nullptr));
- blink::mojom::PresentationControllerPtr controller_ptr;
- controller_binding_.reset(
- new mojo::Binding<blink::mojom::PresentationController>(
- &mock_controller_, mojo::MakeRequest(&controller_ptr)));
+ PresentationControllerPtr controller_ptr;
+ controller_binding_.reset(new mojo::Binding<PresentationController>(
+ &mock_controller_, mojo::MakeRequest(&controller_ptr)));
service_impl_->SetController(std::move(controller_ptr));
presentation_urls_.push_back(presentation_url1_);
@@ -318,8 +251,7 @@ class PresentationServiceImplTest : public RenderViewHostImplTestHarness {
if (!main_frame)
rfh = rfh_tester->AppendChild("subframe");
std::unique_ptr<NavigationHandle> navigation_handle =
- NavigationHandle::CreateNavigationHandleForTesting(
- GURL(), rfh, true);
+ NavigationHandle::CreateNavigationHandleForTesting(GURL(), rfh, true);
// Destructor calls DidFinishNavigation.
}
@@ -355,17 +287,17 @@ class PresentationServiceImplTest : public RenderViewHostImplTestHarness {
service_impl_->screen_availability_listeners_.end());
}
- void ExpectPresentationSuccess(PresentationInfoPtr info,
- blink::mojom::PresentationErrorPtr error) {
- EXPECT_FALSE(info.is_null());
- EXPECT_TRUE(error.is_null());
+ void ExpectPresentationSuccess(PresentationConnectionResultPtr result,
+ PresentationErrorPtr error) {
+ EXPECT_TRUE(result);
+ EXPECT_FALSE(error);
presentation_cb_was_run_ = true;
}
- void ExpectPresentationError(PresentationInfoPtr info,
- blink::mojom::PresentationErrorPtr error) {
- EXPECT_TRUE(info.is_null());
- EXPECT_FALSE(error.is_null());
+ void ExpectPresentationError(PresentationConnectionResultPtr result,
+ PresentationErrorPtr error) {
+ EXPECT_FALSE(result);
+ EXPECT_TRUE(error);
presentation_cb_was_run_ = true;
}
@@ -380,8 +312,7 @@ class PresentationServiceImplTest : public RenderViewHostImplTestHarness {
std::unique_ptr<PresentationServiceImpl> service_impl_;
MockPresentationController mock_controller_;
- std::unique_ptr<mojo::Binding<blink::mojom::PresentationController>>
- controller_binding_;
+ std::unique_ptr<mojo::Binding<PresentationController>> controller_binding_;
GURL presentation_url1_;
GURL presentation_url2_;
@@ -469,11 +400,24 @@ TEST_F(PresentationServiceImplTest, SetDefaultPresentationUrls) {
PresentationInfo presentation_info(presentation_url2_, kPresentationId);
- EXPECT_CALL(mock_controller_, OnDefaultPresentationStartedInternal(
- InfoEquals(presentation_info)));
+ EXPECT_CALL(mock_controller_, OnDefaultPresentationStarted(_))
+ .WillOnce([&presentation_info](PresentationConnectionResultPtr result) {
+ EXPECT_THAT(*result->presentation_info, InfoEquals(presentation_info));
+ });
EXPECT_CALL(mock_delegate_, ListenForConnectionStateChange(_, _, _, _));
- std::move(callback).Run(
- PresentationInfo(presentation_url2_, kPresentationId));
+
+ // Mojo requires we not send nullptr for the InterfacePtrInfo and
+ // InterfaceRequest in PresentationConnectionResult, but there's no reason to
+ // actually have them properly bound in the test. To get around this, we
+ // create mojo pipes but bind to a nullptr for the implementation.
+ PresentationConnectionPtrInfo receiver_ptr;
+ PresentationConnectionPtr controller_ptr;
+ auto request = mojo::MakeRequest(&controller_ptr);
+ mojo::Binding<PresentationConnection> binding(
+ /** impl */ nullptr, mojo::MakeRequest(&receiver_ptr));
+ std::move(callback).Run(PresentationConnectionResult::New(
+ blink::mojom::PresentationInfo::New(presentation_url2_, kPresentationId),
+ std::move(receiver_ptr), std::move(request)));
base::RunLoop().RunUntilIdle();
}
@@ -503,8 +447,8 @@ TEST_F(PresentationServiceImplTest, ListenForConnectionStateChange) {
.WillOnce(SaveArg<3>(&state_changed_cb));
service_impl_->ListenForConnectionStateChange(connection);
- EXPECT_CALL(mock_controller_, OnConnectionStateChangedInternal(
- InfoEquals(presentation_connection),
+ EXPECT_CALL(mock_controller_, OnConnectionStateChanged(
+ InfoPtrEquals(presentation_connection),
PresentationConnectionState::TERMINATED));
state_changed_cb.Run(PresentationConnectionStateChangeInfo(
PresentationConnectionState::TERMINATED));
@@ -526,10 +470,10 @@ TEST_F(PresentationServiceImplTest, ListenForConnectionClose) {
closed_info.close_reason = PresentationConnectionCloseReason::WENT_AWAY;
closed_info.message = "Foo";
- EXPECT_CALL(mock_controller_,
- OnConnectionClosedInternal(
- InfoEquals(presentation_connection),
- PresentationConnectionCloseReason::WENT_AWAY, "Foo"));
+ EXPECT_CALL(
+ mock_controller_,
+ OnConnectionClosed(InfoPtrEquals(presentation_connection),
+ PresentationConnectionCloseReason::WENT_AWAY, "Foo"));
state_changed_cb.Run(closed_info);
base::RunLoop().RunUntilIdle();
}
@@ -545,33 +489,41 @@ TEST_F(PresentationServiceImplTest, SetSameDefaultPresentationUrls) {
}
TEST_F(PresentationServiceImplTest, StartPresentationSuccess) {
- base::OnceCallback<void(const PresentationInfo&)> success_cb;
- EXPECT_CALL(mock_delegate_, StartPresentationInternal(_, _, _))
- .WillOnce(SaveArgByMove<1>(&success_cb));
+ PresentationConnectionCallback saved_success_cb;
+ EXPECT_CALL(mock_delegate_, StartPresentation(_, _, _))
+ .WillOnce([&saved_success_cb](const auto& request, auto success_cb,
+ auto error_cb) {
+ saved_success_cb = std::move(success_cb);
+ });
service_impl_->StartPresentation(presentation_urls_,
std::move(expect_presentation_success_cb_));
- EXPECT_FALSE(success_cb.is_null());
+ EXPECT_FALSE(saved_success_cb.is_null());
EXPECT_CALL(mock_delegate_, ListenForConnectionStateChange(_, _, _, _))
.Times(1);
- std::move(success_cb)
- .Run(PresentationInfo(presentation_url1_, kPresentationId));
+ std::move(saved_success_cb)
+ .Run(PresentationConnectionResult::New(
+ blink::mojom::PresentationInfo::New(presentation_url1_,
+ kPresentationId),
+ nullptr, nullptr));
ExpectPresentationCallbackWasRun();
}
TEST_F(PresentationServiceImplTest, StartPresentationError) {
- base::OnceCallback<void(const PresentationError&)> error_cb;
- EXPECT_CALL(mock_delegate_, StartPresentationInternal(_, _, _))
- .WillOnce(SaveArgByMove<2>(&error_cb));
+ base::OnceCallback<void(const PresentationError&)> saved_error_cb;
+ EXPECT_CALL(mock_delegate_, StartPresentation(_, _, _))
+ .WillOnce([&](const auto& request, auto success_cb, auto error_cb) {
+ saved_error_cb = std::move(error_cb);
+ });
service_impl_->StartPresentation(presentation_urls_,
std::move(expect_presentation_error_cb_));
- EXPECT_FALSE(error_cb.is_null());
- std::move(error_cb).Run(
- PresentationError(PresentationErrorType::UNKNOWN, "Error message"));
+ EXPECT_FALSE(saved_error_cb.is_null());
+ std::move(saved_error_cb)
+ .Run(PresentationError(PresentationErrorType::UNKNOWN, "Error message"));
ExpectPresentationCallbackWasRun();
}
TEST_F(PresentationServiceImplTest, StartPresentationInProgress) {
- EXPECT_CALL(mock_delegate_, StartPresentationInternal(_, _, _)).Times(1);
+ EXPECT_CALL(mock_delegate_, StartPresentation(_, _, _)).Times(1);
// Uninvoked callbacks must outlive |service_impl_| since they get invoked
// at |service_impl_|'s destruction.
service_impl_->StartPresentation(presentation_urls_, base::DoNothing());
@@ -584,32 +536,37 @@ TEST_F(PresentationServiceImplTest, StartPresentationInProgress) {
}
TEST_F(PresentationServiceImplTest, ReconnectPresentationSuccess) {
- base::OnceCallback<void(const PresentationInfo&)> success_cb;
- EXPECT_CALL(mock_delegate_,
- ReconnectPresentationInternal(_, kPresentationId, _, _))
- .WillOnce(SaveArgByMove<2>(&success_cb));
+ PresentationConnectionCallback saved_success_cb;
+ EXPECT_CALL(mock_delegate_, ReconnectPresentation(_, kPresentationId, _, _))
+ .WillOnce([&saved_success_cb](const auto& request, const auto& id,
+ auto success_cb, auto error_cb) {
+ saved_success_cb = std::move(success_cb);
+ });
service_impl_->ReconnectPresentation(
presentation_urls_, kPresentationId,
std::move(expect_presentation_success_cb_));
- EXPECT_FALSE(success_cb.is_null());
+ EXPECT_FALSE(saved_success_cb.is_null());
EXPECT_CALL(mock_delegate_, ListenForConnectionStateChange(_, _, _, _))
.Times(1);
- std::move(success_cb)
- .Run(PresentationInfo(presentation_url1_, kPresentationId));
+ std::move(saved_success_cb)
+ .Run(PresentationConnectionResult::New(
+ blink::mojom::PresentationInfo::New(presentation_url1_,
+ kPresentationId),
+ nullptr, nullptr));
ExpectPresentationCallbackWasRun();
}
TEST_F(PresentationServiceImplTest, ReconnectPresentationError) {
- base::OnceCallback<void(const PresentationError&)> error_cb;
- EXPECT_CALL(mock_delegate_,
- ReconnectPresentationInternal(_, kPresentationId, _, _))
- .WillOnce(SaveArgByMove<3>(&error_cb));
+ base::OnceCallback<void(const PresentationError&)> saved_error_cb;
+ EXPECT_CALL(mock_delegate_, ReconnectPresentation(_, kPresentationId, _, _))
+ .WillOnce([&](const auto& request, const std::string& id, auto success_cb,
+ auto error_cb) { saved_error_cb = std::move(error_cb); });
service_impl_->ReconnectPresentation(
presentation_urls_, kPresentationId,
std::move(expect_presentation_error_cb_));
- EXPECT_FALSE(error_cb.is_null());
- std::move(error_cb).Run(
- PresentationError(PresentationErrorType::UNKNOWN, "Error message"));
+ EXPECT_FALSE(saved_error_cb.is_null());
+ std::move(saved_error_cb)
+ .Run(PresentationError(PresentationErrorType::UNKNOWN, "Error message"));
ExpectPresentationCallbackWasRun();
}
@@ -618,7 +575,7 @@ TEST_F(PresentationServiceImplTest, MaxPendingReconnectPresentationRequests) {
const char* presentation_id = "presentationId%d";
int num_requests = PresentationServiceImpl::kMaxQueuedRequests;
int i = 0;
- EXPECT_CALL(mock_delegate_, ReconnectPresentationInternal(_, _, _, _))
+ EXPECT_CALL(mock_delegate_, ReconnectPresentation(_, _, _, _))
.Times(num_requests);
for (; i < num_requests; ++i) {
std::vector<GURL> urls = {GURL(base::StringPrintf(presentation_url, i))};
@@ -646,25 +603,6 @@ TEST_F(PresentationServiceImplTest, Terminate) {
service_impl_->Terminate(presentation_url1_, kPresentationId);
}
-TEST_F(PresentationServiceImplTest, SetPresentationConnection) {
- PresentationInfoPtr presentation_info =
- PresentationInfo::New(presentation_url1_, kPresentationId);
-
- blink::mojom::PresentationConnectionPtr connection;
- MockPresentationConnection mock_presentation_connection;
- mojo::Binding<blink::mojom::PresentationConnection> connection_binding(
- &mock_presentation_connection, mojo::MakeRequest(&connection));
- blink::mojom::PresentationConnectionPtr receiver_connection;
- auto request = mojo::MakeRequest(&receiver_connection);
-
- PresentationInfo expected(presentation_url1_, kPresentationId);
- EXPECT_CALL(mock_delegate_, RegisterLocalPresentationConnectionRaw(
- _, _, InfoEquals(expected), _));
-
- service_impl_->SetPresentationConnection(
- std::move(presentation_info), std::move(connection), std::move(request));
-}
-
TEST_F(PresentationServiceImplTest, ReceiverPresentationServiceDelegate) {
EXPECT_CALL(mock_receiver_delegate_, AddObserver(_, _, _)).Times(1);
@@ -687,14 +625,14 @@ TEST_F(PresentationServiceImplTest, ReceiverPresentationServiceDelegate) {
PresentationInfo expected(presentation_url1_, kPresentationId);
// Client gets notified of receiver connections.
- blink::mojom::PresentationConnectionPtr controller_connection;
+ PresentationConnectionPtr controller_connection;
MockPresentationConnection mock_presentation_connection;
- mojo::Binding<blink::mojom::PresentationConnection> connection_binding(
+ mojo::Binding<PresentationConnection> connection_binding(
&mock_presentation_connection, mojo::MakeRequest(&controller_connection));
- blink::mojom::PresentationConnectionPtr receiver_connection;
+ PresentationConnectionPtr receiver_connection;
EXPECT_CALL(mock_receiver,
- OnReceiverConnectionAvailable(InfoEquals(expected)))
+ OnReceiverConnectionAvailable(InfoPtrEquals(expected), _, _))
.Times(1);
callback.Run(PresentationInfo::New(expected),
std::move(controller_connection),
@@ -716,10 +654,9 @@ TEST_F(PresentationServiceImplTest, ReceiverDelegateOnSubFrame) {
RegisterReceiverConnectionAvailableCallback(_))
.Times(0);
- blink::mojom::PresentationControllerPtr controller_ptr;
- controller_binding_.reset(
- new mojo::Binding<blink::mojom::PresentationController>(
- &mock_controller_, mojo::MakeRequest(&controller_ptr)));
+ PresentationControllerPtr controller_ptr;
+ controller_binding_.reset(new mojo::Binding<PresentationController>(
+ &mock_controller_, mojo::MakeRequest(&controller_ptr)));
service_impl.controller_delegate_ = nullptr;
service_impl.SetController(std::move(controller_ptr));
diff --git a/chromium/content/browser/push_messaging/push_messaging_manager.cc b/chromium/content/browser/push_messaging/push_messaging_manager.cc
index bc6ee59fe0c..91018ad3310 100644
--- a/chromium/content/browser/push_messaging/push_messaging_manager.cc
+++ b/chromium/content/browser/push_messaging/push_messaging_manager.cc
@@ -13,6 +13,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
+#include "base/optional.h"
#include "base/strings/string_number_conversions.h"
#include "content/browser/permissions/permission_controller_impl.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
@@ -133,7 +134,7 @@ struct PushMessagingManager::RegisterData {
GURL requesting_origin;
int64_t service_worker_registration_id;
- std::string existing_subscription_id;
+ base::Optional<std::string> existing_subscription_id;
PushSubscriptionOptions options;
SubscribeCallback callback;
@@ -502,11 +503,12 @@ void PushMessagingManager::Core::DidRegister(
mojom::PushRegistrationStatus status) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- // TODO(nator): Handle the case where |push_subscription_id| and
+ // TODO(crbug.com/646721): Handle the case where |push_subscription_id| and
// |data.existing_subscription_id| are not the same. Right now we just
// override the old subscription ID and encryption information.
const bool subscription_changed =
- push_subscription_id != data.existing_subscription_id;
+ data.existing_subscription_id.has_value() &&
+ data.existing_subscription_id.value() != push_subscription_id;
if (status == mojom::PushRegistrationStatus::SUCCESS_FROM_PUSH_SERVICE) {
BrowserThread::PostTask(
@@ -806,7 +808,8 @@ void PushMessagingManager::DidGetSubscription(
case blink::ServiceWorkerStatusCode::kErrorScriptEvaluateFailed:
case blink::ServiceWorkerStatusCode::kErrorDiskCache:
case blink::ServiceWorkerStatusCode::kErrorRedundant:
- case blink::ServiceWorkerStatusCode::kErrorDisallowed: {
+ case blink::ServiceWorkerStatusCode::kErrorDisallowed:
+ case blink::ServiceWorkerStatusCode::kErrorInvalidArguments: {
NOTREACHED() << "Got unexpected error code: "
<< static_cast<uint32_t>(service_worker_status) << " "
<< blink::ServiceWorkerStatusToString(service_worker_status);
diff --git a/chromium/content/browser/push_messaging/push_messaging_router.cc b/chromium/content/browser/push_messaging/push_messaging_router.cc
index a648b5d11fa..697ca1fabf8 100644
--- a/chromium/content/browser/push_messaging/push_messaging_router.cc
+++ b/chromium/content/browser/push_messaging/push_messaging_router.cc
@@ -11,11 +11,9 @@
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_storage.h"
-#include "content/common/service_worker/service_worker_messages.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
-#include "content/public/common/push_event_payload.h"
#include "content/public/common/push_messaging_status.mojom.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
@@ -39,7 +37,7 @@ void PushMessagingRouter::DeliverMessage(
BrowserContext* browser_context,
const GURL& origin,
int64_t service_worker_registration_id,
- const PushEventPayload& payload,
+ base::Optional<std::string> payload,
const DeliverMessageCallback& deliver_message_callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
StoragePartition* partition =
@@ -50,7 +48,7 @@ void PushMessagingRouter::DeliverMessage(
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::BindOnce(&PushMessagingRouter::FindServiceWorkerRegistration,
- origin, service_worker_registration_id, payload,
+ origin, service_worker_registration_id, std::move(payload),
deliver_message_callback, service_worker_context));
}
@@ -58,7 +56,7 @@ void PushMessagingRouter::DeliverMessage(
void PushMessagingRouter::FindServiceWorkerRegistration(
const GURL& origin,
int64_t service_worker_registration_id,
- const PushEventPayload& payload,
+ base::Optional<std::string> payload,
const DeliverMessageCallback& deliver_message_callback,
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -67,13 +65,13 @@ void PushMessagingRouter::FindServiceWorkerRegistration(
service_worker_context->FindReadyRegistrationForId(
service_worker_registration_id, origin,
base::BindOnce(
- &PushMessagingRouter::FindServiceWorkerRegistrationCallback, payload,
- deliver_message_callback));
+ &PushMessagingRouter::FindServiceWorkerRegistrationCallback,
+ std::move(payload), deliver_message_callback));
}
// static
void PushMessagingRouter::FindServiceWorkerRegistrationCallback(
- const PushEventPayload& payload,
+ base::Optional<std::string> payload,
const DeliverMessageCallback& deliver_message_callback,
blink::ServiceWorkerStatusCode service_worker_status,
scoped_refptr<ServiceWorkerRegistration> service_worker_registration) {
@@ -102,14 +100,14 @@ void PushMessagingRouter::FindServiceWorkerRegistrationCallback(
ServiceWorkerMetrics::EventType::PUSH,
base::BindOnce(&PushMessagingRouter::DeliverMessageToWorker,
base::WrapRefCounted(version), service_worker_registration,
- payload, deliver_message_callback));
+ std::move(payload), deliver_message_callback));
}
// static
void PushMessagingRouter::DeliverMessageToWorker(
const scoped_refptr<ServiceWorkerVersion>& service_worker,
const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration,
- const PushEventPayload& payload,
+ base::Optional<std::string> payload,
const DeliverMessageCallback& deliver_message_callback,
blink::ServiceWorkerStatusCode start_worker_status) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -168,6 +166,7 @@ void PushMessagingRouter::DeliverMessageEnd(
case blink::ServiceWorkerStatusCode::kErrorNetwork:
case blink::ServiceWorkerStatusCode::kErrorSecurity:
case blink::ServiceWorkerStatusCode::kErrorState:
+ case blink::ServiceWorkerStatusCode::kErrorInvalidArguments:
NOTREACHED() << "Got unexpected error code: "
<< static_cast<uint32_t>(service_worker_status) << " "
<< blink::ServiceWorkerStatusToString(service_worker_status);
diff --git a/chromium/content/browser/push_messaging/push_messaging_router.h b/chromium/content/browser/push_messaging/push_messaging_router.h
index 71bb530f425..773bed1ee05 100644
--- a/chromium/content/browser/push_messaging/push_messaging_router.h
+++ b/chromium/content/browser/push_messaging/push_messaging_router.h
@@ -10,6 +10,7 @@
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/optional.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
#include "url/gurl.h"
@@ -20,7 +21,6 @@ enum class PushDeliveryStatus;
}
class BrowserContext;
-struct PushEventPayload;
class ServiceWorkerContextWrapper;
class ServiceWorkerRegistration;
class ServiceWorkerVersion;
@@ -37,7 +37,7 @@ class PushMessagingRouter {
BrowserContext* browser_context,
const GURL& origin,
int64_t service_worker_registration_id,
- const PushEventPayload& payload,
+ base::Optional<std::string> payload,
const DeliverMessageCallback& deliver_message_callback);
private:
@@ -46,7 +46,7 @@ class PushMessagingRouter {
static void FindServiceWorkerRegistration(
const GURL& origin,
int64_t service_worker_registration_id,
- const PushEventPayload& payload,
+ base::Optional<std::string> payload,
const DeliverMessageCallback& deliver_message_callback,
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context);
@@ -54,7 +54,7 @@ class PushMessagingRouter {
// |data| on the Service Worker identified by |service_worker_registration|.
// Must be called on the IO thread.
static void FindServiceWorkerRegistrationCallback(
- const PushEventPayload& payload,
+ base::Optional<std::string> payload,
const DeliverMessageCallback& deliver_message_callback,
blink::ServiceWorkerStatusCode service_worker_status,
scoped_refptr<ServiceWorkerRegistration> service_worker_registration);
@@ -65,7 +65,7 @@ class PushMessagingRouter {
const scoped_refptr<ServiceWorkerVersion>& service_worker,
const scoped_refptr<ServiceWorkerRegistration>&
service_worker_registration,
- const PushEventPayload& payload,
+ base::Optional<std::string> payload,
const DeliverMessageCallback& deliver_message_callback,
blink::ServiceWorkerStatusCode start_worker_status);
diff --git a/chromium/content/browser/renderer_host/DEPS b/chromium/content/browser/renderer_host/DEPS
index 8ac26e104a5..a38288a21c9 100644
--- a/chromium/content/browser/renderer_host/DEPS
+++ b/chromium/content/browser/renderer_host/DEPS
@@ -3,7 +3,7 @@ include_rules = [
"+components/viz/common",
"+components/viz/host",
"+components/viz/service",
- "+services/ui/public",
+ "+services/ws/public",
"+third_party/blink/public/platform/web_gesture_curve.h",
"+third_party/zlib",
"+ui/events/gestures/blink/web_gesture_curve_impl.h",
diff --git a/chromium/content/browser/renderer_host/browser_compositor_view_mac.h b/chromium/content/browser/renderer_host/browser_compositor_view_mac.h
index 46be85eea4b..7dc490ea560 100644
--- a/chromium/content/browser/renderer_host/browser_compositor_view_mac.h
+++ b/chromium/content/browser/renderer_host/browser_compositor_view_mac.h
@@ -13,10 +13,12 @@
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "components/viz/common/surfaces/scoped_surface_id_allocator.h"
#include "content/browser/renderer_host/delegated_frame_host.h"
+#include "content/public/common/screen_info.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/compositor_observer.h"
#include "ui/compositor/layer_observer.h"
#include "ui/display/display.h"
+#include "ui/gfx/ca_layer_params.h"
namespace ui {
class AcceleratedWidgetMacNSView;
@@ -30,7 +32,6 @@ class BrowserCompositorMacClient {
virtual SkColor BrowserCompositorMacGetGutterColor() const = 0;
virtual void BrowserCompositorMacOnBeginFrame(base::TimeTicks frame_time) = 0;
virtual void OnFrameTokenChanged(uint32_t frame_token) = 0;
- virtual void DidReceiveFirstFrameAfterNavigation() = 0;
virtual void DestroyCompositorForShutdown() = 0;
virtual bool SynchronizeVisualProperties(
const base::Optional<viz::LocalSurfaceId>&
@@ -136,7 +137,6 @@ class CONTENT_EXPORT BrowserCompositorMac : public DelegatedFrameHostClient,
void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
void OnBeginFrame(base::TimeTicks frame_time) override;
void OnFrameTokenChanged(uint32_t frame_token) override;
- void DidReceiveFirstFrameAfterNavigation() override;
base::WeakPtr<BrowserCompositorMac> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
@@ -148,7 +148,7 @@ class CONTENT_EXPORT BrowserCompositorMac : public DelegatedFrameHostClient,
bool ForceNewSurfaceForTesting();
- ui::Compositor* GetCompositorForTesting() const;
+ ui::Compositor* GetCompositor() const;
private:
// ui::LayerObserver implementation:
diff --git a/chromium/content/browser/renderer_host/browser_compositor_view_mac.mm b/chromium/content/browser/renderer_host/browser_compositor_view_mac.mm
index 92afcc77910..fb23caccdd1 100644
--- a/chromium/content/browser/renderer_host/browser_compositor_view_mac.mm
+++ b/chromium/content/browser/renderer_host/browser_compositor_view_mac.mm
@@ -60,9 +60,7 @@ BrowserCompositorMac::BrowserCompositorMac(
// content (otherwise this solid color will be flashed during navigation).
root_layer_->SetColor(SK_ColorTRANSPARENT);
delegated_frame_host_.reset(new DelegatedFrameHost(
- frame_sink_id, this,
- base::FeatureList::IsEnabled(features::kVizDisplayCompositor),
- true /* should_register_frame_sink_id */));
+ frame_sink_id, this, true /* should_register_frame_sink_id */));
SetRenderWidgetHostIsHidden(render_widget_host_is_hidden);
SetNSViewAttachedToWindow(false);
@@ -265,7 +263,7 @@ void BrowserCompositorMac::TransitionToState(State new_state) {
root_layer_->parent()->RemoveObserver(this);
root_layer_->parent()->Remove(root_layer_.get());
delegated_frame_host_->WasHidden();
- delegated_frame_host_->ResetCompositor();
+ delegated_frame_host_->DetachFromCompositor();
state_ = HasNoCompositor;
}
@@ -287,7 +285,8 @@ void BrowserCompositorMac::TransitionToState(State new_state) {
// Transition HasDetachedCompositor -> HasAttachedCompositor.
if (state_ == HasDetachedCompositor && new_state < HasDetachedCompositor) {
- delegated_frame_host_->SetCompositor(recyclable_compositor_->compositor());
+ delegated_frame_host_->AttachToCompositor(
+ recyclable_compositor_->compositor());
delegated_frame_host_->WasShown(GetRendererLocalSurfaceId(), dfh_size_dip_,
false /* record_presentation_time */);
@@ -308,7 +307,7 @@ void BrowserCompositorMac::TransitionToState(State new_state) {
// Marking the DelegatedFrameHost as removed from the window hierarchy is
// necessary to remove all connections to its old ui::Compositor.
delegated_frame_host_->WasHidden();
- delegated_frame_host_->ResetCompositor();
+ delegated_frame_host_->DetachFromCompositor();
state_ = HasDetachedCompositor;
}
@@ -327,7 +326,8 @@ void BrowserCompositorMac::TransitionToState(State new_state) {
DCHECK(parent_ui_layer_);
DCHECK(parent_ui_layer_->GetCompositor());
DCHECK(!root_layer_->parent());
- delegated_frame_host_->SetCompositor(parent_ui_layer_->GetCompositor());
+ delegated_frame_host_->AttachToCompositor(
+ parent_ui_layer_->GetCompositor());
delegated_frame_host_->WasShown(GetRendererLocalSurfaceId(), dfh_size_dip_,
false /* record_presentation_time */);
parent_ui_layer_->Add(root_layer_.get());
@@ -416,10 +416,6 @@ void BrowserCompositorMac::DidNavigate() {
is_first_navigation_ = false;
}
-void BrowserCompositorMac::DidReceiveFirstFrameAfterNavigation() {
- client_->DidReceiveFirstFrameAfterNavigation();
-}
-
bool BrowserCompositorMac::ShouldContinueToPauseForFrame() const {
if (state_ == UseParentLayerCompositor)
return false;
@@ -496,7 +492,9 @@ void BrowserCompositorMac::LayerDestroyed(ui::Layer* layer) {
SetParentUiLayer(nullptr);
}
-ui::Compositor* BrowserCompositorMac::GetCompositorForTesting() const {
+ui::Compositor* BrowserCompositorMac::GetCompositor() const {
+ if (parent_ui_layer_)
+ return parent_ui_layer_->GetCompositor();
if (recyclable_compositor_)
return recyclable_compositor_->compositor();
return nullptr;
diff --git a/chromium/content/browser/renderer_host/compositor_impl_android.cc b/chromium/content/browser/renderer_host/compositor_impl_android.cc
index 454ebcafa7a..ebfb4c19fb0 100644
--- a/chromium/content/browser/renderer_host/compositor_impl_android.cc
+++ b/chromium/content/browser/renderer_host/compositor_impl_android.cc
@@ -13,6 +13,7 @@
#include <utility>
#include <vector>
+#include "base/android/application_status_listener.h"
#include "base/android/jni_android.h"
#include "base/android/scoped_java_ref.h"
#include "base/auto_reset.h"
@@ -43,7 +44,6 @@
#include "components/viz/client/hit_test_data_provider_draw_quad.h"
#include "components/viz/client/local_surface_id_provider.h"
#include "components/viz/common/features.h"
-#include "components/viz/common/gl_helper.h"
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/common/gpu/vulkan_in_process_context_provider.h"
#include "components/viz/common/quads/compositor_frame.h"
@@ -81,9 +81,9 @@
#include "gpu/vulkan/init/vulkan_factory.h"
#include "gpu/vulkan/vulkan_implementation.h"
#include "gpu/vulkan/vulkan_surface.h"
-#include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
#include "services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom.h"
#include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h"
+#include "services/ws/public/cpp/gpu/context_provider_command_buffer.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
#include "third_party/skia/include/core/SkMallocPixelRef.h"
@@ -104,6 +104,29 @@ namespace content {
namespace {
+// These functions are called based on application visibility status.
+void SendOnBackgroundedToGpuService() {
+ content::GpuProcessHost::CallOnIO(
+ content::GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
+ false /* force_create */,
+ base::BindRepeating([](content::GpuProcessHost* host) {
+ if (host) {
+ host->gpu_service()->OnBackgrounded();
+ }
+ }));
+}
+
+void SendOnForegroundedToGpuService() {
+ content::GpuProcessHost::CallOnIO(
+ content::GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
+ false /* force_create */,
+ base::BindRepeating([](content::GpuProcessHost* host) {
+ if (host) {
+ host->gpu_service()->OnForegrounded();
+ }
+ }));
+}
+
// The client_id used here should not conflict with the client_id generated
// from RenderWidgetHostImpl.
constexpr uint32_t kDefaultClientId = 0u;
@@ -161,13 +184,14 @@ class CompositorDependencies {
host_frame_sink_manager.SetConnectionLostCallback(base::BindRepeating(
[]() { CompositorDependencies::Get().CreateVizFrameSinkManager(); }));
- BrowserMainLoop::GetInstance()
- ->gpu_channel_establish_factory()
- ->EstablishGpuChannel(base::BindOnce(
- &CompositorDependencies::
- OnReadyToConnectVizFrameSinkManagerOnMainThread,
- base::Unretained(this), std::move(frame_sink_manager_request),
- frame_sink_manager_client.PassInterface()));
+ pending_connect_viz_on_main_thread_ = base::BindOnce(
+ &CompositorDependencies::
+ OnReadyToConnectVizFrameSinkManagerOnMainThread,
+ base::Unretained(this), std::move(frame_sink_manager_request),
+ frame_sink_manager_client.PassInterface());
+
+ // Will connect using the above callback if we are foreground.
+ TryEstablishVizConnectionIfNeeded();
}
SingleThreadTaskGraphRunner task_graph_runner;
@@ -190,7 +214,13 @@ class CompositorDependencies {
private:
friend class base::NoDestructor<CompositorDependencies>;
- CompositorDependencies() : frame_sink_id_allocator(kDefaultClientId) {
+ CompositorDependencies()
+ : frame_sink_id_allocator(kDefaultClientId),
+ app_listener_(base::BindRepeating(
+ &CompositorDependencies::OnApplicationStateChange,
+ base::Unretained(this))) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
bool enable_viz =
base::FeatureList::IsEnabled(features::kVizDisplayCompositor);
if (!enable_viz) {
@@ -203,6 +233,9 @@ class CompositorDependencies {
} else {
CreateVizFrameSinkManager();
}
+
+ // Ensure we're in the correct state at start up.
+ OnApplicationStateChange(app_listener_.GetState());
}
void OnReadyToConnectVizFrameSinkManagerOnMainThread(
@@ -234,10 +267,85 @@ class CompositorDependencies {
// GpuProcessHost::Get() can return null.
auto* gpu_process_host = GpuProcessHost::Get();
if (gpu_process_host) {
- gpu_process_host->ConnectFrameSinkManager(std::move(request),
- std::move(client));
+ gpu_process_host->gpu_host()->ConnectFrameSinkManager(std::move(request),
+ std::move(client));
+ }
+ }
+
+ void TryEstablishVizConnectionIfNeeded() {
+ // We don't connect to the viz process if backgrounded, as the OS may
+ // repeatedly kill the resulting process. Instead wait until we come to the
+ // foreground.
+ if (pending_connect_viz_on_main_thread_ && application_is_foreground_) {
+ BrowserMainLoop::GetInstance()
+ ->gpu_channel_establish_factory()
+ ->EstablishGpuChannel(std::move(pending_connect_viz_on_main_thread_));
+ }
+ }
+
+ void EnqueueLowEndBackgroundCleanup() {
+ if (base::SysInfo::IsLowEndDevice()) {
+ low_end_background_cleanup_task_.Reset(
+ base::BindOnce(&CompositorDependencies::DoLowEndBackgroundCleanup,
+ base::Unretained(this)));
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, low_end_background_cleanup_task_.callback(),
+ base::TimeDelta::FromSeconds(5));
+ }
+ }
+
+ void DoLowEndBackgroundCleanup() {
+ // When we become visible, we immediately cancel the callback that runs this
+ // code. First, evict all unlocked frames, allowing resources to be
+ // reclaimed.
+ viz::FrameEvictionManager::GetInstance()->PurgeAllUnlockedFrames();
+
+ // Next, notify the GPU process to do background processing, which will
+ // lose all renderer contexts.
+ content::GpuProcessHost::CallOnIO(
+ content::GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
+ false /* force_create */,
+ base::BindRepeating([](content::GpuProcessHost* host) {
+ if (host) {
+ host->gpu_service()->OnBackgroundCleanup();
+ }
+ }));
+ }
+
+ // This callback function runs when application state changes. If application
+ // state is UNKNOWN, consider it as the app running as a conservative
+ // approach so that we don't send the gpu services to background.
+ void OnApplicationStateChange(
+ base::android::ApplicationState application_state) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ switch (application_state) {
+ case base::android::APPLICATION_STATE_UNKNOWN:
+ case base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES:
+ case base::android::APPLICATION_STATE_HAS_PAUSED_ACTIVITIES:
+ GpuDataManagerImpl::GetInstance()->SetApplicationVisible(true);
+ SendOnForegroundedToGpuService();
+ low_end_background_cleanup_task_.Cancel();
+ application_is_foreground_ = true;
+ TryEstablishVizConnectionIfNeeded();
+ break;
+ case base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES:
+ case base::android::APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES:
+ GpuDataManagerImpl::GetInstance()->SetApplicationVisible(false);
+ SendOnBackgroundedToGpuService();
+ EnqueueLowEndBackgroundCleanup();
+ application_is_foreground_ = false;
}
}
+
+ // A task which runs cleanup tasks on low-end Android after a delay. Enqueued
+ // when we hide, canceled when we're shown.
+ base::CancelableOnceClosure low_end_background_cleanup_task_;
+
+ // An instance of Android AppListener.
+ base::android::ApplicationStatusListener app_listener_;
+ bool application_is_foreground_ = true;
+ gpu::GpuChannelEstablishedCallback pending_connect_viz_on_main_thread_;
};
const unsigned int kMaxDisplaySwapBuffers = 1U;
@@ -361,20 +469,20 @@ void CreateContextProviderAfterGpuChannelEstablished(
constexpr bool support_grcontext = false;
auto context_provider =
- base::MakeRefCounted<ui::ContextProviderCommandBuffer>(
+ base::MakeRefCounted<ws::ContextProviderCommandBuffer>(
std::move(gpu_channel_host), factory->GetGpuMemoryBufferManager(),
stream_id, stream_priority, handle,
GURL(std::string("chrome://gpu/Compositor::CreateContextProvider")),
automatic_flushes, support_locking, support_grcontext,
shared_memory_limits, attributes,
- ui::command_buffer_metrics::ContextType::UNKNOWN);
+ ws::command_buffer_metrics::ContextType::UNKNOWN);
callback.Run(std::move(context_provider));
}
class AndroidOutputSurface : public viz::OutputSurface {
public:
AndroidOutputSurface(
- scoped_refptr<ui::ContextProviderCommandBuffer> context_provider,
+ scoped_refptr<ws::ContextProviderCommandBuffer> context_provider,
base::RepeatingCallback<void(const gfx::Size&)> swap_buffers_callback)
: viz::OutputSurface(std::move(context_provider)),
swap_buffers_callback_(std::move(swap_buffers_callback)),
@@ -459,7 +567,7 @@ class AndroidOutputSurface : public viz::OutputSurface {
uint32_t GetFramebufferCopyTextureFormat() override {
auto* gl =
- static_cast<ui::ContextProviderCommandBuffer*>(context_provider());
+ static_cast<ws::ContextProviderCommandBuffer*>(context_provider());
return gl->GetCopyTextureInternalFormat();
}
@@ -467,8 +575,8 @@ class AndroidOutputSurface : public viz::OutputSurface {
private:
gpu::CommandBufferProxyImpl* GetCommandBufferProxy() {
- ui::ContextProviderCommandBuffer* provider_command_buffer =
- static_cast<ui::ContextProviderCommandBuffer*>(context_provider_.get());
+ ws::ContextProviderCommandBuffer* provider_command_buffer =
+ static_cast<ws::ContextProviderCommandBuffer*>(context_provider_.get());
gpu::CommandBufferProxyImpl* command_buffer_proxy =
provider_command_buffer->GetCommandBufferProxy();
DCHECK(command_buffer_proxy);
@@ -609,33 +717,6 @@ class VulkanOutputSurface : public viz::OutputSurface {
};
#endif
-// TODO(khushalsagar): These are being sent based on the CompositorImpl
-// visiblity which bakes in the assumption that there is a single CompositorImpl
-// instance per application, while the embedder could potentially create
-// multiple compositor instances. We should use the ApplicationStateListener to
-// send these notifications to the GPU instead. See crbug.com/859723.
-void SendOnBackgroundedToGpuService() {
- content::GpuProcessHost::CallOnIO(
- content::GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
- false /* force_create */,
- base::BindRepeating([](content::GpuProcessHost* host) {
- if (host) {
- host->gpu_service()->OnBackgrounded();
- }
- }));
-}
-
-void SendOnForegroundedToGpuService() {
- content::GpuProcessHost::CallOnIO(
- content::GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
- false /* force_create */,
- base::BindRepeating([](content::GpuProcessHost* host) {
- if (host) {
- host->gpu_service()->OnForegrounded();
- }
- }));
-}
-
static bool g_initialized = false;
} // anonymous namespace
@@ -703,9 +784,6 @@ CompositorImpl::CompositorImpl(CompositorClient* client,
enable_viz_(
base::FeatureList::IsEnabled(features::kVizDisplayCompositor)),
weak_factory_(this) {
- GetHostFrameSinkManager()->RegisterFrameSinkId(frame_sink_id_, this);
- GetHostFrameSinkManager()->SetFrameSinkDebugLabel(frame_sink_id_,
- "CompositorImpl");
DCHECK(client);
SetRootWindow(root_window);
@@ -720,7 +798,6 @@ CompositorImpl::~CompositorImpl() {
DetachRootWindow();
// Clean-up any surface references.
SetSurface(NULL);
- GetHostFrameSinkManager()->InvalidateFrameSinkId(frame_sink_id_);
}
void CompositorImpl::DetachRootWindow() {
@@ -858,38 +935,65 @@ void CompositorImpl::CreateLayerTreeHost() {
void CompositorImpl::SetVisible(bool visible) {
TRACE_EVENT1("cc", "CompositorImpl::SetVisible", "visible", visible);
+
if (!visible) {
DCHECK(host_->IsVisible());
+ // Tear down the display first, synchronously completing any pending
+ // draws/readbacks if poosible.
+ TearDownDisplayAndUnregisterRootFrameSink();
+ // Hide the LayerTreeHost and release its frame sink.
+ host_->SetVisible(false);
+ host_->ReleaseLayerTreeFrameSink();
+ has_layer_tree_frame_sink_ = false;
+ pending_frames_ = 0;
+ } else {
+ DCHECK(!host_->IsVisible());
+ RegisterRootFrameSink();
+ host_->SetVisible(true);
+ has_submitted_frame_since_became_visible_ = false;
+ if (layer_tree_frame_sink_request_pending_)
+ HandlePendingLayerTreeFrameSinkRequest();
+ }
+}
+void CompositorImpl::TearDownDisplayAndUnregisterRootFrameSink() {
+ if (enable_viz_) {
+ // Make a best effort to try to complete pending readbacks.
+ // TODO(crbug.com/637035): Consider doing this in a better way,
+ // ideally with the guarantee of readbacks completing.
+ if (display_private_ && HavePendingReadbacks()) {
+ // Note that while this is not a Sync IPC, the call to
+ // InvalidateFrameSinkId below will end up triggering a sync call to
+ // FrameSinkManager::DestroyCompositorFrameSink, as this is the root
+ // frame sink. Because |display_private_| is an associated interface to
+ // FrameSinkManager, this subsequent sync call will ensure ordered
+ // execution of this call.
+ display_private_->ForceImmediateDrawAndSwapIfPossible();
+ }
+
+ GetHostFrameSinkManager()->InvalidateFrameSinkId(frame_sink_id_);
+ display_private_.reset();
+ } else {
// Make a best effort to try to complete pending readbacks.
// TODO(crbug.com/637035): Consider doing this in a better way,
// ideally with the guarantee of readbacks completing.
- if (display_.get() && HavePendingReadbacks())
+ if (display_ && HavePendingReadbacks())
display_->ForceImmediateDrawAndSwapIfPossible();
- host_->SetVisible(false);
- host_->ReleaseLayerTreeFrameSink();
- has_layer_tree_frame_sink_ = false;
- pending_frames_ = 0;
if (display_) {
GetFrameSinkManager()->UnregisterBeginFrameSource(
root_window_->GetBeginFrameSource());
}
+
+ GetHostFrameSinkManager()->InvalidateFrameSinkId(frame_sink_id_);
display_.reset();
- GpuDataManagerImpl::GetInstance()->SetApplicationVisible(false);
- SendOnBackgroundedToGpuService();
- EnqueueLowEndBackgroundCleanup();
- } else {
- host_->SetVisible(true);
- has_submitted_frame_since_became_visible_ = false;
- if (layer_tree_frame_sink_request_pending_)
- HandlePendingLayerTreeFrameSinkRequest();
- GpuDataManagerImpl::GetInstance()->SetApplicationVisible(true);
- SendOnForegroundedToGpuService();
- low_end_background_cleanup_task_.Cancel();
}
- if (display_private_)
- display_private_->SetDisplayVisible(visible);
+}
+
+void CompositorImpl::RegisterRootFrameSink() {
+ GetHostFrameSinkManager()->RegisterFrameSinkId(frame_sink_id_, this);
+ GetHostFrameSinkManager()->SetFrameSinkDebugLabel(frame_sink_id_,
+ "CompositorImpl");
}
void CompositorImpl::SetWindowBounds(const gfx::Size& size) {
@@ -1011,10 +1115,8 @@ void CompositorImpl::OnGpuChannelEstablished(
return;
}
- // We don't need the context anymore if we are invisible. Additionally, we
- // should notify the channel that we are invisible.
+ // We don't need the context anymore if we are invisible.
if (!host_->IsVisible()) {
- SendOnBackgroundedToGpuService();
return;
}
@@ -1036,7 +1138,7 @@ void CompositorImpl::OnGpuChannelEstablished(
gpu::SurfaceHandle surface_handle =
enable_viz_ ? gpu::kNullSurfaceHandle : surface_handle_;
auto context_provider =
- base::MakeRefCounted<ui::ContextProviderCommandBuffer>(
+ base::MakeRefCounted<ws::ContextProviderCommandBuffer>(
std::move(gpu_channel_host), factory->GetGpuMemoryBufferManager(),
stream_id, stream_priority, surface_handle,
GURL(std::string("chrome://gpu/CompositorImpl::") +
@@ -1045,7 +1147,7 @@ void CompositorImpl::OnGpuChannelEstablished(
GetCompositorContextSharedMemoryLimits(root_window_),
GetCompositorContextAttributes(display_color_space_,
requires_alpha_channel_),
- ui::command_buffer_metrics::ContextType::BROWSER_COMPOSITOR);
+ ws::command_buffer_metrics::ContextType::BROWSER_COMPOSITOR);
auto result = context_provider->BindToCurrentThread();
LOG_IF(FATAL, result == gpu::ContextResult::kFatalFailure)
<< "Fatal error making Gpu context";
@@ -1232,44 +1334,26 @@ bool CompositorImpl::IsDrawingFirstVisibleFrame() const {
return !has_submitted_frame_since_became_visible_;
}
-void CompositorImpl::OnCompositorLockStateChanged(bool locked) {
- if (host_)
- host_->SetDeferCommits(locked);
-}
-
-void CompositorImpl::EnqueueLowEndBackgroundCleanup() {
- if (base::SysInfo::IsLowEndDevice()) {
- low_end_background_cleanup_task_.Reset(
- base::BindOnce(&CompositorImpl::DoLowEndBackgroundCleanup,
- weak_factory_.GetWeakPtr()));
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, low_end_background_cleanup_task_.callback(),
- base::TimeDelta::FromSeconds(5));
- }
-}
+void CompositorImpl::SetVSyncPaused(bool paused) {
+ // No action needed in non-Viz mode, as VSync is handled in WindowAndroid.
+ if (!enable_viz_)
+ return;
-void CompositorImpl::DoLowEndBackgroundCleanup() {
- // When we become visible, we immediately cancel the callback that runs this
- // code.
- DCHECK(!host_->IsVisible());
+ if (vsync_paused_ == paused)
+ return;
- // First, evict all unlocked frames, allowing resources to be reclaimed.
- viz::FrameEvictionManager::GetInstance()->PurgeAllUnlockedFrames();
+ vsync_paused_ = paused;
+ if (display_private_)
+ display_private_->SetVSyncPaused(paused);
+}
- // Next, notify the GPU process to do background processing, which will
- // lose all renderer contexts.
- content::GpuProcessHost::CallOnIO(
- content::GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
- false /* force_create */,
- base::BindRepeating([](content::GpuProcessHost* host) {
- if (host) {
- host->gpu_service()->OnBackgroundCleanup();
- }
- }));
+void CompositorImpl::OnCompositorLockStateChanged(bool locked) {
+ if (host_)
+ host_->SetDeferCommits(locked);
}
void CompositorImpl::InitializeVizLayerTreeFrameSink(
- scoped_refptr<ui::ContextProviderCommandBuffer> context_provider) {
+ scoped_refptr<ws::ContextProviderCommandBuffer> context_provider) {
DCHECK(enable_viz_);
pending_frames_ = 0;
@@ -1297,6 +1381,7 @@ void CompositorImpl::InitializeVizLayerTreeFrameSink(
viz::RendererSettings renderer_settings;
renderer_settings.allow_antialiasing = false;
renderer_settings.highp_threshold_min = 2048;
+ renderer_settings.requires_alpha_channel = requires_alpha_channel_;
root_params->frame_sink_id = frame_sink_id_;
root_params->widget = surface_handle_;
root_params->gpu_compositing = true;
@@ -1325,6 +1410,7 @@ void CompositorImpl::InitializeVizLayerTreeFrameSink(
host_->SetLayerTreeFrameSink(std::move(layer_tree_frame_sink));
display_private_->SetDisplayVisible(true);
display_private_->Resize(size_);
+ display_private_->SetVSyncPaused(vsync_paused_);
}
viz::LocalSurfaceId CompositorImpl::GenerateLocalSurfaceId() const {
diff --git a/chromium/content/browser/renderer_host/compositor_impl_android.h b/chromium/content/browser/renderer_host/compositor_impl_android.h
index ad8f0ea0358..465dee6734a 100644
--- a/chromium/content/browser/renderer_host/compositor_impl_android.h
+++ b/chromium/content/browser/renderer_host/compositor_impl_android.h
@@ -25,8 +25,8 @@
#include "gpu/command_buffer/common/capabilities.h"
#include "gpu/ipc/common/surface_handle.h"
#include "gpu/vulkan/buildflags.h"
-#include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
#include "services/viz/privileged/interfaces/compositing/display_private.mojom.h"
+#include "services/ws/public/cpp/gpu/context_provider_command_buffer.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "ui/android/resources/resource_manager_impl.h"
#include "ui/android/resources/ui_resource_provider.h"
@@ -148,6 +148,7 @@ class CONTENT_EXPORT CompositorImpl
ui::CompositorLockClient* client,
base::TimeDelta timeout) override;
bool IsDrawingFirstVisibleFrame() const override;
+ void SetVSyncPaused(bool paused) override;
// viz::HostFrameSinkClient implementation.
void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override {
@@ -189,9 +190,16 @@ class CONTENT_EXPORT CompositorImpl
// returns an empty surface.
viz::LocalSurfaceId GenerateLocalSurfaceId() const;
+ // Tears down the display for both Viz and non-Viz, unregistering the root
+ // frame sink ID in the process.
+ void TearDownDisplayAndUnregisterRootFrameSink();
+
+ // Registers the root frame sink ID.
+ void RegisterRootFrameSink();
+
// Viz specific functions:
void InitializeVizLayerTreeFrameSink(
- scoped_refptr<ui::ContextProviderCommandBuffer> context_provider);
+ scoped_refptr<ws::ContextProviderCommandBuffer> context_provider);
viz::FrameSinkId frame_sink_id_;
@@ -240,10 +248,6 @@ class CONTENT_EXPORT CompositorImpl
ui::CompositorLockManager lock_manager_;
bool has_submitted_frame_since_became_visible_ = false;
- // A task which runs cleanup tasks on low-end Android after a delay. Enqueued
- // when we hide, canceled when we're shown.
- base::CancelableOnceClosure low_end_background_cleanup_task_;
-
// If true, we are using surface synchronization.
const bool enable_surface_synchronization_;
@@ -253,6 +257,7 @@ class CONTENT_EXPORT CompositorImpl
// Viz-specific members for communicating with the display.
viz::mojom::DisplayPrivateAssociatedPtr display_private_;
std::unique_ptr<viz::HostDisplayClient> display_client_;
+ bool vsync_paused_ = false;
// Test-only. Called when we are notified of a swap.
base::RepeatingCallback<void(const gfx::Size&)>
diff --git a/chromium/content/browser/renderer_host/compositor_impl_android_browsertest.cc b/chromium/content/browser/renderer_host/compositor_impl_android_browsertest.cc
index a2b349b0a46..207c42dd823 100644
--- a/chromium/content/browser/renderer_host/compositor_impl_android_browsertest.cc
+++ b/chromium/content/browser/renderer_host/compositor_impl_android_browsertest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/android/application_status_listener.h"
#include "base/base_switches.h"
#include "base/test/scoped_feature_list.h"
#include "components/viz/common/features.h"
@@ -198,6 +199,8 @@ IN_PROC_BROWSER_TEST_P(CompositorImplLowEndBrowserTest,
ContextLostRunLoop run_loop(context.get());
compositor->SetVisibleForTesting(false);
+ base::android::ApplicationStatusListener::NotifyApplicationStateChange(
+ base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES);
rwhva->OnRootWindowVisibilityChanged(false);
rwhva->Hide();
@@ -208,6 +211,8 @@ IN_PROC_BROWSER_TEST_P(CompositorImplLowEndBrowserTest,
// Become visible again:
compositor->SetVisibleForTesting(true);
+ base::android::ApplicationStatusListener::NotifyApplicationStateChange(
+ base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES);
rwhva->Show();
rwhva->OnRootWindowVisibilityChanged(true);
diff --git a/chromium/content/browser/renderer_host/cursor_manager.cc b/chromium/content/browser/renderer_host/cursor_manager.cc
index 724d64cd472..6d5ec95d2fd 100644
--- a/chromium/content/browser/renderer_host/cursor_manager.cc
+++ b/chromium/content/browser/renderer_host/cursor_manager.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 "cursor_manager.h"
+#include "content/browser/renderer_host/cursor_manager.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
diff --git a/chromium/content/browser/renderer_host/delegated_frame_host.cc b/chromium/content/browser/renderer_host/delegated_frame_host.cc
index 8b8bc279ccf..995ba36a5e1 100644
--- a/chromium/content/browser/renderer_host/delegated_frame_host.cc
+++ b/chromium/content/browser/renderer_host/delegated_frame_host.cc
@@ -15,6 +15,7 @@
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "cc/base/switches.h"
+#include "components/viz/common/features.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "components/viz/common/resources/single_release_callback.h"
@@ -37,22 +38,22 @@ namespace content {
DelegatedFrameHost::DelegatedFrameHost(const viz::FrameSinkId& frame_sink_id,
DelegatedFrameHostClient* client,
- bool enable_viz,
bool should_register_frame_sink_id)
: frame_sink_id_(frame_sink_id),
client_(client),
- enable_viz_(enable_viz),
+ enable_viz_(
+ base::FeatureList::IsEnabled(features::kVizDisplayCompositor)),
should_register_frame_sink_id_(should_register_frame_sink_id),
+ host_frame_sink_manager_(GetHostFrameSinkManager()),
frame_evictor_(std::make_unique<viz::FrameEvictor>(this)) {
ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
factory->GetContextFactory()->AddObserver(this);
- viz::HostFrameSinkManager* host_frame_sink_manager =
- factory->GetContextFactoryPrivate()->GetHostFrameSinkManager();
- host_frame_sink_manager->RegisterFrameSinkId(frame_sink_id_, this);
- host_frame_sink_manager->EnableSynchronizationReporting(
+ DCHECK(host_frame_sink_manager_);
+ host_frame_sink_manager_->RegisterFrameSinkId(frame_sink_id_, this);
+ host_frame_sink_manager_->EnableSynchronizationReporting(
frame_sink_id_, "Compositing.MainFrameSynchronization.Duration");
- host_frame_sink_manager->SetFrameSinkDebugLabel(frame_sink_id_,
- "DelegatedFrameHost");
+ host_frame_sink_manager_->SetFrameSinkDebugLabel(frame_sink_id_,
+ "DelegatedFrameHost");
CreateCompositorFrameSinkSupport();
}
@@ -62,10 +63,8 @@ DelegatedFrameHost::~DelegatedFrameHost() {
factory->GetContextFactory()->RemoveObserver(this);
ResetCompositorFrameSinkSupport();
-
- viz::HostFrameSinkManager* host_frame_sink_manager =
- factory->GetContextFactoryPrivate()->GetHostFrameSinkManager();
- host_frame_sink_manager->InvalidateFrameSinkId(frame_sink_id_);
+ DCHECK(host_frame_sink_manager_);
+ host_frame_sink_manager_->InvalidateFrameSinkId(frame_sink_id_);
}
void DelegatedFrameHost::WasShown(
@@ -142,15 +141,14 @@ void DelegatedFrameHost::ProcessCopyOutputRequest(
gfx::Vector2d(area.width(), area.height()),
gfx::Vector2d(result_selection.width(), result_selection.height()));
}
-
- GetHostFrameSinkManager()->RequestCopyOfOutput(
+ DCHECK(host_frame_sink_manager_);
+ host_frame_sink_manager_->RequestCopyOfOutput(
viz::SurfaceId(frame_sink_id_, pending_local_surface_id_),
std::move(request));
}
bool DelegatedFrameHost::CanCopyFromCompositingSurface() const {
- return (enable_viz_ || support_) && HasFallbackSurface() &&
- active_device_scale_factor_ != 0.f;
+ return HasFallbackSurface() && active_device_scale_factor_ != 0.f;
}
bool DelegatedFrameHost::TransformPointToLocalCoordSpaceLegacy(
@@ -170,19 +168,6 @@ bool DelegatedFrameHost::TransformPointToLocalCoordSpaceLegacy(
transformed_point);
}
-bool DelegatedFrameHost::TransformPointToCoordSpaceForView(
- const gfx::PointF& point,
- RenderWidgetHostViewBase* target_view,
- gfx::PointF* transformed_point,
- viz::EventSource source) {
- if (!HasFallbackSurface())
- return false;
-
- return target_view->TransformPointToLocalCoordSpace(
- point, viz::SurfaceId(frame_sink_id_, active_local_surface_id_),
- transformed_point, source);
-}
-
void DelegatedFrameHost::SetNeedsBeginFrames(bool needs_begin_frames) {
if (enable_viz_) {
NOTIMPLEMENTED();
@@ -334,41 +319,13 @@ void DelegatedFrameHost::OnBeginFramePausedChanged(bool paused) {
void DelegatedFrameHost::OnFirstSurfaceActivation(
const viz::SurfaceInfo& surface_info) {
- // If this is the first Surface created after navigation, notify |client_|.
- // If the Surface was created before navigation, drop it.
- uint32_t parent_sequence_number =
- surface_info.id().local_surface_id().parent_sequence_number();
- uint32_t latest_parent_sequence_number =
- pending_local_surface_id_.parent_sequence_number();
- // If |latest_parent_sequence_number| is less than
- // |first_parent_sequence_number_after_navigation_|, then the parent id has
- // wrapped around. Make sure that case is covered.
- if (parent_sequence_number >=
- first_parent_sequence_number_after_navigation_ ||
- (latest_parent_sequence_number <
- first_parent_sequence_number_after_navigation_ &&
- parent_sequence_number <= latest_parent_sequence_number)) {
- if (!received_frame_after_navigation_) {
- received_frame_after_navigation_ = true;
- client_->DidReceiveFirstFrameAfterNavigation();
- }
- } else {
- ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
- viz::HostFrameSinkManager* host_frame_sink_manager =
- factory->GetContextFactoryPrivate()->GetHostFrameSinkManager();
- host_frame_sink_manager->DropTemporaryReference(surface_info.id());
- return;
- }
-
// If there's no primary surface, then we don't wish to display content at
// this time (e.g. the view is hidden) and so we don't need a fallback
// surface either. Since we won't use the fallback surface, we drop the
// temporary reference here to save resources.
if (!HasPrimarySurface()) {
- ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
- viz::HostFrameSinkManager* host_frame_sink_manager =
- factory->GetContextFactoryPrivate()->GetHostFrameSinkManager();
- host_frame_sink_manager->DropTemporaryReference(surface_info.id());
+ DCHECK(host_frame_sink_manager_);
+ host_frame_sink_manager_->DropTemporaryReference(surface_info.id());
return;
}
@@ -401,14 +358,30 @@ void DelegatedFrameHost::OnBeginFrame(const viz::BeginFrameArgs& args) {
client_->OnBeginFrame(args.frame_time);
}
+void DelegatedFrameHost::ResetFallbackToFirstNavigationSurface() {
+ if (HasFallbackSurface()) {
+ client_->DelegatedFrameHostGetLayer()->SetFallbackSurfaceId(viz::SurfaceId(
+ frame_sink_id_, first_local_surface_id_after_navigation_));
+ }
+}
+
void DelegatedFrameHost::EvictDelegatedFrame() {
- // Replaces the SurfaceLayer with a SolidColorLayer.
- client_->DelegatedFrameHostGetLayer()->SetShowSolidColorContent();
+ // Reset fallback and primary surfaces.
+ if (HasFallbackSurface()) {
+ client_->DelegatedFrameHostGetLayer()->SetFallbackSurfaceId(
+ viz::SurfaceId());
+ }
+ if (HasPrimarySurface()) {
+ client_->DelegatedFrameHostGetLayer()->SetShowPrimarySurface(
+ viz::SurfaceId(), current_frame_size_in_dip_, GetGutterColor(),
+ cc::DeadlinePolicy::UseDefaultDeadline(), false);
+ }
if (!HasSavedFrame())
return;
std::vector<viz::SurfaceId> surface_ids = {GetCurrentSurfaceId()};
- GetHostFrameSinkManager()->EvictSurfaces(surface_ids);
+ DCHECK(host_frame_sink_manager_);
+ host_frame_sink_manager_->EvictSurfaces(surface_ids);
frame_evictor_->DiscardedFrame();
}
@@ -423,16 +396,12 @@ void DelegatedFrameHost::OnCompositingStarted(ui::Compositor* compositor,
void DelegatedFrameHost::OnCompositingEnded(ui::Compositor* compositor) {}
-void DelegatedFrameHost::OnCompositingLockStateChanged(
- ui::Compositor* compositor) {
-}
-
void DelegatedFrameHost::OnCompositingChildResizing(
ui::Compositor* compositor) {}
void DelegatedFrameHost::OnCompositingShuttingDown(ui::Compositor* compositor) {
DCHECK_EQ(compositor, compositor_);
- ResetCompositor();
+ DetachFromCompositor();
DCHECK(!compositor_);
}
@@ -457,23 +426,23 @@ void DelegatedFrameHost::OnLostVizProcess() {
////////////////////////////////////////////////////////////////////////////////
// DelegatedFrameHost, private:
-void DelegatedFrameHost::SetCompositor(ui::Compositor* compositor) {
+void DelegatedFrameHost::AttachToCompositor(ui::Compositor* compositor) {
DCHECK(!compositor_);
if (!compositor)
return;
compositor_ = compositor;
compositor_->AddObserver(this);
if (should_register_frame_sink_id_)
- compositor_->AddFrameSink(frame_sink_id_);
+ compositor_->AddChildFrameSink(frame_sink_id_);
}
-void DelegatedFrameHost::ResetCompositor() {
+void DelegatedFrameHost::DetachFromCompositor() {
if (!compositor_)
return;
if (compositor_->HasObserver(this))
compositor_->RemoveObserver(this);
if (should_register_frame_sink_id_)
- compositor_->RemoveFrameSink(frame_sink_id_);
+ compositor_->RemoveChildFrameSink(frame_sink_id_);
compositor_ = nullptr;
}
@@ -494,13 +463,11 @@ void DelegatedFrameHost::CreateCompositorFrameSinkSupport() {
DCHECK(!support_);
constexpr bool is_root = false;
constexpr bool needs_sync_points = true;
- ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
- support_ = factory->GetContextFactoryPrivate()
- ->GetHostFrameSinkManager()
- ->CreateCompositorFrameSinkSupport(this, frame_sink_id_,
- is_root, needs_sync_points);
+ DCHECK(host_frame_sink_manager_);
+ support_ = host_frame_sink_manager_->CreateCompositorFrameSinkSupport(
+ this, frame_sink_id_, is_root, needs_sync_points);
if (compositor_ && should_register_frame_sink_id_)
- compositor_->AddFrameSink(frame_sink_id_);
+ compositor_->AddChildFrameSink(frame_sink_id_);
if (needs_begin_frame_)
support_->SetNeedsBeginFrame(true);
}
@@ -509,13 +476,12 @@ void DelegatedFrameHost::ResetCompositorFrameSinkSupport() {
if (!support_)
return;
if (compositor_ && should_register_frame_sink_id_)
- compositor_->RemoveFrameSink(frame_sink_id_);
+ compositor_->RemoveChildFrameSink(frame_sink_id_);
support_.reset();
}
void DelegatedFrameHost::DidNavigate() {
- first_parent_sequence_number_after_navigation_ =
- pending_local_surface_id_.parent_sequence_number();
+ first_local_surface_id_after_navigation_ = pending_local_surface_id_;
received_frame_after_navigation_ = false;
}
@@ -525,9 +491,8 @@ bool DelegatedFrameHost::IsPrimarySurfaceEvicted() const {
}
void DelegatedFrameHost::WindowTitleChanged(const std::string& title) {
- auto* host_frame_sink_manager = GetHostFrameSinkManager();
- if (host_frame_sink_manager)
- host_frame_sink_manager->SetFrameSinkDebugLabel(frame_sink_id_, title);
+ if (host_frame_sink_manager_)
+ host_frame_sink_manager_->SetFrameSinkDebugLabel(frame_sink_id_, title);
}
void DelegatedFrameHost::TakeFallbackContentFrom(DelegatedFrameHost* other) {
diff --git a/chromium/content/browser/renderer_host/delegated_frame_host.h b/chromium/content/browser/renderer_host/delegated_frame_host.h
index d8f5261cc35..b223d4708b3 100644
--- a/chromium/content/browser/renderer_host/delegated_frame_host.h
+++ b/chromium/content/browser/renderer_host/delegated_frame_host.h
@@ -17,8 +17,6 @@
#include "components/viz/host/host_frame_sink_client.h"
#include "content/browser/compositor/image_transport_factory.h"
#include "content/browser/renderer_host/dip_util.h"
-#include "content/browser/renderer_host/render_widget_host_impl.h"
-#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/common/content_export.h"
#include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h"
#include "services/viz/public/interfaces/hit_test/hit_test_region_list.mojom.h"
@@ -53,7 +51,6 @@ class CONTENT_EXPORT DelegatedFrameHostClient {
const viz::SurfaceInfo& surface_info) = 0;
virtual void OnBeginFrame(base::TimeTicks frame_time) = 0;
virtual void OnFrameTokenChanged(uint32_t frame_token) = 0;
- virtual void DidReceiveFirstFrameAfterNavigation() = 0;
};
// The DelegatedFrameHost is used to host all of the RenderWidgetHostView state
@@ -73,7 +70,6 @@ class CONTENT_EXPORT DelegatedFrameHost
// responsible for doing the appropriate [un]registration.
DelegatedFrameHost(const viz::FrameSinkId& frame_sink_id,
DelegatedFrameHostClient* client,
- bool enable_viz,
bool should_register_frame_sink_id);
~DelegatedFrameHost() override;
@@ -82,7 +78,6 @@ class CONTENT_EXPORT DelegatedFrameHost
void OnCompositingStarted(ui::Compositor* compositor,
base::TimeTicks start_time) override;
void OnCompositingEnded(ui::Compositor* compositor) override;
- void OnCompositingLockStateChanged(ui::Compositor* compositor) override;
void OnCompositingChildResizing(ui::Compositor* compositor) override;
void OnCompositingShuttingDown(ui::Compositor* compositor) override;
@@ -93,6 +88,8 @@ class CONTENT_EXPORT DelegatedFrameHost
// FrameEvictorClient implementation.
void EvictDelegatedFrame() override;
+ void ResetFallbackToFirstNavigationSurface();
+
// viz::mojom::CompositorFrameSinkClient implementation.
void DidReceiveCompositorFrameAck(
const std::vector<viz::ReturnedResource>& resources) override;
@@ -126,8 +123,8 @@ class CONTENT_EXPORT DelegatedFrameHost
const gfx::Size& dip_size,
cc::DeadlinePolicy deadline_policy);
bool HasSavedFrame() const;
- void SetCompositor(ui::Compositor* compositor);
- void ResetCompositor();
+ void AttachToCompositor(ui::Compositor* compositor);
+ void DetachFromCompositor();
// Note: |src_subrect| is specified in DIP dimensions while |output_size|
// expects pixels. If |src_subrect| is empty, the entire surface area is
// copied.
@@ -147,17 +144,6 @@ class CONTENT_EXPORT DelegatedFrameHost
const viz::SurfaceId& original_surface,
gfx::PointF* transformed_point);
- // Given a RenderWidgetHostViewBase that renders to a Surface that is
- // contained within this class' Surface, find the relative transform between
- // the Surfaces and apply it to a point. Returns false if a Surface has not
- // yet been created or if |target_view| is not a descendant RWHV from our
- // client.
- bool TransformPointToCoordSpaceForView(
- const gfx::PointF& point,
- RenderWidgetHostViewBase* target_view,
- gfx::PointF* transformed_point,
- viz::EventSource source = viz::EventSource::ANY);
-
void SetNeedsBeginFrames(bool needs_begin_frames);
void SetWantsAnimateOnlyBeginFrames();
void DidNotProduceFrame(const viz::BeginFrameAck& ack);
@@ -239,6 +225,8 @@ class CONTENT_EXPORT DelegatedFrameHost
// This is the last root background color from a swapped frame.
SkColor background_color_;
+ viz::HostFrameSinkManager* const host_frame_sink_manager_;
+
// State for rendering into a Surface.
std::unique_ptr<viz::CompositorFrameSinkSupport> support_;
@@ -249,7 +237,7 @@ class CONTENT_EXPORT DelegatedFrameHost
std::unique_ptr<viz::FrameEvictor> frame_evictor_;
- uint32_t first_parent_sequence_number_after_navigation_ = 0;
+ viz::LocalSurfaceId first_local_surface_id_after_navigation_;
bool received_frame_after_navigation_ = false;
std::vector<std::unique_ptr<viz::CopyOutputRequest>>
diff --git a/chromium/content/browser/renderer_host/delegated_frame_host_client_android.cc b/chromium/content/browser/renderer_host/delegated_frame_host_client_android.cc
new file mode 100644
index 00000000000..99604021dbd
--- /dev/null
+++ b/chromium/content/browser/renderer_host/delegated_frame_host_client_android.cc
@@ -0,0 +1,45 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/renderer_host/delegated_frame_host_client_android.h"
+
+#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_view_android.h"
+
+namespace content {
+
+DelegatedFrameHostClientAndroid::DelegatedFrameHostClientAndroid(
+ RenderWidgetHostViewAndroid* render_widget_host_view)
+ : render_widget_host_view_(render_widget_host_view) {}
+
+DelegatedFrameHostClientAndroid::~DelegatedFrameHostClientAndroid() {}
+
+void DelegatedFrameHostClientAndroid::SetBeginFrameSource(
+ viz::BeginFrameSource* begin_frame_source) {
+ render_widget_host_view_->SetBeginFrameSource(begin_frame_source);
+}
+
+void DelegatedFrameHostClientAndroid::DidReceiveCompositorFrameAck(
+ const std::vector<viz::ReturnedResource>& resources) {
+ render_widget_host_view_->DidReceiveCompositorFrameAck(resources);
+}
+
+void DelegatedFrameHostClientAndroid::DidPresentCompositorFrame(
+ uint32_t presentation_token,
+ const gfx::PresentationFeedback& feedback) {
+ render_widget_host_view_->DidPresentCompositorFrame(presentation_token,
+ feedback);
+}
+
+void DelegatedFrameHostClientAndroid::ReclaimResources(
+ const std::vector<viz::ReturnedResource>& resources) {
+ render_widget_host_view_->ReclaimResources(resources);
+}
+
+void DelegatedFrameHostClientAndroid::OnFrameTokenChanged(
+ uint32_t frame_token) {
+ render_widget_host_view_->OnFrameTokenChangedForView(frame_token);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/delegated_frame_host_client_android.h b/chromium/content/browser/renderer_host/delegated_frame_host_client_android.h
new file mode 100644
index 00000000000..967143a3fea
--- /dev/null
+++ b/chromium/content/browser/renderer_host/delegated_frame_host_client_android.h
@@ -0,0 +1,42 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_RENDERER_HOST_DELEGATED_FRAME_HOST_CLIENT_ANDROID_H_
+#define CONTENT_BROWSER_RENDERER_HOST_DELEGATED_FRAME_HOST_CLIENT_ANDROID_H_
+
+#include "base/macros.h"
+#include "content/common/content_export.h"
+#include "ui/android/delegated_frame_host_android.h"
+
+namespace content {
+
+class RenderWidgetHostViewAndroid;
+
+class CONTENT_EXPORT DelegatedFrameHostClientAndroid
+ : public ui::DelegatedFrameHostAndroid::Client {
+ public:
+ explicit DelegatedFrameHostClientAndroid(
+ RenderWidgetHostViewAndroid* render_widget_host_view);
+ ~DelegatedFrameHostClientAndroid() override;
+
+ private:
+ // DelegatedFrameHostAndroid::Client implementation.
+ void SetBeginFrameSource(viz::BeginFrameSource* begin_frame_source) override;
+ void DidPresentCompositorFrame(
+ uint32_t presentation_token,
+ const gfx::PresentationFeedback& feedback) override;
+ void DidReceiveCompositorFrameAck(
+ const std::vector<viz::ReturnedResource>& resources) override;
+ void ReclaimResources(
+ const std::vector<viz::ReturnedResource>& resources) override;
+ void OnFrameTokenChanged(uint32_t frame_token) override;
+
+ RenderWidgetHostViewAndroid* render_widget_host_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(DelegatedFrameHostClientAndroid);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_DELEGATED_FRAME_HOST_CLIENT_ANDROID_H_
diff --git a/chromium/content/browser/renderer_host/delegated_frame_host_client_aura.cc b/chromium/content/browser/renderer_host/delegated_frame_host_client_aura.cc
index 4c83aa1b8d5..b3dc666da0f 100644
--- a/chromium/content/browser/renderer_host/delegated_frame_host_client_aura.cc
+++ b/chromium/content/browser/renderer_host/delegated_frame_host_client_aura.cc
@@ -21,19 +21,20 @@ DelegatedFrameHostClientAura::DelegatedFrameHostClientAura(
DelegatedFrameHostClientAura::~DelegatedFrameHostClientAura() {}
ui::Layer* DelegatedFrameHostClientAura::DelegatedFrameHostGetLayer() const {
- return render_widget_host_view_->window_->layer();
+ return render_widget_host_view_->window()->layer();
}
bool DelegatedFrameHostClientAura::DelegatedFrameHostIsVisible() const {
- return !render_widget_host_view_->host_->is_hidden();
+ return !render_widget_host_view_->host()->is_hidden();
}
SkColor DelegatedFrameHostClientAura::DelegatedFrameHostGetGutterColor() const {
// When making an element on the page fullscreen the element's background
// may not match the page's, so use black as the gutter color to avoid
// flashes of brighter colors during the transition.
- if (render_widget_host_view_->host_->delegate() &&
- render_widget_host_view_->host_->delegate()
+ if (render_widget_host_view_->host()->delegate() &&
+ render_widget_host_view_->host()
+ ->delegate()
->IsFullscreenForCurrentTab()) {
return SK_ColorBLACK;
}
@@ -53,8 +54,4 @@ void DelegatedFrameHostClientAura::OnFrameTokenChanged(uint32_t frame_token) {
render_widget_host_view_->OnFrameTokenChangedForView(frame_token);
}
-void DelegatedFrameHostClientAura::DidReceiveFirstFrameAfterNavigation() {
- render_widget_host_view_->host_->DidReceiveFirstFrameAfterNavigation();
-}
-
} // namespace content
diff --git a/chromium/content/browser/renderer_host/delegated_frame_host_client_aura.h b/chromium/content/browser/renderer_host/delegated_frame_host_client_aura.h
index 9a7964ddc24..3df3bbb637d 100644
--- a/chromium/content/browser/renderer_host/delegated_frame_host_client_aura.h
+++ b/chromium/content/browser/renderer_host/delegated_frame_host_client_aura.h
@@ -33,7 +33,6 @@ class CONTENT_EXPORT DelegatedFrameHostClientAura
void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
void OnBeginFrame(base::TimeTicks frame_time) override;
void OnFrameTokenChanged(uint32_t frame_token) override;
- void DidReceiveFirstFrameAfterNavigation() override;
private:
RenderWidgetHostViewAura* render_widget_host_view_;
diff --git a/chromium/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc b/chromium/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc
index 5fb0c0179d5..1302730229f 100644
--- a/chromium/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc
+++ b/chromium/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc
@@ -22,7 +22,7 @@
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "mojo/public/cpp/bindings/callback_helpers.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "ui/gfx/win/direct_write.h"
diff --git a/chromium/content/browser/renderer_host/frame_connector_delegate.h b/chromium/content/browser/renderer_host/frame_connector_delegate.h
index 00a5e62ade0..d5f4343835f 100644
--- a/chromium/content/browser/renderer_host/frame_connector_delegate.h
+++ b/chromium/content/browser/renderer_host/frame_connector_delegate.h
@@ -15,7 +15,7 @@
#include "ui/gfx/geometry/rect.h"
#if defined(USE_AURA)
-#include "services/ui/public/interfaces/window_tree.mojom.h"
+#include "services/ws/public/mojom/window_tree.mojom.h"
#endif
namespace blink {
@@ -144,11 +144,6 @@ class CONTENT_EXPORT FrameConnectorDelegate {
gfx::PointF* transformed_point,
viz::EventSource source = viz::EventSource::ANY);
- // Pass acked touch events to the root view for gesture processing.
- virtual void ForwardProcessAckedTouchEvent(
- const TouchEventWithLatencyInfo& touch,
- InputEventAckState ack_result) {}
-
// Pass acked touchpad pinch gesture events to the root view for processing.
virtual void ForwardAckedTouchpadPinchGestureEvent(
const blink::WebGestureEvent& event,
@@ -183,6 +178,10 @@ class CONTENT_EXPORT FrameConnectorDelegate {
return compositor_visible_rect_;
}
+ // Returns whether the current view may be occluded or distorted (e.g, with
+ // CSS opacity or transform) in the parent view.
+ bool occluded_or_obscured() const { return occluded_or_obscured_; }
+
// Returns the viz::LocalSurfaceId propagated from the parent to be used by
// this child frame.
const viz::LocalSurfaceId& local_surface_id() const {
@@ -242,7 +241,7 @@ class CONTENT_EXPORT FrameConnectorDelegate {
// Embeds a WindowTreeClient in the parent. This results in the parent
// creating a window in the ui server so that this can render to the screen.
virtual void EmbedRendererWindowTreeClientInParent(
- ui::mojom::WindowTreeClientPtr window_tree_client) {}
+ ws::mojom::WindowTreeClientPtr window_tree_client) {}
#endif
// Called by RenderWidgetHostViewChildFrame when the child frame has updated
@@ -266,6 +265,8 @@ class CONTENT_EXPORT FrameConnectorDelegate {
gfx::Rect compositor_visible_rect_;
+ bool occluded_or_obscured_ = false;
+
ScreenInfo screen_info_;
gfx::Size local_frame_size_in_dip_;
gfx::Size local_frame_size_in_pixels_;
diff --git a/chromium/content/browser/renderer_host/input/autoscroll_browsertest.cc b/chromium/content/browser/renderer_host/input/autoscroll_browsertest.cc
new file mode 100644
index 00000000000..0b662c1fd05
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/autoscroll_browsertest.cc
@@ -0,0 +1,155 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/feature_list.h"
+#include "build/build_config.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/shell/browser/shell.h"
+#include "third_party/blink/public/platform/web_input_event.h"
+#include "ui/events/base_event_utils.h"
+
+using blink::WebInputEvent;
+
+namespace {
+
+const std::string kAutoscrollDataURL = R"HTML(
+ <!DOCTYPE html>
+ <meta name='viewport' content='width=device-width'/>
+ <style>
+ html, body {
+ margin: 0;
+ }
+ .spacer { height: 10000px; }
+ </style>
+ <div class=spacer></div>
+ <script>
+ document.title='ready';
+ </script>)HTML";
+} // namespace
+
+namespace content {
+
+class AutoscrollBrowserTest : public ContentBrowserTest {
+ public:
+ AutoscrollBrowserTest() {}
+ ~AutoscrollBrowserTest() override {}
+
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ command_line->AppendSwitchASCII("--enable-blink-features",
+ "MiddleClickAutoscroll");
+ }
+
+ protected:
+ RenderWidgetHostImpl* GetWidgetHost() {
+ return RenderWidgetHostImpl::From(
+ shell()->web_contents()->GetRenderViewHost()->GetWidget());
+ }
+
+ void LoadURL(const std::string& page_data) {
+ const GURL data_url("data:text/html," + page_data);
+ NavigateToURL(shell(), data_url);
+
+ RenderWidgetHostImpl* host = GetWidgetHost();
+ host->GetView()->SetSize(gfx::Size(400, 400));
+
+ base::string16 ready_title(base::ASCIIToUTF16("ready"));
+ TitleWatcher watcher(shell()->web_contents(), ready_title);
+ ignore_result(watcher.WaitAndGetTitle());
+
+ MainThreadFrameObserver main_thread_sync(host);
+ main_thread_sync.Wait();
+ }
+
+ void SimulateMiddleClick(int x, int y, int modifiers) {
+ // Simulate and send middle click mouse down.
+ blink::WebMouseEvent down_event = SyntheticWebMouseEventBuilder::Build(
+ blink::WebInputEvent::kMouseDown, x, y, modifiers);
+ down_event.button = blink::WebMouseEvent::Button::kMiddle;
+ down_event.SetTimeStamp(ui::EventTimeForNow());
+ down_event.SetPositionInScreen(x, y);
+ GetWidgetHost()->ForwardMouseEvent(down_event);
+
+ // Simulate and send middle click mouse up.
+ blink::WebMouseEvent up_event = SyntheticWebMouseEventBuilder::Build(
+ blink::WebInputEvent::kMouseUp, x, y, modifiers);
+ up_event.button = blink::WebMouseEvent::Button::kMiddle;
+ up_event.SetTimeStamp(ui::EventTimeForNow());
+ up_event.SetPositionInScreen(x, y);
+ GetWidgetHost()->ForwardMouseEvent(up_event);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AutoscrollBrowserTest);
+};
+
+// TODO(sahel): This test is flaky https://crbug.com/838769
+IN_PROC_BROWSER_TEST_F(AutoscrollBrowserTest, DISABLED_AutoscrollFling) {
+ LoadURL(kAutoscrollDataURL);
+
+ // Start autoscroll with middle click.
+ auto input_msg_watcher = std::make_unique<InputMsgWatcher>(
+ GetWidgetHost(), blink::WebInputEvent::kGestureScrollBegin);
+ SimulateMiddleClick(10, 10, blink::WebInputEvent::kNoModifiers);
+ input_msg_watcher->WaitForAck();
+
+ // The page should start scrolling with mouse move.
+ RenderFrameSubmissionObserver observer(
+ GetWidgetHost()->render_frame_metadata_provider());
+ blink::WebMouseEvent move_event = SyntheticWebMouseEventBuilder::Build(
+ blink::WebInputEvent::kMouseMove, 30, 30,
+ blink::WebInputEvent::kNoModifiers);
+ move_event.SetTimeStamp(ui::EventTimeForNow());
+ move_event.SetPositionInScreen(30, 30);
+ GetWidgetHost()->ForwardMouseEvent(move_event);
+ gfx::Vector2dF default_scroll_offset;
+ while (observer.LastRenderFrameMetadata()
+ .root_scroll_offset.value_or(default_scroll_offset)
+ .y() <= 0) {
+ observer.WaitForMetadataChange();
+ }
+}
+
+#if !defined(OS_ANDROID)
+#define MAYBE_WheelScrollingWorksAfterAutoscrollCancel \
+ WheelScrollingWorksAfterAutoscrollCancel
+#else
+#define MAYBE_WheelScrollingWorksAfterAutoscrollCancel \
+ DISABLED_WheelScrollingWorksAfterAutoscrollCancel
+#endif
+// Checks that wheel scrolling works after autoscroll cancelation.
+IN_PROC_BROWSER_TEST_F(AutoscrollBrowserTest,
+ MAYBE_WheelScrollingWorksAfterAutoscrollCancel) {
+ LoadURL(kAutoscrollDataURL);
+
+ // Start autoscroll with middle click.
+ auto input_msg_watcher = std::make_unique<InputMsgWatcher>(
+ GetWidgetHost(), blink::WebInputEvent::kGestureScrollBegin);
+ SimulateMiddleClick(10, 10, blink::WebInputEvent::kNoModifiers);
+ input_msg_watcher->WaitForAck();
+
+ // Without moving the mouse cancel the autoscroll fling with another click.
+ input_msg_watcher = std::make_unique<InputMsgWatcher>(
+ GetWidgetHost(), blink::WebInputEvent::kGestureScrollEnd);
+ SimulateMiddleClick(10, 10, blink::WebInputEvent::kNoModifiers);
+ input_msg_watcher->WaitForAck();
+
+ // The mouse wheel scrolling must work after autoscroll cancellation.
+ RenderFrameSubmissionObserver observer(
+ GetWidgetHost()->render_frame_metadata_provider());
+ blink::WebMouseWheelEvent wheel_event =
+ SyntheticWebMouseWheelEventBuilder::Build(10, 10, 0, -53, 0, true);
+ wheel_event.phase = blink::WebMouseWheelEvent::kPhaseBegan;
+ GetWidgetHost()->ForwardWheelEvent(wheel_event);
+ gfx::Vector2dF default_scroll_offset;
+ while (observer.LastRenderFrameMetadata()
+ .root_scroll_offset.value_or(default_scroll_offset)
+ .y() <= 0) {
+ observer.WaitForMetadataChange();
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/fling_browsertest.cc b/chromium/content/browser/renderer_host/input/fling_browsertest.cc
index b8371dc58c6..cba336b610d 100644
--- a/chromium/content/browser/renderer_host/input/fling_browsertest.cc
+++ b/chromium/content/browser/renderer_host/input/fling_browsertest.cc
@@ -2,13 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "build/build_config.h"
#include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/hit_test_region_observer.h"
#include "content/shell/browser/shell.h"
+#include "content/test/content_browser_test_utils_internal.h"
+#include "net/dns/mock_host_resolver.h"
#include "third_party/blink/public/platform/web_input_event.h"
#include "ui/events/base_event_utils.h"
@@ -51,16 +53,21 @@ class BrowserSideFlingBrowserTest : public ContentBrowserTest {
BrowserSideFlingBrowserTest() {}
~BrowserSideFlingBrowserTest() override {}
- void SetUpCommandLine(base::CommandLine* command_line) override {
- command_line->AppendSwitchASCII("--enable-blink-features",
- "MiddleClickAutoscroll");
- }
-
void OnSyntheticGestureCompleted(SyntheticGesture::Result result) {
EXPECT_EQ(SyntheticGesture::GESTURE_FINISHED, result);
run_loop_->Quit();
}
+ void SetUpOnMainThread() override {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ SetupCrossSiteRedirector(embedded_test_server());
+ ASSERT_TRUE(embedded_test_server()->Start());
+ }
+
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ IsolateAllSitesForTesting(command_line);
+ }
+
protected:
RenderWidgetHostImpl* GetWidgetHost() {
return RenderWidgetHostImpl::From(
@@ -82,25 +89,151 @@ class BrowserSideFlingBrowserTest : public ContentBrowserTest {
main_thread_sync.Wait();
}
- void SimulateMiddleClick(int x, int y, int modifiers) {
- // Simulate and send middle click mouse down.
- blink::WebMouseEvent down_event = SyntheticWebMouseEventBuilder::Build(
- blink::WebInputEvent::kMouseDown, x, y, modifiers);
- down_event.button = blink::WebMouseEvent::Button::kMiddle;
- down_event.SetTimeStamp(ui::EventTimeForNow());
- down_event.SetPositionInScreen(x, y);
- GetWidgetHost()->ForwardMouseEvent(down_event);
-
- // Simulate and send middle click mouse up.
- blink::WebMouseEvent up_event = SyntheticWebMouseEventBuilder::Build(
- blink::WebInputEvent::kMouseUp, x, y, modifiers);
- up_event.button = blink::WebMouseEvent::Button::kMiddle;
- up_event.SetTimeStamp(ui::EventTimeForNow());
- up_event.SetPositionInScreen(x, y);
- GetWidgetHost()->ForwardMouseEvent(up_event);
+ void LoadPageWithOOPIF() {
+ // navigate main frame to URL.
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/frame_tree/page_with_positioned_frame.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // Navigate oopif to URL.
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ ASSERT_EQ(1U, root->child_count());
+ FrameTreeNode* iframe_node = root->child_at(0);
+ GURL iframe_url(embedded_test_server()->GetURL("b.com", "/tall_page.html"));
+ NavigateFrameToURL(iframe_node, iframe_url);
+
+ WaitForHitTestDataOrChildSurfaceReady(iframe_node->current_frame_host());
+ FrameTreeVisualizer visualizer;
+ ASSERT_EQ(
+ " Site A ------------ proxies for B\n"
+ " +--Site B ------- proxies for A\n"
+ "Where A = http://a.com/\n"
+ " B = http://b.com/",
+ visualizer.DepictFrameTree(root));
+
+ root_view_ = static_cast<RenderWidgetHostViewBase*>(
+ root->current_frame_host()->GetRenderWidgetHost()->GetView());
+ child_view_ = static_cast<RenderWidgetHostViewBase*>(
+ iframe_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+ }
+
+ void SimulateTouchscreenFling(RenderWidgetHostImpl* render_widget_host) {
+ DCHECK(render_widget_host);
+ // Send a GSB to start scrolling sequence.
+ blink::WebGestureEvent gesture_scroll_begin(
+ blink::WebGestureEvent::kGestureScrollBegin,
+ blink::WebInputEvent::kNoModifiers, ui::EventTimeForNow());
+ gesture_scroll_begin.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
+ gesture_scroll_begin.data.scroll_begin.delta_hint_units =
+ blink::WebGestureEvent::ScrollUnits::kPrecisePixels;
+ gesture_scroll_begin.data.scroll_begin.delta_x_hint = 0.f;
+ gesture_scroll_begin.data.scroll_begin.delta_y_hint = -5.f;
+ const gfx::PointF scroll_location_in_widget(1, 1);
+ const gfx::PointF scroll_location_in_root =
+ child_view_ ? child_view_->TransformPointToRootCoordSpaceF(
+ scroll_location_in_widget)
+ : scroll_location_in_widget;
+ const gfx::PointF scroll_location_in_screen =
+ child_view_ ? scroll_location_in_root +
+ root_view_->GetViewBounds().OffsetFromOrigin()
+ : scroll_location_in_widget;
+ gesture_scroll_begin.SetPositionInWidget(scroll_location_in_widget);
+ gesture_scroll_begin.SetPositionInScreen(scroll_location_in_screen);
+ render_widget_host->ForwardGestureEvent(gesture_scroll_begin);
+
+ // Send a GFS.
+ blink::WebGestureEvent gesture_fling_start(
+ blink::WebGestureEvent::kGestureFlingStart,
+ blink::WebInputEvent::kNoModifiers, ui::EventTimeForNow());
+ gesture_fling_start.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
+ gesture_fling_start.data.fling_start.velocity_x = 0.f;
+ gesture_fling_start.data.fling_start.velocity_y = -2000.f;
+ gesture_fling_start.SetPositionInWidget(scroll_location_in_widget);
+ gesture_fling_start.SetPositionInScreen(scroll_location_in_screen);
+ render_widget_host->ForwardGestureEvent(gesture_fling_start);
+ }
+
+ void SimulateTouchpadFling(RenderWidgetHostImpl* render_widget_host) {
+ DCHECK(render_widget_host);
+ // Send a wheel event to start scrolling sequence.
+ auto input_msg_watcher = std::make_unique<InputMsgWatcher>(
+ GetWidgetHost(), blink::WebInputEvent::kMouseWheel);
+ blink::WebMouseWheelEvent wheel_event =
+ SyntheticWebMouseWheelEventBuilder::Build(10, 10, 0, -53, 0, true);
+ wheel_event.phase = blink::WebMouseWheelEvent::kPhaseBegan;
+ const gfx::PointF position_in_widget(1, 1);
+ const gfx::PointF position_in_root =
+ child_view_
+ ? child_view_->TransformPointToRootCoordSpaceF(position_in_widget)
+ : position_in_widget;
+ const gfx::PointF position_in_screen =
+ child_view_
+ ? position_in_root + root_view_->GetViewBounds().OffsetFromOrigin()
+ : position_in_widget;
+ wheel_event.SetPositionInWidget(position_in_widget);
+ wheel_event.SetPositionInScreen(position_in_screen);
+ render_widget_host->ForwardWheelEvent(wheel_event);
+ input_msg_watcher->WaitForAck();
+
+ // Send a GFS.
+ blink::WebGestureEvent gesture_fling_start(
+ blink::WebGestureEvent::kGestureFlingStart,
+ blink::WebInputEvent::kNoModifiers, ui::EventTimeForNow());
+ gesture_fling_start.SetSourceDevice(blink::kWebGestureDeviceTouchpad);
+ gesture_fling_start.data.fling_start.velocity_x = 0.f;
+ gesture_fling_start.data.fling_start.velocity_y = -2000.f;
+ gesture_fling_start.SetPositionInWidget(position_in_widget);
+ gesture_fling_start.SetPositionInScreen(position_in_screen);
+ render_widget_host->ForwardGestureEvent(gesture_fling_start);
+ }
+
+ void WaitForScroll() {
+ RenderFrameSubmissionObserver observer(
+ GetWidgetHost()->render_frame_metadata_provider());
+ gfx::Vector2dF default_scroll_offset;
+ // scrollTop > 0 is not enough since the first progressFling is called from
+ // FlingController::ProcessGestureFlingStart. Wait for scrollTop to exceed
+ // 100 pixels to make sure that ProgressFling has been called through
+ // FlingScheduler at least once.
+ while (observer.LastRenderFrameMetadata()
+ .root_scroll_offset.value_or(default_scroll_offset)
+ .y() <= 100) {
+ observer.WaitForMetadataChange();
+ }
+ }
+
+ void GiveItSomeTime() {
+ base::RunLoop run_loop;
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitClosure(),
+ base::TimeDelta::FromMilliseconds(10));
+ run_loop.Run();
+ }
+
+ void WaitForChildScroll() {
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ ASSERT_EQ(1U, root->child_count());
+ FrameTreeNode* iframe_node = root->child_at(0);
+ int scroll_top = EvalJs(iframe_node->current_frame_host(), "window.scrollY")
+ .ExtractDouble();
+ // scrollTop > 0 is not enough since the first progressFling is called from
+ // FlingController::ProcessGestureFlingStart. Wait for scrollTop to exceed
+ // 100 pixels to make sure that ProgressFling has been called through
+ // FlingScheduler at least once.
+ while (scroll_top < 100) {
+ GiveItSomeTime();
+ scroll_top = EvalJs(iframe_node->current_frame_host(), "window.scrollY")
+ .ExtractDouble();
+ }
}
std::unique_ptr<base::RunLoop> run_loop_;
+ RenderWidgetHostViewBase* child_view_ = nullptr;
+ RenderWidgetHostViewBase* root_view_ = nullptr;
private:
DISALLOW_COPY_AND_ASSIGN(BrowserSideFlingBrowserTest);
@@ -108,132 +241,24 @@ class BrowserSideFlingBrowserTest : public ContentBrowserTest {
IN_PROC_BROWSER_TEST_F(BrowserSideFlingBrowserTest, TouchscreenFling) {
LoadURL(kBrowserFlingDataURL);
-
- // Send a GSB to start scrolling sequence.
- blink::WebGestureEvent gesture_scroll_begin(
- blink::WebGestureEvent::kGestureScrollBegin,
- blink::WebInputEvent::kNoModifiers, ui::EventTimeForNow());
- gesture_scroll_begin.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
- gesture_scroll_begin.data.scroll_begin.delta_hint_units =
- blink::WebGestureEvent::ScrollUnits::kPrecisePixels;
- gesture_scroll_begin.data.scroll_begin.delta_x_hint = 0.f;
- gesture_scroll_begin.data.scroll_begin.delta_y_hint = -5.f;
- GetWidgetHost()->ForwardGestureEvent(gesture_scroll_begin);
-
- // Send a GFS and wait for the page to scroll making sure that fling progress
- // has started.
- blink::WebGestureEvent gesture_fling_start(
- blink::WebGestureEvent::kGestureFlingStart,
- blink::WebInputEvent::kNoModifiers, ui::EventTimeForNow());
- gesture_fling_start.SetSourceDevice(blink::kWebGestureDeviceTouchscreen);
- gesture_fling_start.data.fling_start.velocity_x = 0.f;
- gesture_fling_start.data.fling_start.velocity_y = -2000.f;
- GetWidgetHost()->ForwardGestureEvent(gesture_fling_start);
- RenderFrameSubmissionObserver observer(
- GetWidgetHost()->render_frame_metadata_provider());
- gfx::Vector2dF default_scroll_offset;
- while (observer.LastRenderFrameMetadata()
- .root_scroll_offset.value_or(default_scroll_offset)
- .y() <= 0) {
- observer.WaitForMetadataChange();
- }
+ SimulateTouchscreenFling(GetWidgetHost());
+ WaitForScroll();
}
-
IN_PROC_BROWSER_TEST_F(BrowserSideFlingBrowserTest, TouchpadFling) {
LoadURL(kBrowserFlingDataURL);
-
- // Send a wheel event to start scrolling sequence.
- auto input_msg_watcher = std::make_unique<InputMsgWatcher>(
- GetWidgetHost(), blink::WebInputEvent::kMouseWheel);
- blink::WebMouseWheelEvent wheel_event =
- SyntheticWebMouseWheelEventBuilder::Build(10, 10, 0, -53, 0, true);
- wheel_event.phase = blink::WebMouseWheelEvent::kPhaseBegan;
- GetWidgetHost()->ForwardWheelEvent(wheel_event);
- input_msg_watcher->WaitForAck();
-
- // Send a GFS and wait for the page to scroll more than 60 pixels making sure
- // that fling progress has started.
- blink::WebGestureEvent gesture_fling_start(
- blink::WebGestureEvent::kGestureFlingStart,
- blink::WebInputEvent::kNoModifiers, ui::EventTimeForNow());
- gesture_fling_start.SetSourceDevice(blink::kWebGestureDeviceTouchpad);
- gesture_fling_start.data.fling_start.velocity_x = 0.f;
- gesture_fling_start.data.fling_start.velocity_y = -2000.f;
- GetWidgetHost()->ForwardGestureEvent(gesture_fling_start);
- RenderFrameSubmissionObserver observer(
- GetWidgetHost()->render_frame_metadata_provider());
- gfx::Vector2dF default_scroll_offset;
- while (observer.LastRenderFrameMetadata()
- .root_scroll_offset.value_or(default_scroll_offset)
- .y() <= 60) {
- observer.WaitForMetadataChange();
- }
+ SimulateTouchpadFling(GetWidgetHost());
+ WaitForScroll();
}
-// TODO(sahel): This test is flaky https://crbug.com/838769
-IN_PROC_BROWSER_TEST_F(BrowserSideFlingBrowserTest, DISABLED_AutoscrollFling) {
- LoadURL(kBrowserFlingDataURL);
-
- // Start autoscroll with middle click.
- auto input_msg_watcher = std::make_unique<InputMsgWatcher>(
- GetWidgetHost(), blink::WebInputEvent::kGestureScrollBegin);
- SimulateMiddleClick(10, 10, blink::WebInputEvent::kNoModifiers);
- input_msg_watcher->WaitForAck();
-
- // The page should start scrolling with mouse move.
- RenderFrameSubmissionObserver observer(
- GetWidgetHost()->render_frame_metadata_provider());
- blink::WebMouseEvent move_event = SyntheticWebMouseEventBuilder::Build(
- blink::WebInputEvent::kMouseMove, 30, 30,
- blink::WebInputEvent::kNoModifiers);
- move_event.SetTimeStamp(ui::EventTimeForNow());
- move_event.SetPositionInScreen(30, 30);
- GetWidgetHost()->ForwardMouseEvent(move_event);
- gfx::Vector2dF default_scroll_offset;
- while (observer.LastRenderFrameMetadata()
- .root_scroll_offset.value_or(default_scroll_offset)
- .y() <= 0) {
- observer.WaitForMetadataChange();
- }
+IN_PROC_BROWSER_TEST_F(BrowserSideFlingBrowserTest, TouchscreenFlingInOOPIF) {
+ LoadPageWithOOPIF();
+ SimulateTouchscreenFling(child_view_->host());
+ WaitForChildScroll();
}
-
-#if !defined(OS_ANDROID)
-#define MAYBE_WheelScrollingWorksAfterAutoscrollCancel \
- WheelScrollingWorksAfterAutoscrollCancel
-#else
-#define MAYBE_WheelScrollingWorksAfterAutoscrollCancel \
- DISABLED_WheelScrollingWorksAfterAutoscrollCancel
-#endif
-// Checks that wheel scrolling works after autoscroll cancelation.
-IN_PROC_BROWSER_TEST_F(BrowserSideFlingBrowserTest,
- MAYBE_WheelScrollingWorksAfterAutoscrollCancel) {
- LoadURL(kBrowserFlingDataURL);
-
- // Start autoscroll with middle click.
- auto input_msg_watcher = std::make_unique<InputMsgWatcher>(
- GetWidgetHost(), blink::WebInputEvent::kGestureScrollBegin);
- SimulateMiddleClick(10, 10, blink::WebInputEvent::kNoModifiers);
- input_msg_watcher->WaitForAck();
-
- // Without moving the mouse cancel the autoscroll fling with another click.
- input_msg_watcher = std::make_unique<InputMsgWatcher>(
- GetWidgetHost(), blink::WebInputEvent::kGestureScrollEnd);
- SimulateMiddleClick(10, 10, blink::WebInputEvent::kNoModifiers);
- input_msg_watcher->WaitForAck();
-
- // The mouse wheel scrolling must work after autoscroll cancellation.
- RenderFrameSubmissionObserver observer(
- GetWidgetHost()->render_frame_metadata_provider());
- blink::WebMouseWheelEvent wheel_event =
- SyntheticWebMouseWheelEventBuilder::Build(10, 10, 0, -53, 0, true);
- wheel_event.phase = blink::WebMouseWheelEvent::kPhaseBegan;
- GetWidgetHost()->ForwardWheelEvent(wheel_event);
- gfx::Vector2dF default_scroll_offset;
- while (observer.LastRenderFrameMetadata()
- .root_scroll_offset.value_or(default_scroll_offset)
- .y() <= 0) {
- observer.WaitForMetadataChange();
- }
+IN_PROC_BROWSER_TEST_F(BrowserSideFlingBrowserTest, TouchpadFlingInOOPIF) {
+ LoadPageWithOOPIF();
+ SimulateTouchscreenFling(child_view_->host());
+ WaitForChildScroll();
}
// Disabled on MacOS because it doesn't support touchscreen scroll.
diff --git a/chromium/content/browser/renderer_host/input/fling_controller.cc b/chromium/content/browser/renderer_host/input/fling_controller.cc
index ef40b4f664a..a82ea976947 100644
--- a/chromium/content/browser/renderer_host/input/fling_controller.cc
+++ b/chromium/content/browser/renderer_host/input/fling_controller.cc
@@ -16,12 +16,23 @@ using blink::WebInputEvent;
using blink::WebGestureEvent;
namespace {
+constexpr base::TimeDelta kFrameDelta =
+ base::TimeDelta::FromSecondsD(1.0 / 60.0);
+
// Maximum time between a fling event's timestamp and the first |Progress| call
// for the fling curve to use the fling timestamp as the initial animation time.
// Two frames allows a minor delay between event creation and the first
// progress.
constexpr base::TimeDelta kMaxMicrosecondsFromFlingTimestampToFirstProgress =
- base::TimeDelta::FromMicroseconds(33333);
+ base::TimeDelta::FromSecondsD(2.0 / 60.0);
+
+// Since the progress fling is called in ProcessGestureFlingStart right after
+// processing the GFS, it is possible to have a very small delta for the first
+// event. Don't send an event with deltas smaller than the
+// |kMinInertialScrollDelta| since the renderer ignores it and the fling gets
+// cancelled in FlingController::OnGestureEventAck due to an inertial GSU with
+// ack ignored.
+const float kMinInertialScrollDelta = 0.1f;
const char* kFlingTraceName = "FlingController::HandlingGestureFling";
} // namespace
@@ -177,7 +188,14 @@ void FlingController::ProcessGestureFlingStart(
current_fling_parameters_.velocity,
current_fling_parameters_.source_device,
current_fling_parameters_.modifiers);
- ScheduleFlingProgress();
+
+ // Wait for BeginFrame to call ProgressFling when
+ // SetNeedsBeginFrameForFlingProgress is used to progress flings instead of
+ // compositor animation observer (happens on Android WebView).
+ if (scheduler_client_->NeedsBeginFrameForFlingProgress())
+ ScheduleFlingProgress();
+ else
+ ProgressFling(base::TimeTicks::Now());
}
void FlingController::ScheduleFlingProgress() {
@@ -206,16 +224,34 @@ void FlingController::ProgressFling(base::TimeTicks current_time) {
}
if (!has_fling_animation_started_) {
- // Guard against invalid, future or sufficiently stale start times, as there
- // are no guarantees fling event and progress timestamps are compatible.
- if (current_fling_parameters_.start_time.is_null() ||
- current_time <= current_fling_parameters_.start_time ||
- current_time >= current_fling_parameters_.start_time +
- kMaxMicrosecondsFromFlingTimestampToFirstProgress) {
+ // Guard against invalid as there are no guarantees fling event and progress
+ // timestamps are compatible.
+ if (current_fling_parameters_.start_time.is_null()) {
current_fling_parameters_.start_time = current_time;
ScheduleFlingProgress();
return;
}
+
+ // If the first time that progressFling is called is more than two frames
+ // later than the fling start time, delay the fling start time to one frame
+ // prior to the current time. This makes sure that at least one progress
+ // event is sent while the fling is active even when the fling duration is
+ // short (samll velocity) and the time delta between its timestamp and its
+ // processing time is big (e.g. When a GFS gets bubbled from an oopif).
+ if (current_time >= current_fling_parameters_.start_time +
+ kMaxMicrosecondsFromFlingTimestampToFirstProgress) {
+ current_fling_parameters_.start_time = current_time - kFrameDelta;
+ }
+ }
+
+ // ProgressFling is called inside FlingScheduler::OnAnimationStep. Sometimes
+ // the first OnAnimationStep call has the time of the last frame before
+ // AddAnimationObserver call rather than time of the first frame after
+ // AddAnimationObserver call. Do not advance the fling when current_time is
+ // less than the GFS event timestamp.
+ if (current_time <= current_fling_parameters_.start_time) {
+ ScheduleFlingProgress();
+ return;
}
gfx::Vector2dF delta_to_scroll;
@@ -223,7 +259,8 @@ void FlingController::ProgressFling(base::TimeTicks current_time) {
(current_time - current_fling_parameters_.start_time).InSecondsF(),
current_fling_parameters_.velocity, delta_to_scroll);
if (fling_is_active) {
- if (delta_to_scroll != gfx::Vector2d()) {
+ if (std::abs(delta_to_scroll.x()) > kMinInertialScrollDelta ||
+ std::abs(delta_to_scroll.y()) > kMinInertialScrollDelta) {
GenerateAndSendFlingProgressEvents(delta_to_scroll);
has_fling_animation_started_ = true;
}
@@ -419,11 +456,6 @@ bool FlingController::FlingCancellationIsDeferred() const {
return fling_booster_ && fling_booster_->fling_cancellation_is_deferred();
}
-bool FlingController::TouchscreenFlingInProgress() const {
- return fling_in_progress_ && current_fling_parameters_.source_device ==
- blink::kWebGestureDeviceTouchscreen;
-}
-
gfx::Vector2dF FlingController::CurrentFlingVelocity() const {
return current_fling_parameters_.velocity;
}
diff --git a/chromium/content/browser/renderer_host/input/fling_controller.h b/chromium/content/browser/renderer_host/input/fling_controller.h
index 869e17b79e2..56e997187ca 100644
--- a/chromium/content/browser/renderer_host/input/fling_controller.h
+++ b/chromium/content/browser/renderer_host/input/fling_controller.h
@@ -46,6 +46,8 @@ class CONTENT_EXPORT FlingControllerSchedulerClient {
virtual void DidStopFlingingOnBrowser(
base::WeakPtr<FlingController> fling_controller) = 0;
+
+ virtual bool NeedsBeginFrameForFlingProgress() = 0;
};
class CONTENT_EXPORT FlingController {
@@ -99,8 +101,6 @@ class CONTENT_EXPORT FlingController {
bool FlingCancellationIsDeferred() const;
- bool TouchscreenFlingInProgress() const;
-
gfx::Vector2dF CurrentFlingVelocity() const;
// Returns the |TouchpadTapSuppressionController| instance.
diff --git a/chromium/content/browser/renderer_host/input/fling_controller_unittest.cc b/chromium/content/browser/renderer_host/input/fling_controller_unittest.cc
index 9f658accb9f..3478d4eb08e 100644
--- a/chromium/content/browser/renderer_host/input/fling_controller_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/fling_controller_unittest.cc
@@ -6,6 +6,7 @@
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
+#include "build/build_config.h"
#include "content/browser/renderer_host/input/gesture_event_queue.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/base_event_utils.h"
@@ -32,14 +33,15 @@ class FakeFlingController : public FlingController {
bool FlingBoosted() const { return fling_booster_->fling_boosted(); }
};
-class FlingControllerTest : public testing::Test,
- public GestureEventQueueClient,
+class FlingControllerTest : public GestureEventQueueClient,
public FlingControllerEventSenderClient,
- public FlingControllerSchedulerClient {
+ public FlingControllerSchedulerClient,
+ public testing::TestWithParam<bool> {
public:
// testing::Test
FlingControllerTest()
- : scoped_task_environment_(
+ : needs_begin_frame_for_fling_progress_(GetParam()),
+ scoped_task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::UI) {}
~FlingControllerTest() override {}
@@ -62,9 +64,14 @@ class FlingControllerTest : public testing::Test,
void SendGeneratedWheelEvent(
const MouseWheelEventWithLatencyInfo& wheel_event) override {
last_sent_wheel_ = wheel_event.event;
+ first_wheel_event_sent_ = true;
+
+ if (wheel_event.event.momentum_phase == WebMouseWheelEvent::kPhaseEnded)
+ first_wheel_event_sent_ = false;
}
void SendGeneratedGestureScrollEvents(
const GestureEventWithLatencyInfo& gesture_event) override {
+ sent_scroll_gesture_count_++;
last_sent_gesture_ = gesture_event.event;
}
@@ -78,10 +85,14 @@ class FlingControllerTest : public testing::Test,
base::WeakPtr<FlingController> fling_controller) override {
notified_client_after_fling_stop_ = true;
}
+ bool NeedsBeginFrameForFlingProgress() override {
+ return needs_begin_frame_for_fling_progress_;
+ }
void SimulateFlingStart(blink::WebGestureDevice source_device,
const gfx::Vector2dF& velocity) {
scheduled_next_fling_progress_ = false;
+ sent_scroll_gesture_count_ = 0;
WebGestureEvent fling_start(WebInputEvent::kGestureFlingStart, 0,
base::TimeTicks::Now(), source_device);
fling_start.data.fling_start.velocity_x = velocity.x();
@@ -121,13 +132,19 @@ class FlingControllerTest : public testing::Test,
bool last_fling_cancel_filtered_;
bool scheduled_next_fling_progress_;
bool notified_client_after_fling_stop_;
+ bool first_wheel_event_sent_ = false;
+ int sent_scroll_gesture_count_ = 0;
private:
+ bool needs_begin_frame_for_fling_progress_;
base::test::ScopedTaskEnvironment scoped_task_environment_;
std::unique_ptr<GestureEventQueue> queue_;
+ DISALLOW_COPY_AND_ASSIGN(FlingControllerTest);
};
-TEST_F(FlingControllerTest,
+INSTANTIATE_TEST_CASE_P(, FlingControllerTest, testing::Bool());
+
+TEST_P(FlingControllerTest,
ControllerSendsWheelEndOnTouchpadFlingWithZeroVelocity) {
SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF());
// The controller doesn't start a fling and sends a wheel end event
@@ -138,7 +155,7 @@ TEST_F(FlingControllerTest,
EXPECT_EQ(0.f, last_sent_wheel_.delta_y);
}
-TEST_F(FlingControllerTest,
+TEST_P(FlingControllerTest,
ControllerSendsGSEOnTouchscreenFlingWithZeroVelocity) {
SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, gfx::Vector2dF());
// The controller doesn't start a fling and sends a GSE immediately.
@@ -146,14 +163,25 @@ TEST_F(FlingControllerTest,
EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType());
}
-TEST_F(FlingControllerTest, ControllerHandlesTouchpadGestureFling) {
+// TODO(https://crbug.com/836996): Timing-dependent flakes on some platforms.
+TEST_P(FlingControllerTest, DISABLED_ControllerHandlesTouchpadGestureFling) {
base::TimeTicks progress_time = base::TimeTicks::Now();
SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(1000, 0));
EXPECT_TRUE(FlingInProgress());
- // The first wheel event must have momentum_phase == KPhaseBegan.
+ // Processing GFS will send the first fling prgoress event if the time delta
+ // between the timestamp of the GFS and the time that ProcessGestureFlingStart
+ // is called is large enough.
+ bool process_GFS_sent_first_event = first_wheel_event_sent_;
+
progress_time += base::TimeDelta::FromMilliseconds(17);
ProgressFling(progress_time);
- EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, last_sent_wheel_.momentum_phase);
+
+ if (!process_GFS_sent_first_event) {
+ EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, last_sent_wheel_.momentum_phase);
+ } else {
+ EXPECT_EQ(WebMouseWheelEvent::kPhaseChanged,
+ last_sent_wheel_.momentum_phase);
+ }
EXPECT_GT(last_sent_wheel_.delta_x, 0.f);
// The rest of the wheel events must have momentum_phase == KPhaseChanged.
@@ -176,7 +204,8 @@ TEST_F(FlingControllerTest, ControllerHandlesTouchpadGestureFling) {
EXPECT_EQ(0.f, last_sent_wheel_.delta_y);
}
-TEST_F(FlingControllerTest, ControllerHandlesTouchscreenGestureFling) {
+// TODO(https://crbug.com/836996): Timing-dependent flakes on some platforms.
+TEST_P(FlingControllerTest, DISABLED_ControllerHandlesTouchscreenGestureFling) {
base::TimeTicks progress_time = base::TimeTicks::Now();
SimulateFlingStart(blink::kWebGestureDeviceTouchscreen,
gfx::Vector2dF(1000, 0));
@@ -202,13 +231,25 @@ TEST_F(FlingControllerTest, ControllerHandlesTouchscreenGestureFling) {
EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType());
}
-TEST_F(FlingControllerTest, ControllerSendsWheelEndWhenTouchpadFlingIsOver) {
+// TODO(https://crbug.com/836996): Timing-dependent flakes on some platforms.
+TEST_P(FlingControllerTest,
+ DISABLED_ControllerSendsWheelEndWhenTouchpadFlingIsOver) {
base::TimeTicks progress_time = base::TimeTicks::Now();
SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(100, 0));
EXPECT_TRUE(FlingInProgress());
+ // Processing GFS will send the first fling prgoress event if the time delta
+ // between the timestamp of the GFS and the time that ProcessGestureFlingStart
+ // is called is large enough.
+ bool process_GFS_sent_first_event = first_wheel_event_sent_;
+
progress_time += base::TimeDelta::FromMilliseconds(17);
ProgressFling(progress_time);
- EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, last_sent_wheel_.momentum_phase);
+ if (!process_GFS_sent_first_event) {
+ EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, last_sent_wheel_.momentum_phase);
+ } else {
+ EXPECT_EQ(WebMouseWheelEvent::kPhaseChanged,
+ last_sent_wheel_.momentum_phase);
+ }
EXPECT_GT(last_sent_wheel_.delta_x, 0.f);
progress_time += base::TimeDelta::FromMilliseconds(17);
@@ -226,7 +267,9 @@ TEST_F(FlingControllerTest, ControllerSendsWheelEndWhenTouchpadFlingIsOver) {
EXPECT_EQ(0.f, last_sent_wheel_.delta_y);
}
-TEST_F(FlingControllerTest, ControllerSendsGSEWhenTouchscreenFlingIsOver) {
+// TODO(https://crbug.com/836996): Timing-dependent flakes on some platforms.
+TEST_P(FlingControllerTest,
+ DISABLED_ControllerSendsGSEWhenTouchscreenFlingIsOver) {
base::TimeTicks progress_time = base::TimeTicks::Now();
SimulateFlingStart(blink::kWebGestureDeviceTouchscreen,
gfx::Vector2dF(100, 0));
@@ -247,14 +290,25 @@ TEST_F(FlingControllerTest, ControllerSendsGSEWhenTouchscreenFlingIsOver) {
EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType());
}
-TEST_F(FlingControllerTest,
- EarlyTouchpadFlingCancelationOnInertialGSUAckNotConsumed) {
+// TODO(https://crbug.com/836996): Timing-dependent flakes on some platforms.
+TEST_P(FlingControllerTest,
+ DISABLED_EarlyTouchpadFlingCancelationOnInertialGSUAckNotConsumed) {
base::TimeTicks progress_time = base::TimeTicks::Now();
SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(1000, 0));
EXPECT_TRUE(FlingInProgress());
+ // Processing GFS will send the first fling prgoress event if the time delta
+ // between the timestamp of the GFS and the time that ProcessGestureFlingStart
+ // is called is large enough.
+ bool process_GFS_sent_first_event = first_wheel_event_sent_;
+
progress_time += base::TimeDelta::FromMilliseconds(17);
ProgressFling(progress_time);
- EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, last_sent_wheel_.momentum_phase);
+ if (!process_GFS_sent_first_event) {
+ EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, last_sent_wheel_.momentum_phase);
+ } else {
+ EXPECT_EQ(WebMouseWheelEvent::kPhaseChanged,
+ last_sent_wheel_.momentum_phase);
+ }
EXPECT_GT(last_sent_wheel_.delta_x, 0.f);
// A non-consumed GSU ack in inertial state cancels out the rest of the fling.
@@ -272,8 +326,9 @@ TEST_F(FlingControllerTest,
EXPECT_EQ(0.f, last_sent_wheel_.delta_y);
}
-TEST_F(FlingControllerTest,
- EarlyTouchscreenFlingCancelationOnInertialGSUAckNotConsumed) {
+// TODO(https://crbug.com/836996): Timing-dependent flakes on some platforms.
+TEST_P(FlingControllerTest,
+ DISABLED_EarlyTouchscreenFlingCancelationOnInertialGSUAckNotConsumed) {
base::TimeTicks progress_time = base::TimeTicks::Now();
SimulateFlingStart(blink::kWebGestureDeviceTouchscreen,
gfx::Vector2dF(1000, 0));
@@ -298,13 +353,24 @@ TEST_F(FlingControllerTest,
EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType());
}
-TEST_F(FlingControllerTest, EarlyTouchpadFlingCancelationOnFlingStop) {
+// Flaky. https://crbug.com/836996.
+TEST_P(FlingControllerTest, DISABLED_EarlyTouchpadFlingCancelationOnFlingStop) {
base::TimeTicks progress_time = base::TimeTicks::Now();
SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(1000, 0));
EXPECT_TRUE(FlingInProgress());
+ // Processing GFS will send the first fling prgoress event if the time delta
+ // between the timestamp of the GFS and the time that ProcessGestureFlingStart
+ // is called is large enough.
+ bool process_GFS_sent_first_event = first_wheel_event_sent_;
+
progress_time += base::TimeDelta::FromMilliseconds(17);
ProgressFling(progress_time);
- EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, last_sent_wheel_.momentum_phase);
+ if (!process_GFS_sent_first_event) {
+ EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, last_sent_wheel_.momentum_phase);
+ } else {
+ EXPECT_EQ(WebMouseWheelEvent::kPhaseChanged,
+ last_sent_wheel_.momentum_phase);
+ }
EXPECT_GT(last_sent_wheel_.delta_x, 0.f);
fling_controller_->StopFling();
@@ -314,7 +380,7 @@ TEST_F(FlingControllerTest, EarlyTouchpadFlingCancelationOnFlingStop) {
EXPECT_EQ(0.f, last_sent_wheel_.delta_y);
}
-TEST_F(FlingControllerTest, EarlyTouchscreenFlingCancelationOnFlingStop) {
+TEST_P(FlingControllerTest, EarlyTouchscreenFlingCancelationOnFlingStop) {
base::TimeTicks progress_time = base::TimeTicks::Now();
SimulateFlingStart(blink::kWebGestureDeviceTouchscreen,
gfx::Vector2dF(1000, 0));
@@ -333,7 +399,7 @@ TEST_F(FlingControllerTest, EarlyTouchscreenFlingCancelationOnFlingStop) {
EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType());
}
-TEST_F(FlingControllerTest, GestureFlingCancelsFiltered) {
+TEST_P(FlingControllerTest, GestureFlingCancelsFiltered) {
// GFC without previous GFS is dropped.
SimulateFlingCancel(blink::kWebGestureDeviceTouchscreen);
EXPECT_TRUE(last_fling_cancel_filtered_);
@@ -352,7 +418,7 @@ TEST_F(FlingControllerTest, GestureFlingCancelsFiltered) {
}
// Flaky. https://crbug.com/836996.
-TEST_F(FlingControllerTest, DISABLED_GestureFlingNotCancelledBySmallTimeDelta) {
+TEST_P(FlingControllerTest, DISABLED_GestureFlingNotCancelledBySmallTimeDelta) {
base::TimeTicks progress_time = base::TimeTicks::Now();
SimulateFlingStart(blink::kWebGestureDeviceTouchscreen,
gfx::Vector2dF(1000, 0));
@@ -377,19 +443,20 @@ TEST_F(FlingControllerTest, DISABLED_GestureFlingNotCancelledBySmallTimeDelta) {
EXPECT_GT(last_sent_gesture_.data.scroll_update.delta_x, 0.f);
}
-TEST_F(FlingControllerTest, GestureFlingWithNegativeTimeDelta) {
+// TODO(https://crbug.com/836996): Timing-dependent flakes on some platforms.
+TEST_P(FlingControllerTest, DISABLED_GestureFlingWithNegativeTimeDelta) {
base::TimeTicks progress_time = base::TimeTicks::Now();
SimulateFlingStart(blink::kWebGestureDeviceTouchscreen,
gfx::Vector2dF(1000, 0));
EXPECT_TRUE(FlingInProgress());
+ int current_sent_scroll_gesture_count = sent_scroll_gesture_count_;
// If we get a negative time delta, that is, the Progress tick time happens
// before the fling's start time then we should *not* try progressing the
- // fling and instead reset the fling start time.
+ // fling.
progress_time -= base::TimeDelta::FromMilliseconds(5);
ProgressFling(progress_time);
- EXPECT_EQ(blink::kWebGestureDeviceUninitialized,
- last_sent_gesture_.SourceDevice());
+ EXPECT_EQ(current_sent_scroll_gesture_count, sent_scroll_gesture_count_);
// The rest of the progress flings must advance the fling normally.
progress_time += base::TimeDelta::FromMilliseconds(17);
@@ -402,14 +469,29 @@ TEST_F(FlingControllerTest, GestureFlingWithNegativeTimeDelta) {
EXPECT_GT(last_sent_gesture_.data.scroll_update.delta_x, 0.f);
}
-TEST_F(FlingControllerTest, ControllerBoostsTouchpadFling) {
+#if defined(OS_LINUX)
+#define MAYBE_ControllerBoostsTouchpadFling \
+ DISABLED_ControllerBoostsTouchpadFling
+#else
+#define MAYBE_ControllerBoostsTouchpadFling ControllerBoostsTouchpadFling
+#endif
+TEST_P(FlingControllerTest, MAYBE_ControllerBoostsTouchpadFling) {
base::TimeTicks progress_time = base::TimeTicks::Now();
SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(1000, 0));
EXPECT_TRUE(FlingInProgress());
- // The first wheel event must have momentum_phase == KPhaseBegan.
+ // Processing GFS will send the first fling prgoress event if the time delta
+ // between the timestamp of the GFS and the time that ProcessGestureFlingStart
+ // is called is large enough.
+ bool process_GFS_sent_first_event = first_wheel_event_sent_;
+
progress_time += base::TimeDelta::FromMilliseconds(17);
ProgressFling(progress_time);
- EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, last_sent_wheel_.momentum_phase);
+ if (!process_GFS_sent_first_event) {
+ EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, last_sent_wheel_.momentum_phase);
+ } else {
+ EXPECT_EQ(WebMouseWheelEvent::kPhaseChanged,
+ last_sent_wheel_.momentum_phase);
+ }
EXPECT_GT(last_sent_wheel_.delta_x, 0.f);
// The rest of the wheel events must have momentum_phase == KPhaseChanged.
@@ -429,7 +511,7 @@ TEST_F(FlingControllerTest, ControllerBoostsTouchpadFling) {
EXPECT_TRUE(FlingBoosted());
}
-TEST_F(FlingControllerTest, ControllerBoostsTouchscreenFling) {
+TEST_P(FlingControllerTest, ControllerBoostsTouchscreenFling) {
base::TimeTicks progress_time = base::TimeTicks::Now();
SimulateFlingStart(blink::kWebGestureDeviceTouchscreen,
gfx::Vector2dF(1000, 0));
@@ -455,7 +537,7 @@ TEST_F(FlingControllerTest, ControllerBoostsTouchscreenFling) {
EXPECT_TRUE(FlingBoosted());
}
-TEST_F(FlingControllerTest, ControllerNotifiesTheClientAfterFlingStart) {
+TEST_P(FlingControllerTest, ControllerNotifiesTheClientAfterFlingStart) {
base::TimeTicks progress_time = base::TimeTicks::Now();
SimulateFlingStart(blink::kWebGestureDeviceTouchscreen,
gfx::Vector2dF(1000, 0));
@@ -475,7 +557,7 @@ TEST_F(FlingControllerTest, ControllerNotifiesTheClientAfterFlingStart) {
EXPECT_TRUE(notified_client_after_fling_stop_);
}
-TEST_F(FlingControllerTest, MiddleClickAutoScrollFling) {
+TEST_P(FlingControllerTest, MiddleClickAutoScrollFling) {
base::TimeTicks progress_time = base::TimeTicks::Now();
SimulateFlingStart(blink::kWebGestureDeviceSyntheticAutoscroll,
gfx::Vector2dF(1000, 0));
diff --git a/chromium/content/browser/renderer_host/input/fling_scheduler.cc b/chromium/content/browser/renderer_host/input/fling_scheduler.cc
index 63a6f7cca39..02772e70c89 100644
--- a/chromium/content/browser/renderer_host/input/fling_scheduler.cc
+++ b/chromium/content/browser/renderer_host/input/fling_scheduler.cc
@@ -52,6 +52,10 @@ void FlingScheduler::DidStopFlingingOnBrowser(
host_->DidStopFlinging();
}
+bool FlingScheduler::NeedsBeginFrameForFlingProgress() {
+ return !GetCompositor();
+}
+
void FlingScheduler::ProgressFlingOnBeginFrameIfneeded(
base::TimeTicks current_time) {
// No fling is active.
diff --git a/chromium/content/browser/renderer_host/input/fling_scheduler.h b/chromium/content/browser/renderer_host/input/fling_scheduler.h
index 634904e7b14..7e263503efd 100644
--- a/chromium/content/browser/renderer_host/input/fling_scheduler.h
+++ b/chromium/content/browser/renderer_host/input/fling_scheduler.h
@@ -28,6 +28,7 @@ class CONTENT_EXPORT FlingScheduler : public FlingSchedulerBase,
base::WeakPtr<FlingController> fling_controller) override;
void DidStopFlingingOnBrowser(
base::WeakPtr<FlingController> fling_controller) override;
+ bool NeedsBeginFrameForFlingProgress() override;
// FlingSchedulerBase
void ProgressFlingOnBeginFrameIfneeded(base::TimeTicks current_time) override;
diff --git a/chromium/content/browser/renderer_host/input/fling_scheduler_android.cc b/chromium/content/browser/renderer_host/input/fling_scheduler_android.cc
index c2e968437ea..28cb2dbb720 100644
--- a/chromium/content/browser/renderer_host/input/fling_scheduler_android.cc
+++ b/chromium/content/browser/renderer_host/input/fling_scheduler_android.cc
@@ -50,6 +50,14 @@ void FlingSchedulerAndroid::DidStopFlingingOnBrowser(
host_->DidStopFlinging();
}
+bool FlingSchedulerAndroid::NeedsBeginFrameForFlingProgress() {
+ ui::WindowAndroid* window = GetRootWindow();
+ // If the root window does not have a Compositor (happens on Android
+ // WebView), we'll never receive an OnAnimate call. In this case fall back
+ // to BeginFrames coming from the host.
+ return !window || !window->GetCompositor();
+}
+
void FlingSchedulerAndroid::ProgressFlingOnBeginFrameIfneeded(
base::TimeTicks current_time) {
// If a WindowAndroid is being observed, there is no need for BeginFrames
diff --git a/chromium/content/browser/renderer_host/input/fling_scheduler_android.h b/chromium/content/browser/renderer_host/input/fling_scheduler_android.h
index cbe1e6e119d..3b54e4e97d4 100644
--- a/chromium/content/browser/renderer_host/input/fling_scheduler_android.h
+++ b/chromium/content/browser/renderer_host/input/fling_scheduler_android.h
@@ -25,6 +25,7 @@ class CONTENT_EXPORT FlingSchedulerAndroid : public FlingSchedulerBase,
base::WeakPtr<FlingController> fling_controller) override;
void DidStopFlingingOnBrowser(
base::WeakPtr<FlingController> fling_controller) override;
+ bool NeedsBeginFrameForFlingProgress() override;
// FlingSchedulerBase
void ProgressFlingOnBeginFrameIfneeded(base::TimeTicks current_time) override;
diff --git a/chromium/content/browser/renderer_host/input/fling_scheduler_mac.mm b/chromium/content/browser/renderer_host/input/fling_scheduler_mac.mm
index f2ac740bea5..f10c5d161dd 100644
--- a/chromium/content/browser/renderer_host/input/fling_scheduler_mac.mm
+++ b/chromium/content/browser/renderer_host/input/fling_scheduler_mac.mm
@@ -5,6 +5,7 @@
#include "content/browser/renderer_host/input/fling_scheduler_mac.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
#include "content/browser/renderer_host/render_widget_host_view_mac.h"
#include "ui/compositor/compositor.h"
@@ -15,20 +16,20 @@ FlingSchedulerMac::FlingSchedulerMac(RenderWidgetHostImpl* host)
FlingSchedulerMac::~FlingSchedulerMac() = default;
ui::Compositor* FlingSchedulerMac::GetCompositor() {
- if (!host_->GetView())
+ RenderWidgetHostViewBase* view = host_->GetView();
+ if (!view)
return nullptr;
- // RWHV_child_frame doesn't have DelegatedFrameHost with ui::Compositor.
- if (host_->GetView()->IsRenderWidgetHostViewChildFrame())
- return nullptr;
+ if (view->IsRenderWidgetHostViewChildFrame()) {
+ view = view->GetRootView();
+ if (!view)
+ return nullptr;
+ }
- // TODO(sahel): Uncomment this once Viz is ready on Mac.
- // https://crbug.com/833985
- /* RenderWidgetHostViewMac* view =
- static_cast<RenderWidgetHostViewMac*>(host_->GetView());
- if (view->BrowserCompositor())
- return view->BrowserCompositor()->Compositor();
- } */
+ RenderWidgetHostViewMac* mac_view =
+ static_cast<RenderWidgetHostViewMac*>(view);
+ if (mac_view->BrowserCompositor())
+ return mac_view->BrowserCompositor()->GetCompositor();
return nullptr;
}
diff --git a/chromium/content/browser/renderer_host/input/gesture_event_queue.cc b/chromium/content/browser/renderer_host/input/gesture_event_queue.cc
index a9ff466e23a..93347d9c37e 100644
--- a/chromium/content/browser/renderer_host/input/gesture_event_queue.cc
+++ b/chromium/content/browser/renderer_host/input/gesture_event_queue.cc
@@ -94,9 +94,6 @@ bool GestureEventQueue::FlingCancellationIsDeferred() const {
return fling_controller_.FlingCancellationIsDeferred();
}
-bool GestureEventQueue::TouchscreenFlingInProgress() const {
- return fling_controller_.TouchscreenFlingInProgress();
-}
gfx::Vector2dF GestureEventQueue::CurrentFlingVelocity() const {
return fling_controller_.CurrentFlingVelocity();
}
diff --git a/chromium/content/browser/renderer_host/input/gesture_event_queue.h b/chromium/content/browser/renderer_host/input/gesture_event_queue.h
index f07f3cd6220..3dec354a48a 100644
--- a/chromium/content/browser/renderer_host/input/gesture_event_queue.h
+++ b/chromium/content/browser/renderer_host/input/gesture_event_queue.h
@@ -117,8 +117,6 @@ class CONTENT_EXPORT GestureEventQueue {
bool FlingCancellationIsDeferred() const;
- bool TouchscreenFlingInProgress() const;
-
gfx::Vector2dF CurrentFlingVelocity() const;
void set_debounce_interval_time_ms_for_testing(int interval_ms) {
diff --git a/chromium/content/browser/renderer_host/input/gesture_event_queue_unittest.cc b/chromium/content/browser/renderer_host/input/gesture_event_queue_unittest.cc
index a977b1921b5..34e5da173ee 100644
--- a/chromium/content/browser/renderer_host/input/gesture_event_queue_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/gesture_event_queue_unittest.cc
@@ -107,6 +107,7 @@ class GestureEventQueueTest : public testing::Test,
base::WeakPtr<FlingController> fling_controller) override {}
void DidStopFlingingOnBrowser(
base::WeakPtr<FlingController> fling_controller) override {}
+ bool NeedsBeginFrameForFlingProgress() override { return false; }
protected:
static GestureEventQueue::Config DefaultConfig() {
@@ -213,6 +214,9 @@ class GestureEventQueueTest : public testing::Test,
}
bool FlingInProgress() { return queue()->fling_in_progress_; }
+ bool FlingCancellationIsDeferred() {
+ return queue()->FlingCancellationIsDeferred();
+ }
bool WillIgnoreNextACK() {
return queue()->ignore_next_ack_;
@@ -1100,7 +1104,9 @@ TEST_F(GestureEventQueueTest, DebounceDropsDeferredEvents) {
// suppressed when tap suppression is enabled.
TEST_F(GestureEventQueueTest, TapGetsSuppressedAfterTapDownCancellsFling) {
SetUpForTapSuppression(400);
- SimulateGestureFlingStartEvent(0, -10, blink::kWebGestureDeviceTouchscreen);
+ // The velocity of the event must be large enough to make sure that the fling
+ // is still active when the tap down happens.
+ SimulateGestureFlingStartEvent(0, -1000, blink::kWebGestureDeviceTouchscreen);
EXPECT_TRUE(FlingInProgress());
// The fling start event is not sent to the renderer.
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
@@ -1111,7 +1117,7 @@ TEST_F(GestureEventQueueTest, TapGetsSuppressedAfterTapDownCancellsFling) {
// fling cancel event is not sent to the renderer.
SimulateGestureEvent(WebInputEvent::kGestureFlingCancel,
blink::kWebGestureDeviceTouchscreen);
- EXPECT_FALSE(FlingInProgress());
+ EXPECT_TRUE(FlingCancellationIsDeferred());
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(0U, GestureEventQueueSize());
RunUntilIdle();
diff --git a/chromium/content/browser/renderer_host/input/input_router_client.h b/chromium/content/browser/renderer_host/input/input_router_client.h
index e714ee3f9c3..01c2c1fa601 100644
--- a/chromium/content/browser/renderer_host/input/input_router_client.h
+++ b/chromium/content/browser/renderer_host/input/input_router_client.h
@@ -51,9 +51,6 @@ class CONTENT_EXPORT InputRouterClient {
// from the renderer.
virtual void OnSetWhiteListedTouchAction(cc::TouchAction touch_action) = 0;
- // Called when a renderer fling has terminated.
- virtual void DidStopFlinging() = 0;
-
// Called when a GSB has started scrolling a viewport.
virtual void DidStartScrollingViewport() = 0;
diff --git a/chromium/content/browser/renderer_host/input/input_router_impl.cc b/chromium/content/browser/renderer_host/input/input_router_impl.cc
index 788b74bd305..582b96fb30c 100644
--- a/chromium/content/browser/renderer_host/input/input_router_impl.cc
+++ b/chromium/content/browser/renderer_host/input/input_router_impl.cc
@@ -215,8 +215,7 @@ void InputRouterImpl::SetForceEnableZoom(bool enabled) {
}
base::Optional<cc::TouchAction> InputRouterImpl::AllowedTouchAction() {
- return touch_action_filter_.allowed_touch_action().value_or(
- cc::kTouchActionAuto);
+ return touch_action_filter_.allowed_touch_action();
}
void InputRouterImpl::BindHost(mojom::WidgetInputHandlerHostRequest request,
@@ -257,15 +256,6 @@ void InputRouterImpl::DidOverscroll(const ui::DidOverscrollParams& params) {
client_->DidOverscroll(fling_updated_params);
}
-void InputRouterImpl::DidStopFlinging() {
- DCHECK_GT(active_renderer_fling_count_, 0);
- // Note that we're only guaranteed to get a fling end notification from the
- // renderer, not from any other consumers. Consequently, the GestureEventQueue
- // cannot use this bookkeeping for logic like tap suppression.
- --active_renderer_fling_count_;
- client_->DidStopFlinging();
-}
-
void InputRouterImpl::DidStartScrollingViewport() {
client_->DidStartScrollingViewport();
}
@@ -349,14 +339,17 @@ void InputRouterImpl::OnTouchEventAck(const TouchEventWithLatencyInfo& event,
// in some cases we may filter out sending the touchstart - catch those here.
if (WebTouchEventTraits::IsTouchSequenceStart(event.event) &&
ack_result == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) {
+ touch_action_filter_.AppendToGestureSequenceForDebugging("T");
// Touch action must be auto when there is no consumer
touch_action_filter_.OnSetTouchAction(cc::kTouchActionAuto);
+ touch_action_filter_.SetActiveTouchInProgress(true);
UpdateTouchAckTimeoutEnabled();
}
disposition_handler_->OnTouchEventAck(event, ack_source, ack_result);
if (WebTouchEventTraits::IsTouchSequenceEnd(event.event)) {
touch_action_filter_.ReportAndResetTouchAction();
+ touch_action_filter_.SetActiveTouchInProgress(false);
UpdateTouchAckTimeoutEnabled();
}
}
@@ -372,10 +365,6 @@ void InputRouterImpl::OnFilteringTouchEvent(const WebTouchEvent& touch_event) {
output_stream_validator_.Validate(touch_event);
}
-bool InputRouterImpl::TouchscreenFlingInProgress() {
- return gesture_event_queue_.TouchscreenFlingInProgress();
-}
-
void InputRouterImpl::SendGestureEventImmediately(
const GestureEventWithLatencyInfo& gesture_event) {
mojom::WidgetInputHandler::DispatchEventCallback callback = base::BindOnce(
@@ -561,11 +550,6 @@ void InputRouterImpl::GestureEventHandled(
InputEventAckStateToString(state));
if (source != InputEventAckSource::BROWSER)
client_->DecrementInFlightEventCount(source);
- if (gesture_event.event.GetType() ==
- blink::WebInputEvent::kGestureFlingStart &&
- state == INPUT_EVENT_ACK_STATE_CONSUMED) {
- ++active_renderer_fling_count_;
- }
if (overscroll) {
DCHECK_EQ(WebInputEvent::kGestureScrollUpdate,
@@ -610,7 +594,13 @@ void InputRouterImpl::OnHasTouchEventHandlers(bool has_handlers) {
}
void InputRouterImpl::ForceSetTouchActionAuto() {
+ touch_action_filter_.AppendToGestureSequenceForDebugging("F");
touch_action_filter_.OnSetTouchAction(cc::kTouchActionAuto);
+ touch_action_filter_.SetActiveTouchInProgress(true);
+}
+
+void InputRouterImpl::OnHasTouchEventHandlersForTest(bool has_handlers) {
+ touch_action_filter_.OnHasTouchEventHandlers(has_handlers);
}
void InputRouterImpl::OnSetTouchAction(cc::TouchAction touch_action) {
@@ -622,7 +612,11 @@ void InputRouterImpl::OnSetTouchAction(cc::TouchAction touch_action) {
if (!touch_event_queue_.IsPendingAckTouchStart())
return;
+ touch_action_filter_.AppendToGestureSequenceForDebugging("S");
+ touch_action_filter_.AppendToGestureSequenceForDebugging(
+ std::to_string(touch_action).c_str());
touch_action_filter_.OnSetTouchAction(touch_action);
+ touch_action_filter_.SetActiveTouchInProgress(true);
// kTouchActionNone should disable the touch ack timeout.
UpdateTouchAckTimeoutEnabled();
diff --git a/chromium/content/browser/renderer_host/input/input_router_impl.h b/chromium/content/browser/renderer_host/input/input_router_impl.h
index 53605ce1286..9f2862155d0 100644
--- a/chromium/content/browser/renderer_host/input/input_router_impl.h
+++ b/chromium/content/browser/renderer_host/input/input_router_impl.h
@@ -93,7 +93,6 @@ class CONTENT_EXPORT InputRouterImpl : public InputRouter,
uint32_t unique_touch_event_id,
InputEventAckState state) override;
void DidOverscroll(const ui::DidOverscrollParams& params) override;
- void DidStopFlinging() override;
void ImeCancelComposition() override;
void DidStartScrollingViewport() override;
void ImeCompositionRangeChanged(
@@ -110,6 +109,8 @@ class CONTENT_EXPORT InputRouterImpl : public InputRouter,
// IPC::Listener
bool OnMessageReceived(const IPC::Message& message) override;
+ void OnHasTouchEventHandlersForTest(bool has_handlers);
+
private:
friend class InputRouterImplTest;
friend class MockRenderWidgetHost;
@@ -127,7 +128,6 @@ class CONTENT_EXPORT InputRouterImpl : public InputRouter,
InputEventAckSource ack_source,
InputEventAckState ack_result) override;
void OnFilteringTouchEvent(const blink::WebTouchEvent& touch_event) override;
- bool TouchscreenFlingInProgress() override;
// GestureEventFilterClient
void SendGestureEventImmediately(
diff --git a/chromium/content/browser/renderer_host/input/input_router_impl_unittest.cc b/chromium/content/browser/renderer_host/input/input_router_impl_unittest.cc
index 5ff4766f351..e06e5c15acb 100644
--- a/chromium/content/browser/renderer_host/input/input_router_impl_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/input_router_impl_unittest.cc
@@ -134,8 +134,6 @@ class MockInputRouterImplClient : public InputRouterImplClient {
input_router_client_.DidOverscroll(params);
}
- void DidStopFlinging() override { input_router_client_.DidStopFlinging(); }
-
void DidStartScrollingViewport() override {
input_router_client_.DidStartScrollingViewport();
}
@@ -292,8 +290,13 @@ class InputRouterImplTest : public testing::Test {
!gesture.data.fling_start.velocity_x &&
!gesture.data.fling_start.velocity_y) {
// Ensure non-zero touchscreen fling velocities, as the router will
- // validate against such.
- gesture.data.fling_start.velocity_x = 5.f;
+ // validate against such. The velocity should be large enough to make
+ // sure that the fling is still active while sending the GFC.
+ gesture.data.fling_start.velocity_x = 500.f;
+ } else if (gesture.GetType() == WebInputEvent::kGestureFlingCancel) {
+ // Set prevent boosting to make sure that the GFC cancels the active
+ // fling.
+ gesture.data.fling_cancel.prevent_boosting = true;
}
input_router_->SendGestureEvent(GestureEventWithLatencyInfo(gesture));
@@ -762,7 +765,13 @@ TEST_F(InputRouterImplTest, TouchTypesIgnoringAck) {
EXPECT_FALSE(HasPendingEvents());
}
-TEST_F(InputRouterImplTest, GestureTypesIgnoringAck) {
+// TODO(https://crbug.com/866946): Test is flaky on Fuchsia.
+#if defined(OS_FUCHSIA)
+#define MAYBE_GestureTypesIgnoringAck DISABLED_GestureTypesIgnoringAck
+#else
+#define MAYBE_GestureTypesIgnoringAck GestureTypesIgnoringAck
+#endif
+TEST_F(InputRouterImplTest, MAYBE_GestureTypesIgnoringAck) {
// We test every gesture type, ensuring that the stream of gestures is valid.
const WebInputEvent::Type eventTypes[] = {
WebInputEvent::kGestureTapDown, WebInputEvent::kGestureShowPress,
@@ -1233,6 +1242,9 @@ TEST_F(InputRouterImplTest, TouchActionResetBeforeEventReachesRenderer) {
// Ensure touch action is still none, as the next touch start hasn't been
// acked yet. ScrollBegin and ScrollEnd don't require acks.
+ SimulateGestureEvent(WebInputEvent::kGestureTapDown,
+ blink::kWebGestureDeviceTouchscreen);
+ EXPECT_EQ(1U, GetAndResetDispatchedMessages().size());
SimulateGestureEvent(WebInputEvent::kGestureScrollBegin,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(0U, GetAndResetDispatchedMessages().size());
@@ -1308,6 +1320,9 @@ TEST_F(InputRouterImplTest, TouchActionResetWhenTouchHasNoConsumer) {
// Ensure we have touch-action:none. ScrollBegin and ScrollEnd don't require
// acks.
+ SimulateGestureEvent(WebInputEvent::kGestureTapDown,
+ blink::kWebGestureDeviceTouchscreen);
+ EXPECT_EQ(1U, GetAndResetDispatchedMessages().size());
SimulateGestureEvent(WebInputEvent::kGestureScrollBegin,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(0U, GetAndResetDispatchedMessages().size());
@@ -1361,6 +1376,9 @@ TEST_F(InputRouterImplTest, TouchActionResetWhenTouchHandlerRemoved) {
dispatched_messages[1]->ToEvent()->CallCallback(
INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(0U, GetAndResetDispatchedMessages().size());
+ SimulateGestureEvent(WebInputEvent::kGestureTapDown,
+ blink::kWebGestureDeviceTouchscreen);
+ EXPECT_EQ(1U, GetAndResetDispatchedMessages().size());
SimulateGestureEvent(WebInputEvent::kGestureScrollBegin,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(0U, GetAndResetDispatchedMessages().size());
@@ -1505,8 +1523,32 @@ TEST_F(InputRouterImplTest, DoubleTapGestureDependsOnFirstTap) {
EXPECT_EQ(0, client_->in_flight_event_count());
}
+class TouchpadPinchInputRouterImplTest
+ : public InputRouterImplTest,
+ public testing::WithParamInterface<bool> {
+ public:
+ TouchpadPinchInputRouterImplTest() : async_events_enabled_(GetParam()) {
+ if (async_events_enabled_) {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kTouchpadAsyncPinchEvents);
+ } else {
+ scoped_feature_list_.InitAndDisableFeature(
+ features::kTouchpadAsyncPinchEvents);
+ }
+ }
+ ~TouchpadPinchInputRouterImplTest() = default;
+
+ const bool async_events_enabled_;
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+ DISALLOW_COPY_AND_ASSIGN(TouchpadPinchInputRouterImplTest);
+};
+
+INSTANTIATE_TEST_CASE_P(, TouchpadPinchInputRouterImplTest, ::testing::Bool());
+
// Test that GesturePinchUpdate is handled specially for trackpad
-TEST_F(InputRouterImplTest, TouchpadPinchUpdate) {
+TEST_P(TouchpadPinchInputRouterImplTest, TouchpadPinchUpdate) {
// GesturePinchUpdate for trackpad sends synthetic wheel events.
// Note that the Touchscreen case is verified as NOT doing this as
// part of the ShowPressIsInOrder test.
@@ -1535,6 +1577,8 @@ TEST_F(InputRouterImplTest, TouchpadPinchUpdate) {
EXPECT_EQ(25, synthetic_wheel->PositionInScreen().y);
EXPECT_TRUE(synthetic_wheel->GetModifiers() &
blink::WebInputEvent::kControlKey);
+ EXPECT_EQ(blink::WebMouseWheelEvent::kPhaseBegan, synthetic_wheel->phase);
+ EXPECT_EQ(blink::WebInputEvent::kBlocking, synthetic_wheel->dispatch_type);
dispatched_messages[0]->ToEvent()->CallCallback(
INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
@@ -1559,24 +1603,114 @@ TEST_F(InputRouterImplTest, TouchpadPinchUpdate) {
input_event = dispatched_messages[0]->ToEvent()->Event()->web_event.get();
ASSERT_EQ(WebInputEvent::kMouseWheel, input_event->GetType());
synthetic_wheel = static_cast<const WebMouseWheelEvent*>(input_event);
+ EXPECT_EQ(blink::WebMouseWheelEvent::kPhaseChanged, synthetic_wheel->phase);
+ if (async_events_enabled_) {
+ EXPECT_EQ(blink::WebInputEvent::kEventNonBlocking,
+ synthetic_wheel->dispatch_type);
+ } else {
+ EXPECT_EQ(blink::WebInputEvent::kBlocking, synthetic_wheel->dispatch_type);
+ }
- dispatched_messages[0]->ToEvent()->CallCallback(
- INPUT_EVENT_ACK_STATE_CONSUMED);
+ if (async_events_enabled_) {
+ dispatched_messages[0]->ToEvent()->CallCallback(
+ INPUT_EVENT_ACK_STATE_IGNORED);
+ } else {
+ dispatched_messages[0]->ToEvent()->CallCallback(
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ }
// Check that the correct HANDLED pinch event was received.
EXPECT_EQ(1U, disposition_handler_->GetAndResetAckCount());
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate,
disposition_handler_->ack_event_type());
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED, disposition_handler_->ack_state());
+ if (async_events_enabled_) {
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_IGNORED, disposition_handler_->ack_state());
+ } else {
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED,
+ disposition_handler_->ack_state());
+ }
EXPECT_FLOAT_EQ(
0.3f,
disposition_handler_->acked_gesture_event().data.pinch_update.scale);
SimulateGestureEvent(WebInputEvent::kGesturePinchEnd,
blink::kWebGestureDeviceTouchpad);
+ dispatched_messages = GetAndResetDispatchedMessages();
+ ASSERT_EQ(1U, dispatched_messages.size());
+ ASSERT_TRUE(dispatched_messages[0]->ToEvent());
+ input_event = dispatched_messages[0]->ToEvent()->Event()->web_event.get();
+ ASSERT_EQ(WebInputEvent::kMouseWheel, input_event->GetType());
+ synthetic_wheel = static_cast<const WebMouseWheelEvent*>(input_event);
+ EXPECT_EQ(blink::WebMouseWheelEvent::kPhaseEnded, synthetic_wheel->phase);
+ EXPECT_EQ(blink::WebInputEvent::kEventNonBlocking,
+ synthetic_wheel->dispatch_type);
+ dispatched_messages[0]->ToEvent()->CallCallback(
+ INPUT_EVENT_ACK_STATE_IGNORED);
+
+ EXPECT_EQ(1U, disposition_handler_->GetAndResetAckCount());
+ EXPECT_EQ(WebInputEvent::kGesturePinchEnd,
+ disposition_handler_->ack_event_type());
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_IGNORED, disposition_handler_->ack_state());
+
+ // The first event is blocked. We should send following wheel events as
+ // blocking events.
+ SimulateGestureEvent(WebInputEvent::kGesturePinchBegin,
+ blink::kWebGestureDeviceTouchpad);
+ EXPECT_EQ(1U, disposition_handler_->GetAndResetAckCount());
+ ASSERT_EQ(WebInputEvent::kGesturePinchBegin,
+ disposition_handler_->ack_event_type());
+
+ SimulateGesturePinchUpdateEvent(1.5f, 20, 25, 0,
+ blink::kWebGestureDeviceTouchpad);
+
+ // Verify we actually sent a special wheel event to the renderer.
+ dispatched_messages = GetAndResetDispatchedMessages();
+ ASSERT_EQ(1U, dispatched_messages.size());
+ ASSERT_TRUE(dispatched_messages[0]->ToEvent());
+ input_event = dispatched_messages[0]->ToEvent()->Event()->web_event.get();
+ ASSERT_EQ(WebInputEvent::kMouseWheel, input_event->GetType());
+ synthetic_wheel = static_cast<const WebMouseWheelEvent*>(input_event);
+ EXPECT_TRUE(synthetic_wheel->GetModifiers() &
+ blink::WebInputEvent::kControlKey);
+ EXPECT_EQ(blink::WebMouseWheelEvent::kPhaseBegan, synthetic_wheel->phase);
+ EXPECT_EQ(blink::WebInputEvent::kBlocking, synthetic_wheel->dispatch_type);
+
+ dispatched_messages[0]->ToEvent()->CallCallback(
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ // Check that the correct handled pinch event was received.
+ EXPECT_EQ(1U, disposition_handler_->GetAndResetAckCount());
+ ASSERT_EQ(WebInputEvent::kGesturePinchUpdate,
+ disposition_handler_->ack_event_type());
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED, disposition_handler_->ack_state());
+ EXPECT_EQ(
+ 1.5f,
+ disposition_handler_->acked_gesture_event().data.pinch_update.scale);
+ EXPECT_EQ(0, client_->in_flight_event_count());
+
+ // Second a second pinch event.
+ SimulateGesturePinchUpdateEvent(0.3f, 20, 25, 0,
+ blink::kWebGestureDeviceTouchpad);
+ dispatched_messages = GetAndResetDispatchedMessages();
+ ASSERT_EQ(1U, dispatched_messages.size());
+ ASSERT_TRUE(dispatched_messages[0]->ToEvent());
+ input_event = dispatched_messages[0]->ToEvent()->Event()->web_event.get();
+ ASSERT_EQ(WebInputEvent::kMouseWheel, input_event->GetType());
+ synthetic_wheel = static_cast<const WebMouseWheelEvent*>(input_event);
+ EXPECT_EQ(blink::WebMouseWheelEvent::kPhaseChanged, synthetic_wheel->phase);
+ EXPECT_EQ(blink::WebInputEvent::kBlocking, synthetic_wheel->dispatch_type);
+
+ dispatched_messages[0]->ToEvent()->CallCallback(
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ // Check that the correct HANDLED pinch event was received.
EXPECT_EQ(1U, disposition_handler_->GetAndResetAckCount());
- ASSERT_EQ(WebInputEvent::kGesturePinchEnd,
+ EXPECT_EQ(WebInputEvent::kGesturePinchUpdate,
disposition_handler_->ack_event_type());
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED, disposition_handler_->ack_state());
+ EXPECT_FLOAT_EQ(
+ 0.3f,
+ disposition_handler_->acked_gesture_event().data.pinch_update.scale);
}
// Test proper handling of touchpad Gesture{Pinch,Scroll}Update sequences.
diff --git a/chromium/content/browser/renderer_host/input/mock_input_router_client.cc b/chromium/content/browser/renderer_host/input/mock_input_router_client.cc
index 33168e98cab..c3e8f83cce3 100644
--- a/chromium/content/browser/renderer_host/input/mock_input_router_client.cc
+++ b/chromium/content/browser/renderer_host/input/mock_input_router_client.cc
@@ -60,9 +60,6 @@ void MockInputRouterClient::OnSetWhiteListedTouchAction(
white_listed_touch_action_ = white_listed_touch_action;
}
-void MockInputRouterClient::DidStopFlinging() {
-}
-
void MockInputRouterClient::DidStartScrollingViewport() {}
void MockInputRouterClient::ForwardGestureEventWithLatencyInfo(
@@ -113,4 +110,8 @@ cc::TouchAction MockInputRouterClient::GetAndResetWhiteListedTouchAction() {
return white_listed_touch_action;
}
+bool MockInputRouterClient::NeedsBeginFrameForFlingProgress() {
+ return false;
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/mock_input_router_client.h b/chromium/content/browser/renderer_host/input/mock_input_router_client.h
index 8e161f5ff0e..508701de832 100644
--- a/chromium/content/browser/renderer_host/input/mock_input_router_client.h
+++ b/chromium/content/browser/renderer_host/input/mock_input_router_client.h
@@ -33,7 +33,6 @@ class MockInputRouterClient : public InputRouterClient,
void OnHasTouchEventHandlers(bool has_handlers) override;
void DidOverscroll(const ui::DidOverscrollParams& params) override;
void OnSetWhiteListedTouchAction(cc::TouchAction touch_action) override;
- void DidStopFlinging() override;
void DidStartScrollingViewport() override;
void ForwardWheelEventWithLatencyInfo(
const blink::WebMouseWheelEvent& wheel_event,
@@ -74,6 +73,7 @@ class MockInputRouterClient : public InputRouterClient,
base::WeakPtr<FlingController> fling_controller) override {}
void DidStopFlingingOnBrowser(
base::WeakPtr<FlingController> fling_controller) override {}
+ bool NeedsBeginFrameForFlingProgress() override;
private:
InputRouter* input_router_;
diff --git a/chromium/content/browser/renderer_host/input/motion_event_web.cc b/chromium/content/browser/renderer_host/input/motion_event_web.cc
index 7efdfac9ab5..38b3571379d 100644
--- a/chromium/content/browser/renderer_host/input/motion_event_web.cc
+++ b/chromium/content/browser/renderer_host/input/motion_event_web.cc
@@ -168,21 +168,27 @@ float MotionEventWeb::GetPressure(size_t pointer_index) const {
float MotionEventWeb::GetTiltX(size_t pointer_index) const {
DCHECK_LT(pointer_index, GetPointerCount());
- if (GetToolType(pointer_index) != ToolType::STYLUS)
- return 0.f;
-
return event_.touches[pointer_index].tilt_x;
}
float MotionEventWeb::GetTiltY(size_t pointer_index) const {
DCHECK_LT(pointer_index, GetPointerCount());
- if (GetToolType(pointer_index) != ToolType::STYLUS)
- return 0.f;
-
return event_.touches[pointer_index].tilt_y;
}
+float MotionEventWeb::GetTwist(size_t pointer_index) const {
+ DCHECK_LT(pointer_index, GetPointerCount());
+
+ return event_.touches[pointer_index].twist;
+}
+
+float MotionEventWeb::GetTangentialPressure(size_t pointer_index) const {
+ DCHECK_LT(pointer_index, GetPointerCount());
+
+ return event_.touches[pointer_index].tangential_pressure;
+}
+
base::TimeTicks MotionEventWeb::GetEventTime() const {
return event_.TimeStamp();
}
diff --git a/chromium/content/browser/renderer_host/input/motion_event_web.h b/chromium/content/browser/renderer_host/input/motion_event_web.h
index de4f1225f8c..31e26433dc0 100644
--- a/chromium/content/browser/renderer_host/input/motion_event_web.h
+++ b/chromium/content/browser/renderer_host/input/motion_event_web.h
@@ -37,6 +37,8 @@ class CONTENT_EXPORT MotionEventWeb : public ui::MotionEvent {
float GetPressure(size_t pointer_index) const override;
float GetTiltX(size_t pointer_index) const override;
float GetTiltY(size_t pointer_index) const override;
+ float GetTwist(size_t pointer_index) const override;
+ float GetTangentialPressure(size_t pointer_index) const override;
base::TimeTicks GetEventTime() const override;
ToolType GetToolType(size_t pointer_index) const override;
int GetButtonState() const override;
diff --git a/chromium/content/browser/renderer_host/input/motion_event_web_unittest.cc b/chromium/content/browser/renderer_host/input/motion_event_web_unittest.cc
index ddd36fee514..bf31318a931 100644
--- a/chromium/content/browser/renderer_host/input/motion_event_web_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/motion_event_web_unittest.cc
@@ -22,6 +22,8 @@ TEST(MotionEventWebTest, Constructor) {
const float orientations[] = {-pi, -2.f * pi / 3, -pi / 2};
const float tilts_x[] = {0.f, -180 / 4, -180 / 3};
const float tilts_y[] = {0.5f, 180 / 2, 180 / 3};
+ const float twists[] = {60, 160, 260};
+ const float tangential_pressures[] = {0.3f, 0.5f, 0.9f};
const MotionEvent::ToolType tool_types[] = {MotionEvent::ToolType::FINGER,
MotionEvent::ToolType::STYLUS,
MotionEvent::ToolType::MOUSE};
@@ -34,10 +36,14 @@ TEST(MotionEventWebTest, Constructor) {
const float tilt_x = tilts_x[i];
const float tilt_y = tilts_y[i];
const float orientation = orientations[i];
+ const float twist = twists[i];
+ const float tangential_pressure = tangential_pressures[i];
PointerProperties pp2;
pp2.orientation = orientation;
pp2.tilt_x = tilt_x;
pp2.tilt_y = tilt_y;
+ pp2.twist = twist;
+ pp2.tangential_pressure = tangential_pressure;
pp2.tool_type = tool_type;
size_t pointer_index = generic_event.PushPointer(pp2);
EXPECT_GT(pointer_index, 0u);
@@ -55,6 +61,9 @@ TEST(MotionEventWebTest, Constructor) {
<< " orientation=" << orientation;
EXPECT_NEAR(tilt_y, event.GetTiltY(pointer_index), 0.5)
<< " orientation=" << orientation;
+ EXPECT_EQ(twist, event.GetTwist(pointer_index));
+ EXPECT_EQ(tangential_pressure,
+ event.GetTangentialPressure(pointer_index));
} else {
EXPECT_EQ(0.f, event.GetTiltX(pointer_index));
EXPECT_EQ(0.f, event.GetTiltY(pointer_index));
diff --git a/chromium/content/browser/renderer_host/input/mouse_wheel_event_queue.cc b/chromium/content/browser/renderer_host/input/mouse_wheel_event_queue.cc
index 702915772e4..db69b0d9fb3 100644
--- a/chromium/content/browser/renderer_host/input/mouse_wheel_event_queue.cc
+++ b/chromium/content/browser/renderer_host/input/mouse_wheel_event_queue.cc
@@ -6,6 +6,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
#include "content/common/input/input_event_dispatch_type.h"
#include "content/public/common/content_features.h"
#include "ui/events/base_event_utils.h"
@@ -126,6 +127,7 @@ void MouseWheelEventQueue::ProcessMouseWheelAck(
event_sent_for_gesture_ack_->event.PositionInScreen());
scroll_update.resending_plugin_id = -1;
+#if !defined(OS_MACOSX)
// Swap X & Y if Shift is down and when there is no horizontal movement.
if ((event_sent_for_gesture_ack_->event.GetModifiers() &
WebInputEvent::kShiftKey) != 0 &&
@@ -134,7 +136,9 @@ void MouseWheelEventQueue::ProcessMouseWheelAck(
event_sent_for_gesture_ack_->event.delta_y;
scroll_update.data.scroll_update.delta_y =
event_sent_for_gesture_ack_->event.delta_x;
- } else {
+ } else
+#endif // OS_MACOSX
+ {
scroll_update.data.scroll_update.delta_x =
event_sent_for_gesture_ack_->event.delta_x;
scroll_update.data.scroll_update.delta_y =
diff --git a/chromium/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc b/chromium/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc
index b8f0067c4a8..51ca2edfd8c 100644
--- a/chromium/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc
@@ -15,6 +15,7 @@
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
#include "content/browser/renderer_host/input/timeout_monitor.h"
#include "content/common/input/synthetic_web_input_event_builders.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -621,4 +622,29 @@ TEST_F(MouseWheelEventQueueTest, WheelScrollingWasLatchedHistogramCheck) {
histogram_tester.ExpectBucketCount(latching_histogram_name, 1, 1);
}
+#if defined(OS_MACOSX)
+TEST_F(MouseWheelEventQueueTest, DoNotSwapXYForShiftScroll) {
+ // Send an event with shift modifier, zero value for delta X, and no direction
+ // for |rails_mode|. Do not swap the scroll direction.
+ SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+ kWheelScrollGlobalY, 0.0, 1.0, WebInputEvent::kShiftKey, false,
+ WebMouseWheelEvent::kPhaseBegan,
+ WebMouseWheelEvent::kPhaseNone, WebInputEvent::kRailsModeFree);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_TRUE(event_in_flight());
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+
+ // Receive an ACK for the mouse wheel event.
+ SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_FALSE(event_in_flight());
+ EXPECT_EQ(WebInputEvent::kMouseWheel, acked_event().GetType());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+
+ EXPECT_EQ(2U, all_sent_events().size());
+ EXPECT_EQ(0U, sent_gesture_event(1)->data.scroll_update.delta_x);
+ EXPECT_EQ(1U, sent_gesture_event(1)->data.scroll_update.delta_y);
+ EXPECT_EQ(2U, GetAndResetSentEventCount());
+}
+#endif
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/mouse_wheel_phase_handler.cc b/chromium/content/browser/renderer_host/input/mouse_wheel_phase_handler.cc
index a13243f3727..6056b1f2863 100644
--- a/chromium/content/browser/renderer_host/input/mouse_wheel_phase_handler.cc
+++ b/chromium/content/browser/renderer_host/input/mouse_wheel_phase_handler.cc
@@ -186,8 +186,9 @@ void MouseWheelPhaseHandler::ScheduleMouseWheelEndDispatching(
TRACE_EVENT_SCOPE_THREAD);
mouse_wheel_end_dispatch_timer_.Start(
FROM_HERE, timeout,
- base::Bind(&MouseWheelPhaseHandler::SendSyntheticWheelEventWithPhaseEnded,
- base::Unretained(this), should_route_event));
+ base::BindOnce(
+ &MouseWheelPhaseHandler::SendSyntheticWheelEventWithPhaseEnded,
+ base::Unretained(this), should_route_event));
}
bool MouseWheelPhaseHandler::IsWithinSlopRegion(
diff --git a/chromium/content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.cc b/chromium/content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.cc
index 78d9411c556..db224eef80f 100644
--- a/chromium/content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.cc
+++ b/chromium/content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.cc
@@ -17,6 +17,15 @@ MouseWheelRailsFilterMac::~MouseWheelRailsFilterMac() {
WebInputEvent::RailsMode MouseWheelRailsFilterMac::UpdateRailsMode(
const WebMouseWheelEvent& event) {
+ if (event.phase == WebMouseWheelEvent::kPhaseNone &&
+ event.momentum_phase == WebMouseWheelEvent::kPhaseNone) {
+ // We should only set the rails mode for trackpad wheel events. The AppKit
+ // documentation state that legacy mouse events (legacy mouse) do not have
+ // |phase| and |momentum_phase|.
+ // https://developer.apple.com/documentation/appkit/nsevent/1533550-phase.
+ return WebInputEvent::kRailsModeFree;
+ }
+
// A somewhat-arbitrary decay constant for hysteresis.
const float kDecayConstant = 0.8f;
diff --git a/chromium/content/browser/renderer_host/input/passthrough_touch_event_queue.h b/chromium/content/browser/renderer_host/input/passthrough_touch_event_queue.h
index bc5f7931272..65d881e9f48 100644
--- a/chromium/content/browser/renderer_host/input/passthrough_touch_event_queue.h
+++ b/chromium/content/browser/renderer_host/input/passthrough_touch_event_queue.h
@@ -33,8 +33,6 @@ class CONTENT_EXPORT PassthroughTouchEventQueueClient {
virtual void OnFilteringTouchEvent(
const blink::WebTouchEvent& touch_event) = 0;
-
- virtual bool TouchscreenFlingInProgress() = 0;
};
// A queue that processes a touch-event and forwards it on to the
diff --git a/chromium/content/browser/renderer_host/input/passthrough_touch_event_queue_unittest.cc b/chromium/content/browser/renderer_host/input/passthrough_touch_event_queue_unittest.cc
index 3f23c3a3ed1..718e02bf755 100644
--- a/chromium/content/browser/renderer_host/input/passthrough_touch_event_queue_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/passthrough_touch_event_queue_unittest.cc
@@ -94,8 +94,6 @@ class PassthroughTouchEventQueueTest : public testing::Test,
void OnFilteringTouchEvent(const blink::WebTouchEvent& touch_event) override {
}
- bool TouchscreenFlingInProgress() override { return false; }
-
protected:
void SetUpForTouchMoveSlopTesting(double slop_length_dips) {
slop_length_dips_ = slop_length_dips;
diff --git a/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc b/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc
index b174affcfc1..5cd15c4ff6e 100644
--- a/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc
@@ -9,13 +9,13 @@
#include "components/rappor/public/rappor_utils.h"
#include "components/rappor/test_rappor_service.h"
#include "components/ukm/test_ukm_recorder.h"
-#include "components/ukm/ukm_source.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/input/synthetic_web_input_event_builders.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/test/test_content_browser_client.h"
#include "content/test/test_render_view_host.h"
#include "content/test/test_web_contents.h"
+#include "services/metrics/public/cpp/ukm_source.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -1272,4 +1272,23 @@ TEST_F(RenderWidgetHostLatencyTrackerTest, WheelDuringMultiFingerTouch) {
ElementsAre(Bucket(14, 1)));
}
+TEST_F(RenderWidgetHostLatencyTrackerTest, TouchpadPinchEvents) {
+ ui::LatencyInfo latency;
+ latency.set_trace_id(kTraceEventId);
+ latency.set_source_event_type(ui::SourceEventType::TOUCHPAD);
+ latency.AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
+ base::TimeTicks() + base::TimeDelta::FromMilliseconds(1), 1);
+ latency.AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
+ base::TimeTicks() + base::TimeDelta::FromMilliseconds(3), 1);
+ AddFakeComponentsWithTimeStamp(
+ *tracker(), &latency,
+ base::TimeTicks() + base::TimeDelta::FromMilliseconds(5));
+ viz_tracker()->OnGpuSwapBuffersCompleted(latency);
+
+ EXPECT_TRUE(HistogramSizeEq("Event.Latency.EventToRender.TouchpadPinch", 1));
+ EXPECT_TRUE(HistogramSizeEq("Event.Latency.EndToEnd.TouchpadPinch", 1));
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/synthetic_gesture_controller_unittest.cc b/chromium/content/browser/renderer_host/input/synthetic_gesture_controller_unittest.cc
index 63a710082da..74d0eb047d9 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_gesture_controller_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/synthetic_gesture_controller_unittest.cc
@@ -68,6 +68,7 @@ WebTouchPoint::State ToWebTouchPointState(
return WebTouchPoint::kStateReleased;
case SyntheticPointerActionParams::PointerActionType::IDLE:
return WebTouchPoint::kStateStationary;
+ case SyntheticPointerActionParams::PointerActionType::LEAVE:
case SyntheticPointerActionParams::PointerActionType::NOT_INITIALIZED:
NOTREACHED()
<< "Invalid SyntheticPointerActionParams::PointerActionType.";
@@ -86,6 +87,8 @@ WebInputEvent::Type ToWebMouseEventType(
return WebInputEvent::kMouseMove;
case SyntheticPointerActionParams::PointerActionType::RELEASE:
return WebInputEvent::kMouseUp;
+ case SyntheticPointerActionParams::PointerActionType::LEAVE:
+ return WebInputEvent::kMouseLeave;
case SyntheticPointerActionParams::PointerActionType::IDLE:
case SyntheticPointerActionParams::PointerActionType::NOT_INITIALIZED:
NOTREACHED()
@@ -188,7 +191,10 @@ class MockSyntheticGestureTarget : public SyntheticGestureTarget {
class MockMoveGestureTarget : public MockSyntheticGestureTarget {
public:
- MockMoveGestureTarget() : total_abs_move_distance_length_(0) {}
+ MockMoveGestureTarget()
+ : total_abs_move_distance_length_(0),
+ precise_scrolling_deltas_(false),
+ scroll_by_page_(false) {}
~MockMoveGestureTarget() override {}
gfx::Vector2dF start_to_end_distance() const {
@@ -197,10 +203,14 @@ class MockMoveGestureTarget : public MockSyntheticGestureTarget {
float total_abs_move_distance_length() const {
return total_abs_move_distance_length_;
}
+ bool precise_scrolling_deltas() const { return precise_scrolling_deltas_; }
+ bool scroll_by_page() const { return scroll_by_page_; }
protected:
gfx::Vector2dF start_to_end_distance_;
float total_abs_move_distance_length_;
+ bool precise_scrolling_deltas_;
+ bool scroll_by_page_;
};
class MockScrollMouseTarget : public MockMoveGestureTarget {
@@ -215,6 +225,8 @@ class MockScrollMouseTarget : public MockMoveGestureTarget {
gfx::Vector2dF delta(mouse_wheel_event.delta_x, mouse_wheel_event.delta_y);
start_to_end_distance_ += delta;
total_abs_move_distance_length_ += delta.Length();
+ precise_scrolling_deltas_ = mouse_wheel_event.has_precise_scrolling_deltas;
+ scroll_by_page_ = mouse_wheel_event.scroll_by_page;
}
};
@@ -256,6 +268,28 @@ class MockMoveTouchTarget : public MockMoveGestureTarget {
bool started_;
};
+class MockFlingGestureTarget : public MockMoveGestureTarget {
+ public:
+ MockFlingGestureTarget() : fling_velocity_x_(0), fling_velocity_y_(0) {}
+ ~MockFlingGestureTarget() override {}
+
+ void DispatchInputEventToPlatform(const WebInputEvent& event) override {
+ if (event.GetType() == WebInputEvent::kGestureFlingStart) {
+ const blink::WebGestureEvent& gesture_event =
+ static_cast<const blink::WebGestureEvent&>(event);
+ fling_velocity_x_ = gesture_event.data.fling_start.velocity_x;
+ fling_velocity_y_ = gesture_event.data.fling_start.velocity_y;
+ }
+ }
+
+ float fling_velocity_x() const { return fling_velocity_x_; }
+ float fling_velocity_y() const { return fling_velocity_y_; }
+
+ private:
+ float fling_velocity_x_;
+ float fling_velocity_y_;
+};
+
class MockDragMouseTarget : public MockMoveGestureTarget {
public:
MockDragMouseTarget() : started_(false) {}
@@ -534,16 +568,20 @@ class MockSyntheticTapMouseTarget : public MockSyntheticTapGestureTarget {
class MockSyntheticPointerActionTarget : public MockSyntheticGestureTarget {
public:
- MockSyntheticPointerActionTarget() : num_actions_dispatched_(0) {}
+ MockSyntheticPointerActionTarget() : num_dispatched_pointer_actions_(0) {}
~MockSyntheticPointerActionTarget() override {}
WebInputEvent::Type type() const { return type_; }
- int num_actions_dispatched() const { return num_actions_dispatched_; }
- void reset_num_actions_dispatched() { num_actions_dispatched_ = 0; }
+ int num_dispatched_pointer_actions() const {
+ return num_dispatched_pointer_actions_;
+ }
+ void reset_num_dispatched_pointer_actions() {
+ num_dispatched_pointer_actions_ = 0;
+ }
protected:
WebInputEvent::Type type_;
- int num_actions_dispatched_;
+ int num_dispatched_pointer_actions_;
};
class MockSyntheticPointerTouchActionTarget
@@ -559,25 +597,26 @@ class MockSyntheticPointerTouchActionTarget
for (size_t i = 0; i < WebTouchEvent::kTouchesLengthCap; ++i) {
if (WebTouchPointStateToEventType(touch_event.touches[i].state) != type_)
continue;
-
- indexes_[i] = touch_event.touches[i].id;
- positions_[i] = gfx::PointF(touch_event.touches[i].PositionInWidget());
- states_[i] = touch_event.touches[i].state;
+ indexes_[num_dispatched_pointer_actions_] = i;
+ positions_[num_dispatched_pointer_actions_] =
+ gfx::PointF(touch_event.touches[i].PositionInWidget());
+ states_[num_dispatched_pointer_actions_] = touch_event.touches[i].state;
+ num_dispatched_pointer_actions_++;
}
- num_actions_dispatched_++;
}
testing::AssertionResult SyntheticTouchActionDispatchedCorrectly(
const SyntheticPointerActionParams& param,
- int index) {
+ int index,
+ int touch_index) {
if (param.pointer_action_type() ==
SyntheticPointerActionParams::PointerActionType::PRESS ||
param.pointer_action_type() ==
SyntheticPointerActionParams::PointerActionType::MOVE) {
- if (indexes_[index] != param.index()) {
+ if (indexes_[index] != touch_index) {
return testing::AssertionFailure()
<< "Pointer index at index " << index << " was "
- << indexes_[index] << ", expected " << param.index() << ".";
+ << indexes_[index] << ", expected " << touch_index << ".";
}
if (positions_[index] != param.position()) {
@@ -598,13 +637,15 @@ class MockSyntheticPointerTouchActionTarget
}
testing::AssertionResult SyntheticTouchActionListDispatchedCorrectly(
- const std::vector<SyntheticPointerActionParams>& params_list) {
+ const std::vector<SyntheticPointerActionParams>& params_list,
+ int start_index,
+ int index_array[]) {
testing::AssertionResult result = testing::AssertionSuccess();
for (size_t i = 0; i < params_list.size(); ++i) {
if (params_list[i].pointer_action_type() !=
SyntheticPointerActionParams::PointerActionType::IDLE)
result = SyntheticTouchActionDispatchedCorrectly(
- params_list[i], params_list[i].index());
+ params_list[i], start_index + i, index_array[i]);
if (result == testing::AssertionFailure())
return result;
}
@@ -630,7 +671,7 @@ class MockSyntheticPointerMouseActionTarget
position_ = gfx::PointF(mouse_event.PositionInWidget());
clickCount_ = mouse_event.click_count;
button_ = mouse_event.button;
- num_actions_dispatched_++;
+ num_dispatched_pointer_actions_++;
}
testing::AssertionResult SyntheticMouseActionDispatchedCorrectly(
@@ -1179,6 +1220,73 @@ TEST_F(SyntheticGestureControllerTest, MultiScrollGestureMouseHorizontal) {
scroll_target->start_to_end_distance().x());
}
+TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchpadSwipe) {
+ CreateControllerAndTarget<MockFlingGestureTarget>();
+
+ SyntheticSmoothMoveGestureParams params;
+ params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_WHEEL_INPUT;
+ params.start_point.SetPoint(39, 86);
+ params.distances.push_back(gfx::Vector2d(0, -132));
+ params.fling_velocity_x = 800;
+ params.fling_velocity_y = -1000;
+ params.prevent_fling = false;
+
+ std::unique_ptr<SyntheticSmoothMoveGesture> gesture(
+ new SyntheticSmoothMoveGesture(params));
+ QueueSyntheticGesture(std::move(gesture));
+ FlushInputUntilComplete();
+
+ MockFlingGestureTarget* swipe_target =
+ static_cast<MockFlingGestureTarget*>(target_);
+ EXPECT_EQ(1, num_success_);
+ EXPECT_EQ(0, num_failure_);
+ EXPECT_EQ(params.fling_velocity_x, swipe_target->fling_velocity_x());
+ EXPECT_EQ(params.fling_velocity_y, swipe_target->fling_velocity_y());
+}
+
+TEST_F(SyntheticGestureControllerTest, SingleScrollGestureMousePreciseScroll) {
+ CreateControllerAndTarget<MockScrollMouseTarget>();
+
+ SyntheticSmoothMoveGestureParams params;
+ params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_WHEEL_INPUT;
+ params.start_point.SetPoint(39, 86);
+ params.distances.push_back(gfx::Vector2d(0, -132));
+ params.precise_scrolling_deltas = true;
+
+ std::unique_ptr<SyntheticSmoothMoveGesture> gesture(
+ new SyntheticSmoothMoveGesture(params));
+ QueueSyntheticGesture(std::move(gesture));
+ FlushInputUntilComplete();
+
+ MockMoveGestureTarget* scroll_target =
+ static_cast<MockMoveGestureTarget*>(target_);
+ EXPECT_EQ(1, num_success_);
+ EXPECT_EQ(0, num_failure_);
+ EXPECT_EQ(params.precise_scrolling_deltas,
+ scroll_target->precise_scrolling_deltas());
+}
+
+TEST_F(SyntheticGestureControllerTest, SingleScrollGestureMouseScrollByPage) {
+ CreateControllerAndTarget<MockScrollMouseTarget>();
+
+ SyntheticSmoothMoveGestureParams params;
+ params.input_type = SyntheticSmoothMoveGestureParams::MOUSE_WHEEL_INPUT;
+ params.start_point.SetPoint(39, 86);
+ params.distances.push_back(gfx::Vector2d(0, -132));
+ params.scroll_by_page = true;
+
+ std::unique_ptr<SyntheticSmoothMoveGesture> gesture(
+ new SyntheticSmoothMoveGesture(params));
+ QueueSyntheticGesture(std::move(gesture));
+ FlushInputUntilComplete();
+
+ MockMoveGestureTarget* scroll_target =
+ static_cast<MockMoveGestureTarget*>(target_);
+ EXPECT_EQ(1, num_success_);
+ EXPECT_EQ(0, num_failure_);
+ EXPECT_EQ(params.scroll_by_page, scroll_target->scroll_by_page());
+}
+
void CheckIsWithinRangeMulti(float scroll_distance,
int target_distance,
SyntheticGestureTarget* target) {
@@ -1666,11 +1774,12 @@ TEST_F(SyntheticGestureControllerTest, PointerTouchAction) {
MockSyntheticPointerTouchActionTarget* pointer_touch_target =
static_cast<MockSyntheticPointerTouchActionTarget*>(target_);
+ int index_array[2] = {0, 1};
EXPECT_EQ(1, num_success_);
EXPECT_EQ(0, num_failure_);
- EXPECT_EQ(pointer_touch_target->num_actions_dispatched(), 2);
+ EXPECT_EQ(pointer_touch_target->num_dispatched_pointer_actions(), 2);
EXPECT_TRUE(pointer_touch_target->SyntheticTouchActionListDispatchedCorrectly(
- param_list));
+ param_list, 0, index_array));
// Second, send a touch release for finger 0, a touch move for finger 1.
param0.set_pointer_action_type(
@@ -1684,14 +1793,15 @@ TEST_F(SyntheticGestureControllerTest, PointerTouchAction) {
params.PushPointerActionParamsList(param_list);
gesture.reset(new SyntheticPointerAction(params));
QueueSyntheticGesture(std::move(gesture));
- pointer_touch_target->reset_num_actions_dispatched();
+ pointer_touch_target->reset_num_dispatched_pointer_actions();
FlushInputUntilComplete();
+ index_array[1] = 0;
EXPECT_EQ(2, num_success_);
EXPECT_EQ(0, num_failure_);
- EXPECT_EQ(pointer_touch_target->num_actions_dispatched(), 4);
+ EXPECT_EQ(pointer_touch_target->num_dispatched_pointer_actions(), 4);
EXPECT_TRUE(pointer_touch_target->SyntheticTouchActionListDispatchedCorrectly(
- param_list));
+ param_list, 2, index_array));
// Third, send a touch release for finger 1.
param1.set_pointer_action_type(
@@ -1701,14 +1811,14 @@ TEST_F(SyntheticGestureControllerTest, PointerTouchAction) {
params.PushPointerActionParamsList(param_list);
gesture.reset(new SyntheticPointerAction(params));
QueueSyntheticGesture(std::move(gesture));
- pointer_touch_target->reset_num_actions_dispatched();
+ pointer_touch_target->reset_num_dispatched_pointer_actions();
FlushInputUntilComplete();
EXPECT_EQ(3, num_success_);
EXPECT_EQ(0, num_failure_);
- EXPECT_EQ(pointer_touch_target->num_actions_dispatched(), 5);
+ EXPECT_EQ(pointer_touch_target->num_dispatched_pointer_actions(), 5);
EXPECT_TRUE(pointer_touch_target->SyntheticTouchActionListDispatchedCorrectly(
- param_list));
+ param_list, 4, index_array));
}
TEST_F(SyntheticGestureControllerTest, PointerMouseAction) {
@@ -1732,7 +1842,7 @@ TEST_F(SyntheticGestureControllerTest, PointerMouseAction) {
static_cast<MockSyntheticPointerMouseActionTarget*>(target_);
EXPECT_EQ(1, num_success_);
EXPECT_EQ(0, num_failure_);
- EXPECT_EQ(pointer_mouse_target->num_actions_dispatched(), 1);
+ EXPECT_EQ(pointer_mouse_target->num_dispatched_pointer_actions(), 1);
EXPECT_TRUE(
pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly(param, 0));
@@ -1743,12 +1853,12 @@ TEST_F(SyntheticGestureControllerTest, PointerMouseAction) {
params.PushPointerActionParams(param);
gesture.reset(new SyntheticPointerAction(params));
QueueSyntheticGesture(std::move(gesture));
- pointer_mouse_target->reset_num_actions_dispatched();
+ pointer_mouse_target->reset_num_dispatched_pointer_actions();
FlushInputUntilComplete();
EXPECT_EQ(2, num_success_);
EXPECT_EQ(0, num_failure_);
- EXPECT_EQ(pointer_mouse_target->num_actions_dispatched(), 2);
+ EXPECT_EQ(pointer_mouse_target->num_dispatched_pointer_actions(), 2);
EXPECT_TRUE(
pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly(param, 1));
@@ -1759,12 +1869,12 @@ TEST_F(SyntheticGestureControllerTest, PointerMouseAction) {
params.PushPointerActionParams(param);
gesture.reset(new SyntheticPointerAction(params));
QueueSyntheticGesture(std::move(gesture));
- pointer_mouse_target->reset_num_actions_dispatched();
+ pointer_mouse_target->reset_num_dispatched_pointer_actions();
FlushInputUntilComplete();
EXPECT_EQ(3, num_success_);
EXPECT_EQ(0, num_failure_);
- EXPECT_EQ(pointer_mouse_target->num_actions_dispatched(), 3);
+ EXPECT_EQ(pointer_mouse_target->num_dispatched_pointer_actions(), 3);
EXPECT_TRUE(
pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly(param, 1));
@@ -1774,14 +1884,102 @@ TEST_F(SyntheticGestureControllerTest, PointerMouseAction) {
params.PushPointerActionParams(param);
gesture.reset(new SyntheticPointerAction(params));
QueueSyntheticGesture(std::move(gesture));
- pointer_mouse_target->reset_num_actions_dispatched();
+ pointer_mouse_target->reset_num_dispatched_pointer_actions();
FlushInputUntilComplete();
EXPECT_EQ(4, num_success_);
EXPECT_EQ(0, num_failure_);
- EXPECT_EQ(pointer_mouse_target->num_actions_dispatched(), 4);
+ EXPECT_EQ(pointer_mouse_target->num_dispatched_pointer_actions(), 4);
EXPECT_TRUE(
pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly(param, 1));
}
+TEST_F(SyntheticGestureControllerTest, PointerPenAction) {
+ CreateControllerAndTarget<MockSyntheticPointerMouseActionTarget>();
+
+ // First, send a pen move.
+ SyntheticPointerActionListParams::ParamList param_list;
+ SyntheticPointerActionParams param = SyntheticPointerActionParams(
+ SyntheticPointerActionParams::PointerActionType::MOVE);
+
+ param.set_position(gfx::PointF(54, 89));
+ SyntheticPointerActionListParams params;
+ params.PushPointerActionParams(param);
+ params.gesture_source_type = SyntheticGestureParams::PEN_INPUT;
+ std::unique_ptr<SyntheticPointerAction> gesture(
+ new SyntheticPointerAction(params));
+ QueueSyntheticGesture(std::move(gesture));
+ FlushInputUntilComplete();
+
+ MockSyntheticPointerMouseActionTarget* pointer_pen_target =
+ static_cast<MockSyntheticPointerMouseActionTarget*>(target_);
+ EXPECT_EQ(1, num_success_);
+ EXPECT_EQ(0, num_failure_);
+ EXPECT_EQ(pointer_pen_target->num_dispatched_pointer_actions(), 1);
+ EXPECT_TRUE(
+ pointer_pen_target->SyntheticMouseActionDispatchedCorrectly(param, 0));
+
+ // Second, send a pen press.
+ param.set_pointer_action_type(
+ SyntheticPointerActionParams::PointerActionType::PRESS);
+ param.set_position(gfx::PointF(183, 239));
+ params.PushPointerActionParams(param);
+ gesture.reset(new SyntheticPointerAction(params));
+ QueueSyntheticGesture(std::move(gesture));
+ pointer_pen_target->reset_num_dispatched_pointer_actions();
+ FlushInputUntilComplete();
+
+ EXPECT_EQ(2, num_success_);
+ EXPECT_EQ(0, num_failure_);
+ EXPECT_EQ(pointer_pen_target->num_dispatched_pointer_actions(), 2);
+ EXPECT_TRUE(
+ pointer_pen_target->SyntheticMouseActionDispatchedCorrectly(param, 1));
+
+ // Third, send a pen move.
+ param.set_pointer_action_type(
+ SyntheticPointerActionParams::PointerActionType::MOVE);
+ param.set_position(gfx::PointF(254, 279));
+ params.PushPointerActionParams(param);
+ gesture.reset(new SyntheticPointerAction(params));
+ QueueSyntheticGesture(std::move(gesture));
+ pointer_pen_target->reset_num_dispatched_pointer_actions();
+ FlushInputUntilComplete();
+
+ EXPECT_EQ(3, num_success_);
+ EXPECT_EQ(0, num_failure_);
+ EXPECT_EQ(pointer_pen_target->num_dispatched_pointer_actions(), 3);
+ EXPECT_TRUE(
+ pointer_pen_target->SyntheticMouseActionDispatchedCorrectly(param, 1));
+
+ // Fourth, send a pen release.
+ param.set_pointer_action_type(
+ SyntheticPointerActionParams::PointerActionType::RELEASE);
+ params.PushPointerActionParams(param);
+ gesture.reset(new SyntheticPointerAction(params));
+ QueueSyntheticGesture(std::move(gesture));
+ pointer_pen_target->reset_num_dispatched_pointer_actions();
+ FlushInputUntilComplete();
+
+ EXPECT_EQ(4, num_success_);
+ EXPECT_EQ(0, num_failure_);
+ EXPECT_EQ(pointer_pen_target->num_dispatched_pointer_actions(), 4);
+ EXPECT_TRUE(
+ pointer_pen_target->SyntheticMouseActionDispatchedCorrectly(param, 1));
+
+ // Fifth, send a pen leave.
+ param.set_pointer_action_type(
+ SyntheticPointerActionParams::PointerActionType::LEAVE);
+ params.PushPointerActionParams(param);
+ gesture.reset(new SyntheticPointerAction(params));
+ QueueSyntheticGesture(std::move(gesture));
+ pointer_pen_target->reset_num_dispatched_pointer_actions();
+ FlushInputUntilComplete();
+
+ EXPECT_EQ(5, num_success_);
+ EXPECT_EQ(0, num_failure_);
+ EXPECT_EQ(pointer_pen_target->num_dispatched_pointer_actions(), 5);
+ EXPECT_TRUE(
+ pointer_pen_target->SyntheticMouseActionDispatchedCorrectly(param, 0));
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc b/chromium/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc
index c9b4679a367..f66e36f7a46 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc
+++ b/chromium/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc
@@ -81,9 +81,16 @@ void SyntheticGestureTargetAura::DispatchWebMouseWheelEventToPlatform(
return;
}
base::TimeTicks timestamp = web_wheel.TimeStamp();
+ int modifiers = ui::EF_NONE;
+ if (web_wheel.has_precise_scrolling_deltas)
+ modifiers |= ui::EF_PRECISION_SCROLLING_DELTA;
+
+ if (web_wheel.scroll_by_page)
+ modifiers |= ui::EF_SCROLL_BY_PAGE;
+
ui::MouseWheelEvent wheel_event(
gfx::Vector2d(web_wheel.delta_x, web_wheel.delta_y), gfx::Point(),
- gfx::Point(), timestamp, ui::EF_NONE, ui::EF_NONE);
+ gfx::Point(), timestamp, modifiers, ui::EF_NONE);
gfx::PointF location(web_wheel.PositionInWidget().x * device_scale_factor_,
web_wheel.PositionInWidget().y * device_scale_factor_);
wheel_event.set_location_f(location);
@@ -101,25 +108,44 @@ void SyntheticGestureTargetAura::DispatchWebMouseWheelEventToPlatform(
void SyntheticGestureTargetAura::DispatchWebGestureEventToPlatform(
const blink::WebGestureEvent& web_gesture,
const ui::LatencyInfo& latency_info) {
- DCHECK(blink::WebInputEvent::IsPinchGestureEventType(web_gesture.GetType()));
+ DCHECK(blink::WebInputEvent::IsPinchGestureEventType(web_gesture.GetType()) ||
+ blink::WebInputEvent::IsFlingGestureEventType(web_gesture.GetType()));
ui::EventType event_type = ui::WebEventTypeToEventType(web_gesture.GetType());
int flags = ui::WebEventModifiersToEventFlags(web_gesture.GetModifiers());
+ aura::Window* window = GetWindow();
+ aura::EventInjector injector;
- ui::GestureEventDetails pinch_details(event_type);
- pinch_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHPAD);
- if (event_type == ui::ET_GESTURE_PINCH_UPDATE)
- pinch_details.set_scale(web_gesture.data.pinch_update.scale);
+ if (blink::WebInputEvent::IsPinchGestureEventType(web_gesture.GetType())) {
+ ui::GestureEventDetails pinch_details(event_type);
+ pinch_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHPAD);
+ if (event_type == ui::ET_GESTURE_PINCH_UPDATE)
+ pinch_details.set_scale(web_gesture.data.pinch_update.scale);
- ui::GestureEvent pinch_event(
- web_gesture.PositionInWidget().x * device_scale_factor_,
- web_gesture.PositionInWidget().y * device_scale_factor_, flags,
- ui::EventTimeForNow(), pinch_details);
+ ui::GestureEvent pinch_event(
+ web_gesture.PositionInWidget().x * device_scale_factor_,
+ web_gesture.PositionInWidget().y * device_scale_factor_, flags,
+ ui::EventTimeForNow(), pinch_details);
- aura::Window* window = GetWindow();
- pinch_event.ConvertLocationToTarget(window, window->GetRootWindow());
+ pinch_event.ConvertLocationToTarget(window, window->GetRootWindow());
- aura::EventInjector injector;
- injector.Inject(window->GetHost(), &pinch_event);
+ injector.Inject(window->GetHost(), &pinch_event);
+ return;
+ }
+
+ ui::EventMomentumPhase momentum_phase =
+ web_gesture.GetType() == blink::WebInputEvent::kGestureFlingStart
+ ? ui::EventMomentumPhase::BEGAN
+ : ui::EventMomentumPhase::END;
+ gfx::PointF location(web_gesture.PositionInWidget().x * device_scale_factor_,
+ web_gesture.PositionInWidget().y * device_scale_factor_);
+ ui::ScrollEvent scroll_event(event_type, gfx::Point(), ui::EventTimeForNow(),
+ flags, web_gesture.data.fling_start.velocity_x,
+ web_gesture.data.fling_start.velocity_y, 0, 0, 2,
+ momentum_phase, ui::ScrollEventPhase::kNone);
+ scroll_event.set_location_f(location);
+ scroll_event.set_root_location_f(location);
+ scroll_event.ConvertLocationToTarget(window, window->GetRootWindow());
+ injector.Inject(window->GetHost(), &scroll_event);
}
void SyntheticGestureTargetAura::DispatchWebMouseEventToPlatform(
diff --git a/chromium/content/browser/renderer_host/input/synthetic_gesture_target_base.cc b/chromium/content/browser/renderer_host/input/synthetic_gesture_target_base.cc
index c238c21add2..f700f10e947 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_gesture_target_base.cc
+++ b/chromium/content/browser/renderer_host/input/synthetic_gesture_target_base.cc
@@ -99,6 +99,19 @@ void SyntheticGestureTargetBase::DispatchInputEventToPlatform(
return;
}
DispatchWebGestureEventToPlatform(web_pinch, latency_info);
+ } else if (WebInputEvent::IsFlingGestureEventType(event.GetType())) {
+ const WebGestureEvent& web_fling =
+ static_cast<const WebGestureEvent&>(event);
+ // Touchscreen swipe should be injected as touch events.
+ DCHECK_EQ(blink::kWebGestureDeviceTouchpad, web_fling.SourceDevice());
+ if (event.GetType() == WebInputEvent::kGestureFlingStart &&
+ !PointIsWithinContents(web_fling.PositionInWidget().x,
+ web_fling.PositionInWidget().y)) {
+ LOG(WARNING)
+ << "Fling coordinates are not within content bounds on FlingStart.";
+ return;
+ }
+ DispatchWebGestureEventToPlatform(web_fling, latency_info);
} else {
NOTREACHED();
}
diff --git a/chromium/content/browser/renderer_host/input/synthetic_mouse_driver.cc b/chromium/content/browser/renderer_host/input/synthetic_mouse_driver.cc
index 2547e5d210c..4a48a9684bc 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_mouse_driver.cc
+++ b/chromium/content/browser/renderer_host/input/synthetic_mouse_driver.cc
@@ -66,6 +66,10 @@ void SyntheticMouseDriver::Release(
(~SyntheticPointerActionParams::GetWebMouseEventModifier(button));
}
+void SyntheticMouseDriver::Leave(int index) {
+ NOTIMPLEMENTED();
+}
+
bool SyntheticMouseDriver::UserInputCheck(
const SyntheticPointerActionParams& params) const {
if (params.index() != 0)
@@ -85,12 +89,17 @@ bool SyntheticMouseDriver::UserInputCheck(
}
if (params.pointer_action_type() ==
- SyntheticPointerActionParams::PointerActionType::RELEASE &&
- mouse_event_.click_count <= 0) {
- return false;
+ SyntheticPointerActionParams::PointerActionType::RELEASE) {
+ if (mouse_event_.click_count <= 0)
+ return false;
+
+ int modifiers =
+ SyntheticPointerActionParams::GetWebMouseEventModifier(params.button());
+ if (!(last_modifiers_ & modifiers))
+ return false;
}
return true;
}
-} // namespace content
+} // namespace content \ No newline at end of file
diff --git a/chromium/content/browser/renderer_host/input/synthetic_mouse_driver.h b/chromium/content/browser/renderer_host/input/synthetic_mouse_driver.h
index a314788e78e..341d167134c 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_mouse_driver.h
+++ b/chromium/content/browser/renderer_host/input/synthetic_mouse_driver.h
@@ -29,16 +29,16 @@ class CONTENT_EXPORT SyntheticMouseDriver : public SyntheticPointerDriver {
void Release(int index = 0,
SyntheticPointerActionParams::Button button =
SyntheticPointerActionParams::Button::LEFT) override;
+ void Leave(int index = 0) override;
bool UserInputCheck(
const SyntheticPointerActionParams& params) const override;
protected:
blink::WebMouseEvent mouse_event_;
-
- private:
unsigned last_modifiers_;
+ private:
DISALLOW_COPY_AND_ASSIGN(SyntheticMouseDriver);
};
diff --git a/chromium/content/browser/renderer_host/input/synthetic_pen_driver.cc b/chromium/content/browser/renderer_host/input/synthetic_pen_driver.cc
index 0d6f85a6e9b..697ee995f5e 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_pen_driver.cc
+++ b/chromium/content/browser/renderer_host/input/synthetic_pen_driver.cc
@@ -12,4 +12,12 @@ SyntheticPenDriver::SyntheticPenDriver() : SyntheticMouseDriver() {
SyntheticPenDriver::~SyntheticPenDriver() {}
-} // namespace content
+void SyntheticPenDriver::Leave(int index) {
+ DCHECK_EQ(index, 0);
+ mouse_event_ = SyntheticWebMouseEventBuilder::Build(
+ blink::WebInputEvent::kMouseLeave, mouse_event_.PositionInWidget().x,
+ mouse_event_.PositionInWidget().y, last_modifiers_,
+ mouse_event_.pointer_type);
+}
+
+} // namespace content \ No newline at end of file
diff --git a/chromium/content/browser/renderer_host/input/synthetic_pen_driver.h b/chromium/content/browser/renderer_host/input/synthetic_pen_driver.h
index d6ece9f0532..428aaba96d6 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_pen_driver.h
+++ b/chromium/content/browser/renderer_host/input/synthetic_pen_driver.h
@@ -16,6 +16,8 @@ class CONTENT_EXPORT SyntheticPenDriver : public SyntheticMouseDriver {
SyntheticPenDriver();
~SyntheticPenDriver() override;
+ void Leave(int index = 0) override;
+
private:
DISALLOW_COPY_AND_ASSIGN(SyntheticPenDriver);
};
diff --git a/chromium/content/browser/renderer_host/input/synthetic_pointer_action.cc b/chromium/content/browser/renderer_host/input/synthetic_pointer_action.cc
index bc0526b5fee..65dccb01a30 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_pointer_action.cc
+++ b/chromium/content/browser/renderer_host/input/synthetic_pointer_action.cc
@@ -74,6 +74,9 @@ SyntheticPointerAction::ForwardTouchOrMouseInputEvents(
case SyntheticPointerActionParams::PointerActionType::RELEASE:
synthetic_pointer_driver_->Release(param.index(), param.button());
break;
+ case SyntheticPointerActionParams::PointerActionType::LEAVE:
+ synthetic_pointer_driver_->Leave(param.index());
+ break;
case SyntheticPointerActionParams::PointerActionType::IDLE:
break;
case SyntheticPointerActionParams::PointerActionType::NOT_INITIALIZED:
diff --git a/chromium/content/browser/renderer_host/input/synthetic_pointer_action_unittest.cc b/chromium/content/browser/renderer_host/input/synthetic_pointer_action_unittest.cc
index c4d45f9d825..8f480dd77dc 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_pointer_action_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/synthetic_pointer_action_unittest.cc
@@ -32,6 +32,7 @@ WebTouchPoint::State ToWebTouchPointState(
return WebTouchPoint::kStateReleased;
case SyntheticPointerActionParams::PointerActionType::IDLE:
return WebTouchPoint::kStateStationary;
+ case SyntheticPointerActionParams::PointerActionType::LEAVE:
case SyntheticPointerActionParams::PointerActionType::NOT_INITIALIZED:
NOTREACHED()
<< "Invalid SyntheticPointerActionParams::PointerActionType.";
@@ -50,6 +51,8 @@ WebInputEvent::Type ToWebMouseEventType(
return WebInputEvent::kMouseMove;
case SyntheticPointerActionParams::PointerActionType::RELEASE:
return WebInputEvent::kMouseUp;
+ case SyntheticPointerActionParams::PointerActionType::LEAVE:
+ return WebInputEvent::kMouseLeave;
case SyntheticPointerActionParams::PointerActionType::IDLE:
case SyntheticPointerActionParams::PointerActionType::NOT_INITIALIZED:
NOTREACHED()
@@ -115,7 +118,8 @@ class MockSyntheticPointerActionTarget : public SyntheticGestureTarget {
class MockSyntheticPointerTouchActionTarget
: public MockSyntheticPointerActionTarget {
public:
- MockSyntheticPointerTouchActionTarget() {}
+ MockSyntheticPointerTouchActionTarget()
+ : num_dispatched_pointer_actions_(0) {}
~MockSyntheticPointerTouchActionTarget() override {}
void DispatchInputEventToPlatform(const WebInputEvent& event) override {
@@ -125,16 +129,18 @@ class MockSyntheticPointerTouchActionTarget
for (size_t i = 0; i < WebTouchEvent::kTouchesLengthCap; ++i) {
if (WebTouchPointStateToEventType(touch_event.touches[i].state) != type_)
continue;
-
- indexes_[i] = touch_event.touches[i].id;
- positions_[i] = gfx::PointF(touch_event.touches[i].PositionInWidget());
- states_[i] = touch_event.touches[i].state;
+ indexes_[num_dispatched_pointer_actions_] = i;
+ positions_[num_dispatched_pointer_actions_] =
+ gfx::PointF(touch_event.touches[i].PositionInWidget());
+ states_[num_dispatched_pointer_actions_] = touch_event.touches[i].state;
+ num_dispatched_pointer_actions_++;
}
}
testing::AssertionResult SyntheticTouchActionDispatchedCorrectly(
const SyntheticPointerActionParams& param,
- int index) {
+ int index,
+ int touch_index) {
if (param.pointer_action_type() ==
SyntheticPointerActionParams::PointerActionType::PRESS ||
param.pointer_action_type() ==
@@ -163,13 +169,16 @@ class MockSyntheticPointerTouchActionTarget
}
testing::AssertionResult SyntheticTouchActionListDispatchedCorrectly(
- const std::vector<SyntheticPointerActionParams>& params_list) {
+ const std::vector<SyntheticPointerActionParams>& params_list,
+ int index_array[]) {
testing::AssertionResult result = testing::AssertionSuccess();
+ num_dispatched_pointer_actions_ = 0;
+ int result_index = 0;
for (size_t i = 0; i < params_list.size(); ++i) {
if (params_list[i].pointer_action_type() !=
SyntheticPointerActionParams::PointerActionType::IDLE)
result = SyntheticTouchActionDispatchedCorrectly(
- params_list[i], params_list[i].index());
+ params_list[i], result_index++, index_array[i]);
if (result == testing::AssertionFailure())
return result;
}
@@ -182,6 +191,7 @@ class MockSyntheticPointerTouchActionTarget
}
private:
+ int num_dispatched_pointer_actions_;
gfx::PointF positions_[WebTouchEvent::kTouchesLengthCap];
int indexes_[WebTouchEvent::kTouchesLengthCap];
WebTouchPoint::State states_[WebTouchEvent::kTouchesLengthCap];
@@ -381,11 +391,12 @@ TEST_F(SyntheticPointerActionTest, PointerTouchAction) {
ForwardSyntheticPointerAction();
MockSyntheticPointerTouchActionTarget* pointer_touch_target =
static_cast<MockSyntheticPointerTouchActionTarget*>(target_.get());
+ int index_array[2] = {0, 1};
EXPECT_EQ(1, num_success_);
EXPECT_EQ(0, num_failure_);
EXPECT_EQ(pointer_touch_target->type(), WebInputEvent::kTouchStart);
EXPECT_TRUE(pointer_touch_target->SyntheticTouchActionListDispatchedCorrectly(
- param_list1));
+ param_list1, index_array));
ForwardSyntheticPointerAction();
EXPECT_EQ(2, num_success_);
@@ -393,21 +404,22 @@ TEST_F(SyntheticPointerActionTest, PointerTouchAction) {
// The type of the SyntheticWebTouchEvent is the action of the last finger.
EXPECT_EQ(pointer_touch_target->type(), WebInputEvent::kTouchStart);
EXPECT_TRUE(pointer_touch_target->SyntheticTouchActionListDispatchedCorrectly(
- param_list2));
+ param_list2, index_array));
ForwardSyntheticPointerAction();
EXPECT_EQ(3, num_success_);
EXPECT_EQ(0, num_failure_);
EXPECT_EQ(pointer_touch_target->type(), WebInputEvent::kTouchMove);
EXPECT_TRUE(pointer_touch_target->SyntheticTouchActionListDispatchedCorrectly(
- param_list3));
+ param_list3, index_array));
ForwardSyntheticPointerAction();
+ index_array[1] = 0;
EXPECT_EQ(4, num_success_);
EXPECT_EQ(0, num_failure_);
EXPECT_EQ(pointer_touch_target->type(), WebInputEvent::kTouchEnd);
EXPECT_TRUE(pointer_touch_target->SyntheticTouchActionListDispatchedCorrectly(
- param_list4));
+ param_list4, index_array));
}
TEST_F(SyntheticPointerActionTest, PointerTouchActionsMultiPressRelease) {
@@ -450,11 +462,12 @@ TEST_F(SyntheticPointerActionTest, PointerTouchActionsMultiPressRelease) {
ForwardSyntheticPointerAction();
MockSyntheticPointerTouchActionTarget* pointer_touch_target =
static_cast<MockSyntheticPointerTouchActionTarget*>(target_.get());
+ int index_array[2] = {0, 1};
EXPECT_EQ(count_success++, num_success_);
EXPECT_EQ(0, num_failure_);
EXPECT_EQ(pointer_touch_target->type(), WebInputEvent::kTouchStart);
EXPECT_TRUE(pointer_touch_target->SyntheticTouchActionListDispatchedCorrectly(
- param_list1));
+ param_list1, index_array));
for (int index = 1; index < 4; ++index) {
ForwardSyntheticPointerAction();
@@ -464,7 +477,7 @@ TEST_F(SyntheticPointerActionTest, PointerTouchActionsMultiPressRelease) {
EXPECT_EQ(pointer_touch_target->type(), WebInputEvent::kTouchStart);
EXPECT_TRUE(
pointer_touch_target->SyntheticTouchActionListDispatchedCorrectly(
- param_list2));
+ param_list2, index_array));
ForwardSyntheticPointerAction();
EXPECT_EQ(count_success++, num_success_);
@@ -473,7 +486,7 @@ TEST_F(SyntheticPointerActionTest, PointerTouchActionsMultiPressRelease) {
EXPECT_EQ(pointer_touch_target->type(), WebInputEvent::kTouchEnd);
EXPECT_TRUE(
pointer_touch_target->SyntheticTouchActionListDispatchedCorrectly(
- param_list3));
+ param_list3, index_array));
}
}
@@ -517,8 +530,8 @@ TEST_F(SyntheticPointerActionTest, PointerTouchActionTypeInvalid) {
EXPECT_EQ(1, num_success_);
EXPECT_EQ(2, num_failure_);
EXPECT_EQ(pointer_touch_target->type(), WebInputEvent::kTouchStart);
- EXPECT_TRUE(
- pointer_touch_target->SyntheticTouchActionDispatchedCorrectly(param, 0));
+ EXPECT_TRUE(pointer_touch_target->SyntheticTouchActionDispatchedCorrectly(
+ param, 0, 0));
// Cannot send a touch press again without releasing the finger.
ForwardSyntheticPointerAction();
@@ -702,6 +715,11 @@ TEST_F(SyntheticPointerActionTest, PointerPenAction) {
SyntheticPointerActionParams param3 = SyntheticPointerActionParams(
SyntheticPointerActionParams::PointerActionType::RELEASE);
params_.PushPointerActionParams(param3);
+
+ // Send a pen leave.
+ SyntheticPointerActionParams param4 = SyntheticPointerActionParams(
+ SyntheticPointerActionParams::PointerActionType::LEAVE);
+ params_.PushPointerActionParams(param4);
pointer_action_.reset(new SyntheticPointerAction(params_));
ForwardSyntheticPointerAction();
@@ -725,6 +743,13 @@ TEST_F(SyntheticPointerActionTest, PointerPenAction) {
EXPECT_EQ(0, num_failure_);
EXPECT_TRUE(pointer_pen_target->SyntheticMouseActionDispatchedCorrectly(
param3, 1, buttons, SyntheticGestureParams::PEN_INPUT));
+
+ ForwardSyntheticPointerAction();
+ EXPECT_EQ(4, num_success_);
+ EXPECT_EQ(0, num_failure_);
+ buttons.pop_back();
+ EXPECT_TRUE(pointer_pen_target->SyntheticMouseActionDispatchedCorrectly(
+ param4, 0, buttons, SyntheticGestureParams::PEN_INPUT));
}
TEST_F(SyntheticPointerActionTest, EmptyParams) {
diff --git a/chromium/content/browser/renderer_host/input/synthetic_pointer_driver.h b/chromium/content/browser/renderer_host/input/synthetic_pointer_driver.h
index 8ca1163b4e9..4325654257e 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_pointer_driver.h
+++ b/chromium/content/browser/renderer_host/input/synthetic_pointer_driver.h
@@ -37,6 +37,7 @@ class CONTENT_EXPORT SyntheticPointerDriver {
virtual void Release(int index = 0,
SyntheticPointerActionParams::Button button =
SyntheticPointerActionParams::Button::LEFT) = 0;
+ virtual void Leave(int index = 0) = 0;
// Check if the user inputs in the SyntheticPointerActionParams can generate
// a valid sequence of pointer actions.
diff --git a/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc b/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc
index ea2c5eca311..11325e371a7 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc
+++ b/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc
@@ -29,8 +29,12 @@ const int kDefaultSpeedInPixelsPerSec = 800;
SyntheticSmoothMoveGestureParams::SyntheticSmoothMoveGestureParams()
: speed_in_pixels_s(kDefaultSpeedInPixelsPerSec),
+ fling_velocity_x(0),
+ fling_velocity_y(0),
prevent_fling(true),
- add_slop(true) {}
+ add_slop(true),
+ precise_scrolling_deltas(false),
+ scroll_by_page(false) {}
SyntheticSmoothMoveGestureParams::SyntheticSmoothMoveGestureParams(
const SyntheticSmoothMoveGestureParams& other) = default;
@@ -185,10 +189,18 @@ void SyntheticSmoothMoveGesture::ForwardMouseWheelInputEvents(
ComputeNextMoveSegment();
} else {
state_ = DONE;
- // Forward a wheel event with phase ended and zero deltas.
- ForwardMouseWheelEvent(target, gfx::Vector2d(),
- blink::WebMouseWheelEvent::kPhaseEnded,
- event_timestamp);
+
+ // Start flinging on the swipe action.
+ if (!params_.prevent_fling && (params_.fling_velocity_x != 0 ||
+ params_.fling_velocity_y != 0)) {
+ ForwardFlingGestureEvent(
+ target, blink::WebGestureEvent::kGestureFlingStart);
+ } else {
+ // Forward a wheel event with phase ended and zero deltas.
+ ForwardMouseWheelEvent(target, gfx::Vector2d(),
+ blink::WebMouseWheelEvent::kPhaseEnded,
+ event_timestamp);
+ }
needs_scroll_begin_ = true;
}
}
@@ -258,8 +270,9 @@ void SyntheticSmoothMoveGesture::ForwardMouseWheelEvent(
const blink::WebMouseWheelEvent::Phase phase,
const base::TimeTicks& timestamp) const {
blink::WebMouseWheelEvent mouse_wheel_event =
- SyntheticWebMouseWheelEventBuilder::Build(0, 0, delta.x(), delta.y(), 0,
- false);
+ SyntheticWebMouseWheelEventBuilder::Build(
+ 0, 0, delta.x(), delta.y(), 0, params_.precise_scrolling_deltas,
+ params_.scroll_by_page);
mouse_wheel_event.SetPositionInWidget(
current_move_segment_start_position_.x(),
@@ -271,6 +284,18 @@ void SyntheticSmoothMoveGesture::ForwardMouseWheelEvent(
target->DispatchInputEventToPlatform(mouse_wheel_event);
}
+void SyntheticSmoothMoveGesture::ForwardFlingGestureEvent(
+ SyntheticGestureTarget* target,
+ const blink::WebInputEvent::Type type) const {
+ blink::WebGestureEvent fling_gesture_event =
+ SyntheticWebGestureEventBuilder::Build(type,
+ blink::kWebGestureDeviceTouchpad);
+ fling_gesture_event.data.fling_start.velocity_x = params_.fling_velocity_x;
+ fling_gesture_event.data.fling_start.velocity_y = params_.fling_velocity_y;
+ fling_gesture_event.SetPositionInWidget(current_move_segment_start_position_);
+ target->DispatchInputEventToPlatform(fling_gesture_event);
+}
+
void SyntheticSmoothMoveGesture::PressPoint(SyntheticGestureTarget* target,
const base::TimeTicks& timestamp) {
DCHECK_EQ(current_move_segment_, 0);
diff --git a/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.h b/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.h
index 353336c1f5c..353b10d30a7 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.h
+++ b/chromium/content/browser/renderer_host/input/synthetic_smooth_move_gesture.h
@@ -34,8 +34,12 @@ class CONTENT_EXPORT SyntheticSmoothMoveGestureParams {
gfx::PointF start_point;
std::vector<gfx::Vector2dF> distances;
int speed_in_pixels_s;
+ int fling_velocity_x;
+ int fling_velocity_y;
bool prevent_fling;
bool add_slop;
+ bool precise_scrolling_deltas;
+ bool scroll_by_page;
};
// This class is used as helper class for simulation of scroll and drag.
@@ -77,6 +81,9 @@ class CONTENT_EXPORT SyntheticSmoothMoveGesture : public SyntheticGesture {
const blink::WebMouseWheelEvent::Phase phase,
const base::TimeTicks& timestamp) const;
+ void ForwardFlingGestureEvent(SyntheticGestureTarget* target,
+ const blink::WebInputEvent::Type type) const;
+
void PressPoint(SyntheticGestureTarget* target,
const base::TimeTicks& timestamp);
void MovePoint(SyntheticGestureTarget* target,
diff --git a/chromium/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.cc b/chromium/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.cc
index de5265912ca..977fe39a806 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.cc
+++ b/chromium/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.cc
@@ -45,9 +45,13 @@ bool SyntheticSmoothScrollGesture::InitializeMoveGesture(
move_params.start_point = params_.anchor;
move_params.distances = params_.distances;
move_params.speed_in_pixels_s = params_.speed_in_pixels_s;
+ move_params.fling_velocity_x = params_.fling_velocity_x;
+ move_params.fling_velocity_y = params_.fling_velocity_y;
move_params.prevent_fling = params_.prevent_fling;
move_params.input_type = GetInputSourceType(gesture_type);
move_params.add_slop = true;
+ move_params.precise_scrolling_deltas = params_.precise_scrolling_deltas;
+ move_params.scroll_by_page = params_.scroll_by_page;
move_gesture_.reset(new SyntheticSmoothMoveGesture(move_params));
return true;
}
diff --git a/chromium/content/browser/renderer_host/input/synthetic_touch_driver.cc b/chromium/content/browser/renderer_host/input/synthetic_touch_driver.cc
index a8e14a2aff0..c16c6e00c9c 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_touch_driver.cc
+++ b/chromium/content/browser/renderer_host/input/synthetic_touch_driver.cc
@@ -25,6 +25,7 @@ void SyntheticTouchDriver::DispatchEvent(SyntheticGestureTarget* target,
if (touch_event_.GetType() != blink::WebInputEvent::kUndefined)
target->DispatchInputEventToPlatform(touch_event_);
touch_event_.ResetPoints();
+ ResetIndexMap();
}
void SyntheticTouchDriver::Press(float x,
@@ -52,6 +53,10 @@ void SyntheticTouchDriver::Release(
index_map_[index] = -1;
}
+void SyntheticTouchDriver::Leave(int index) {
+ NOTIMPLEMENTED();
+}
+
bool SyntheticTouchDriver::UserInputCheck(
const SyntheticPointerActionParams& params) const {
if (params.index() < 0 ||
@@ -84,4 +89,26 @@ bool SyntheticTouchDriver::UserInputCheck(
return true;
}
+void SyntheticTouchDriver::ResetIndexMap() {
+ unsigned free_index = 0;
+ for (unsigned int i = 0; i < blink::WebTouchEvent::kTouchesLengthCap; ++i) {
+ if (free_index >= touch_event_.touches_length)
+ break;
+ if (touch_event_.touches[i].state !=
+ blink::WebTouchPoint::kStateUndefined) {
+ touch_event_.touches[free_index] = touch_event_.touches[i];
+ int index = GetIndexFromMap(i);
+ index_map_[index] = free_index;
+ free_index++;
+ }
+ }
+}
+
+int SyntheticTouchDriver::GetIndexFromMap(int value) const {
+ int index = std::find(index_map_.begin(), index_map_.end(), value) -
+ index_map_.begin();
+ DCHECK(index >= 0 && index < blink::WebTouchEvent::kTouchesLengthCap);
+ return index;
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/synthetic_touch_driver.h b/chromium/content/browser/renderer_host/input/synthetic_touch_driver.h
index 95470f378bf..3f8102a212d 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_touch_driver.h
+++ b/chromium/content/browser/renderer_host/input/synthetic_touch_driver.h
@@ -31,6 +31,7 @@ class CONTENT_EXPORT SyntheticTouchDriver : public SyntheticPointerDriver {
void Release(int index,
SyntheticPointerActionParams::Button button =
SyntheticPointerActionParams::Button::LEFT) override;
+ void Leave(int index) override;
bool UserInputCheck(
const SyntheticPointerActionParams& params) const override;
@@ -38,6 +39,9 @@ class CONTENT_EXPORT SyntheticTouchDriver : public SyntheticPointerDriver {
private:
using IndexMap = std::array<int, blink::WebTouchEvent::kTouchesLengthCap>;
+ void ResetIndexMap();
+ int GetIndexFromMap(int value) const;
+
SyntheticWebTouchEvent touch_event_;
IndexMap index_map_;
diff --git a/chromium/content/browser/renderer_host/input/touch_action_filter.cc b/chromium/content/browser/renderer_host/input/touch_action_filter.cc
index 16e30e8e392..8a35a81229d 100644
--- a/chromium/content/browser/renderer_host/input/touch_action_filter.cc
+++ b/chromium/content/browser/renderer_host/input/touch_action_filter.cc
@@ -6,6 +6,7 @@
#include <math.h>
+#include "base/debug/crash_logging.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "third_party/blink/public/platform/web_gesture_event.h"
@@ -38,7 +39,11 @@ TouchActionFilter::TouchActionFilter()
: suppress_manipulation_events_(false),
drop_current_tap_ending_event_(false),
allow_current_double_tap_event_(true),
- force_enable_zoom_(false) {}
+ force_enable_zoom_(false) {
+ ResetTouchAction();
+}
+
+TouchActionFilter::~TouchActionFilter() {}
FilterGestureEventResult TouchActionFilter::FilterGestureEvent(
WebGestureEvent* gesture_event) {
@@ -50,11 +55,22 @@ FilterGestureEventResult TouchActionFilter::FilterGestureEvent(
switch (gesture_event->GetType()) {
case WebInputEvent::kGestureScrollBegin: {
DCHECK(!suppress_manipulation_events_);
- DCHECK(!touchscreen_scroll_in_progress_);
- touchscreen_scroll_in_progress_ = true;
- // TODO(https://crbug.com/851644): Make sure the value is properly set.
- if (!scrolling_touch_action_.has_value())
+ // In VR or virtual keyboard (https://crbug.com/880701),
+ // GestureScrollBegin could come without GestureTapDown.
+ if (!gesture_sequence_in_progress_) {
+ gesture_sequence_in_progress_ = true;
+ if (!scrolling_touch_action_.has_value())
+ SetTouchAction(cc::kTouchActionAuto);
+ }
+ gesture_sequence_.append("B");
+ if (!scrolling_touch_action_.has_value()) {
+ static auto* crash_key = base::debug::AllocateCrashKeyString(
+ "scrollbegin-gestures", base::debug::CrashKeySize::Size256);
+ base::debug::SetCrashKeyString(crash_key, gesture_sequence_);
+ gesture_sequence_.clear();
+ // https://crbug.com/869375, temporary fix to prevent crash.
SetTouchAction(cc::kTouchActionAuto);
+ }
suppress_manipulation_events_ =
ShouldSuppressManipulation(*gesture_event);
return suppress_manipulation_events_
@@ -66,6 +82,7 @@ FilterGestureEventResult TouchActionFilter::FilterGestureEvent(
if (suppress_manipulation_events_)
return FilterGestureEventResult::kFilterGestureEventFiltered;
+ gesture_sequence_.append("U");
// Scrolls restricted to a specific axis shouldn't permit movement
// in the perpendicular axis.
//
@@ -74,6 +91,14 @@ FilterGestureEventResult TouchActionFilter::FilterGestureEvent(
// two-finger scrolling but a "touch-action: pan-x pinch-zoom" region
// doesn't.
// TODO(mustaq): Add it to spec?
+ if (!scrolling_touch_action_.has_value()) {
+ static auto* crash_key = base::debug::AllocateCrashKeyString(
+ "scrollupdate-gestures", base::debug::CrashKeySize::Size256);
+ base::debug::SetCrashKeyString(crash_key, gesture_sequence_);
+ gesture_sequence_.clear();
+ // https://crbug.com/869375, temporary fix to prevent crash.
+ SetTouchAction(cc::kTouchActionAuto);
+ }
if (IsYAxisActionDisallowed(scrolling_touch_action_.value())) {
gesture_event->data.scroll_update.delta_y = 0;
gesture_event->data.scroll_update.velocity_y = 0;
@@ -91,8 +116,8 @@ FilterGestureEventResult TouchActionFilter::FilterGestureEvent(
break;
case WebInputEvent::kGestureScrollEnd:
- DCHECK(touchscreen_scroll_in_progress_);
- touchscreen_scroll_in_progress_ = false;
+ gesture_sequence_.clear();
+ gesture_sequence_in_progress_ = false;
ReportGestureEventFiltered(suppress_manipulation_events_);
return FilterManipulationEventAndResetState()
? FilterGestureEventResult::kFilterGestureEventFiltered
@@ -101,6 +126,7 @@ FilterGestureEventResult TouchActionFilter::FilterGestureEvent(
case WebInputEvent::kGesturePinchBegin:
case WebInputEvent::kGesturePinchUpdate:
case WebInputEvent::kGesturePinchEnd:
+ gesture_sequence_.append("P");
ReportGestureEventFiltered(suppress_manipulation_events_);
return suppress_manipulation_events_
? FilterGestureEventResult::kFilterGestureEventFiltered
@@ -109,6 +135,8 @@ FilterGestureEventResult TouchActionFilter::FilterGestureEvent(
// The double tap gesture is a tap ending event. If a double tap gesture is
// filtered out, replace it with a tap event.
case WebInputEvent::kGestureDoubleTap:
+ gesture_sequence_in_progress_ = false;
+ gesture_sequence_.append("D");
DCHECK_EQ(1, gesture_event->data.tap.tap_count);
if (!allow_current_double_tap_event_)
gesture_event->SetType(WebInputEvent::kGestureTap);
@@ -117,10 +145,16 @@ FilterGestureEventResult TouchActionFilter::FilterGestureEvent(
// If double tap is disabled, there's no reason for the tap delay.
case WebInputEvent::kGestureTapUnconfirmed: {
+ gesture_sequence_.append("C");
DCHECK_EQ(1, gesture_event->data.tap.tap_count);
- // TODO(https://crbug.com/851644): Make sure the value is properly set.
- if (!scrolling_touch_action_.has_value())
+ if (!scrolling_touch_action_.has_value()) {
+ static auto* crash_key = base::debug::AllocateCrashKeyString(
+ "tapunconfirmed-gestures", base::debug::CrashKeySize::Size256);
+ base::debug::SetCrashKeyString(crash_key, gesture_sequence_);
+ gesture_sequence_.clear();
+ // https://crbug.com/869375, temporary fix to prevent crash.
SetTouchAction(cc::kTouchActionAuto);
+ }
allow_current_double_tap_event_ = (scrolling_touch_action_.value() &
cc::kTouchActionDoubleTapZoom) != 0;
if (!allow_current_double_tap_event_) {
@@ -131,7 +165,16 @@ FilterGestureEventResult TouchActionFilter::FilterGestureEvent(
}
case WebInputEvent::kGestureTap:
+ gesture_sequence_in_progress_ = false;
+ gesture_sequence_.append("A");
+ if (drop_current_tap_ending_event_) {
+ drop_current_tap_ending_event_ = false;
+ return FilterGestureEventResult::kFilterGestureEventFiltered;
+ }
+ break;
+
case WebInputEvent::kGestureTapCancel:
+ gesture_sequence_.append("K");
if (drop_current_tap_ending_event_) {
drop_current_tap_ending_event_ = false;
return FilterGestureEventResult::kFilterGestureEventFiltered;
@@ -139,19 +182,24 @@ FilterGestureEventResult TouchActionFilter::FilterGestureEvent(
break;
case WebInputEvent::kGestureTapDown:
+ gesture_sequence_in_progress_ = true;
// If the gesture is hitting a region that has a non-blocking (such as a
// passive) event listener.
if (gesture_event->is_source_touch_event_set_non_blocking)
SetTouchAction(cc::kTouchActionAuto);
scrolling_touch_action_ = allowed_touch_action_;
- // TODO(https://crbug.com/851644): The value may not set in the case when
- // the gesture event is flushed due to touch ack time out after the finger
- // is lifted up. Make sure the value is properly set.
- if (!scrolling_touch_action_.has_value())
- SetTouchAction(cc::kTouchActionAuto);
+ if (scrolling_touch_action_.has_value())
+ gesture_sequence_.append("O1");
+ else
+ gesture_sequence_.append("O2");
DCHECK(!drop_current_tap_ending_event_);
break;
+ case WebInputEvent::kGestureLongTap:
+ case WebInputEvent::kGestureTwoFingerTap:
+ gesture_sequence_in_progress_ = false;
+ break;
+
default:
// Gesture events unrelated to touch actions (panning/zooming) are left
// alone.
@@ -200,13 +248,22 @@ void TouchActionFilter::OnSetTouchAction(cc::TouchAction touch_action) {
scrolling_touch_action_ = allowed_touch_action_;
}
+void TouchActionFilter::SetActiveTouchInProgress(
+ bool active_touch_in_progress) {
+ active_touch_in_progress_ = active_touch_in_progress;
+}
+
void TouchActionFilter::ReportAndResetTouchAction() {
+ if (has_touch_event_handler_)
+ gesture_sequence_.append("R1");
+ else
+ gesture_sequence_.append("R0");
ReportTouchAction();
ResetTouchAction();
}
void TouchActionFilter::ReportTouchAction() {
- // TODO(https://crbug.com/851644): make sure the value is properly set.
+ // https://crbug.com/869375, temporary fix to prevent crash.
if (!scrolling_touch_action_.has_value())
SetTouchAction(cc::kTouchActionAuto);
// Report the effective touch action computed by blink such as
@@ -214,6 +271,10 @@ void TouchActionFilter::ReportTouchAction() {
// Since |cc::kTouchActionAuto| is equivalent to |cc::kTouchActionMax|, we
// must add one to the upper bound to be able to visualize the number of
// times |cc::kTouchActionAuto| is hit.
+ // https://crbug.com/879511, remove this temporary fix.
+ if (!scrolling_touch_action_.has_value())
+ return;
+
UMA_HISTOGRAM_ENUMERATION("TouchAction.EffectiveTouchAction",
scrolling_touch_action_.value(),
cc::kTouchActionMax + 1);
@@ -228,6 +289,10 @@ void TouchActionFilter::ReportTouchAction() {
}
}
+void TouchActionFilter::AppendToGestureSequenceForDebugging(const char* str) {
+ gesture_sequence_.append(str);
+}
+
void TouchActionFilter::ResetTouchAction() {
// Note that resetting the action mid-sequence is tolerated. Gestures that had
// their begin event(s) suppressed will be suppressed until the next
@@ -303,13 +368,18 @@ void TouchActionFilter::OnHasTouchEventHandlers(bool has_handlers) {
if (has_handlers && has_touch_event_handler_ == has_handlers)
return;
has_touch_event_handler_ = has_handlers;
- ResetTouchAction();
- // If a page has a touch event handler, this function can be called twice with
- // has_handlers = false first and then true later. When it is true, we need to
- // reset the |scrolling_touch_action_|. However, we do not want to reset it if
- // there is an active scroll in progress.
- if (has_touch_event_handler_ && !touchscreen_scroll_in_progress_)
- scrolling_touch_action_.reset();
+ if (has_touch_event_handler_)
+ gesture_sequence_.append("L1");
+ else
+ gesture_sequence_.append("L0");
+ // We have set the associated touch action if the touch start already happened
+ // or there is a gesture in progress. In these cases, we should not reset the
+ // associated touch action.
+ if (!gesture_sequence_in_progress_ && !active_touch_in_progress_) {
+ ResetTouchAction();
+ if (has_touch_event_handler_)
+ scrolling_touch_action_.reset();
+ }
}
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/touch_action_filter.h b/chromium/content/browser/renderer_host/input/touch_action_filter.h
index d1167ae83d6..2d157fbebe9 100644
--- a/chromium/content/browser/renderer_host/input/touch_action_filter.h
+++ b/chromium/content/browser/renderer_host/input/touch_action_filter.h
@@ -9,6 +9,7 @@
#include "base/optional.h"
#include "cc/input/touch_action.h"
#include "content/common/content_export.h"
+#include "third_party/blink/public/platform/web_input_event.h"
namespace blink {
class WebGestureEvent;
@@ -30,6 +31,7 @@ enum class FilterGestureEventResult {
class CONTENT_EXPORT TouchActionFilter {
public:
TouchActionFilter();
+ ~TouchActionFilter();
// Returns kFilterGestureEventFiltered if the supplied gesture event should be
// dropped based on the current touch-action state. Otherwise returns
@@ -65,6 +67,11 @@ class CONTENT_EXPORT TouchActionFilter {
void OnHasTouchEventHandlers(bool has_handlers);
+ void SetActiveTouchInProgress(bool active_touch_in_progress);
+
+ // Debugging only.
+ void AppendToGestureSequenceForDebugging(const char* str);
+
private:
friend class MockRenderWidgetHost;
friend class TouchActionFilterTest;
@@ -91,13 +98,17 @@ class CONTENT_EXPORT TouchActionFilter {
bool force_enable_zoom_;
// Indicates whether this page has touch event handler or not. Set by
- // InputRouterImpl::OnHasTouchEventHandler.
- // TODO(https://crbug.com/850238): default to true or make it Optional.
+ // InputRouterImpl::OnHasTouchEventHandlers. Default to false because one
+ // could not scroll anyways when there is no content, and this is consistent
+ // with the default state committed after DocumentLoader::DidCommitNavigation.
bool has_touch_event_handler_ = false;
- // True if an active touch scroll gesture is in progress. i.e. after GSB and
+ // True if an active gesture sequence is in progress. i.e. after GTD and
// before GSE.
- bool touchscreen_scroll_in_progress_ = false;
+ bool gesture_sequence_in_progress_ = false;
+
+ // True at touch start and false at touch end.
+ bool active_touch_in_progress_ = false;
// What touch actions are currently permitted.
base::Optional<cc::TouchAction> allowed_touch_action_;
@@ -111,6 +122,9 @@ class CONTENT_EXPORT TouchActionFilter {
// Whitelisted touch action received from the compositor.
base::Optional<cc::TouchAction> white_listed_touch_action_;
+ // Debugging only.
+ std::string gesture_sequence_;
+
DISALLOW_COPY_AND_ASSIGN(TouchActionFilter);
};
diff --git a/chromium/content/browser/renderer_host/input/touch_action_filter_unittest.cc b/chromium/content/browser/renderer_host/input/touch_action_filter_unittest.cc
index 9a5d4a8c41c..95d48e39153 100644
--- a/chromium/content/browser/renderer_host/input/touch_action_filter_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/touch_action_filter_unittest.cc
@@ -22,7 +22,7 @@ const blink::WebGestureDevice kSourceDevice =
class TouchActionFilterTest : public testing::Test {
public:
- TouchActionFilterTest(){};
+ TouchActionFilterTest() { filter_.OnHasTouchEventHandlers(true); }
~TouchActionFilterTest() override {}
protected:
@@ -36,6 +36,8 @@ class TouchActionFilterTest : public testing::Test {
float dy,
float expected_dx,
float expected_dy) {
+ WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::kGestureTapDown, kSourceDevice);
WebGestureEvent scroll_end = SyntheticWebGestureEventBuilder::Build(
WebInputEvent::kGestureScrollEnd, kSourceDevice);
@@ -47,6 +49,8 @@ class TouchActionFilterTest : public testing::Test {
WebGestureEvent scroll_begin =
SyntheticWebGestureEventBuilder::BuildScrollBegin(0, 0,
kSourceDevice);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventAllowed);
@@ -69,6 +73,8 @@ class TouchActionFilterTest : public testing::Test {
WebGestureEvent scroll_begin =
SyntheticWebGestureEventBuilder::BuildScrollBegin(scroll_x, scroll_y,
kSourceDevice);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventAllowed);
@@ -104,6 +110,8 @@ class TouchActionFilterTest : public testing::Test {
WebGestureEvent scroll_begin =
SyntheticWebGestureEventBuilder::BuildScrollBegin(scroll_y, scroll_x,
kSourceDevice);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventFiltered);
@@ -123,6 +131,8 @@ class TouchActionFilterTest : public testing::Test {
void PanTestForUnidirectionalTouchAction(cc::TouchAction action,
float scroll_x,
float scroll_y) {
+ WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::kGestureTapDown, kSourceDevice);
WebGestureEvent scroll_end = SyntheticWebGestureEventBuilder::Build(
WebInputEvent::kGestureScrollEnd, kSourceDevice);
@@ -133,6 +143,8 @@ class TouchActionFilterTest : public testing::Test {
WebGestureEvent scroll_begin =
SyntheticWebGestureEventBuilder::BuildScrollBegin(scroll_x, scroll_y,
kSourceDevice);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventAllowed);
@@ -153,6 +165,8 @@ class TouchActionFilterTest : public testing::Test {
WebGestureEvent scroll_begin =
SyntheticWebGestureEventBuilder::BuildScrollBegin(
-scroll_x, -scroll_y, kSourceDevice);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventFiltered);
@@ -173,6 +187,8 @@ class TouchActionFilterTest : public testing::Test {
WebGestureEvent scroll_begin =
SyntheticWebGestureEventBuilder::BuildScrollBegin(
-scroll_x - scroll_y, -scroll_x - scroll_y, kSourceDevice);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventFiltered);
@@ -200,12 +216,12 @@ TEST_F(TouchActionFilterTest, SimpleFilter) {
kSourceDevice);
WebGestureEvent scroll_end = SyntheticWebGestureEventBuilder::Build(
WebInputEvent::kGestureScrollEnd, kSourceDevice);
- WebGestureEvent tap = SyntheticWebGestureEventBuilder::Build(
- WebInputEvent::kGestureTap, kSourceDevice);
// cc::kTouchActionAuto doesn't cause any filtering.
filter_.ResetTouchAction();
filter_.OnSetTouchAction(cc::kTouchActionAuto);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_update),
@@ -220,8 +236,6 @@ TEST_F(TouchActionFilterTest, SimpleFilter) {
filter_.OnSetTouchAction(cc::kTouchActionNone);
EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
FilterGestureEventResult::kFilterGestureEventAllowed);
- EXPECT_EQ(filter_.FilterGestureEvent(&tap),
- FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventFiltered);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_update),
@@ -236,6 +250,8 @@ TEST_F(TouchActionFilterTest, SimpleFilter) {
// When a new touch sequence begins, the state is reset.
filter_.ResetTouchAction();
filter_.OnSetTouchAction(cc::kTouchActionAuto);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_update),
@@ -246,6 +262,8 @@ TEST_F(TouchActionFilterTest, SimpleFilter) {
// Setting touch action doesn't impact any in-progress gestures.
filter_.ResetTouchAction();
filter_.OnSetTouchAction(cc::kTouchActionAuto);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventAllowed);
filter_.OnSetTouchAction(cc::kTouchActionNone);
@@ -257,6 +275,8 @@ TEST_F(TouchActionFilterTest, SimpleFilter) {
// And the state is still cleared for the next gesture.
filter_.ResetTouchAction();
filter_.OnSetTouchAction(cc::kTouchActionAuto);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
@@ -265,6 +285,8 @@ TEST_F(TouchActionFilterTest, SimpleFilter) {
// Changing the touch action during a gesture has no effect.
filter_.ResetTouchAction();
filter_.OnSetTouchAction(cc::kTouchActionNone);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventFiltered);
filter_.OnSetTouchAction(cc::kTouchActionAuto);
@@ -339,6 +361,8 @@ TEST_F(TouchActionFilterTest, PanY) {
TEST_F(TouchActionFilterTest, PanXY) {
const float kDX = 5;
const float kDY = 10;
+ WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::kGestureTapDown, kSourceDevice);
WebGestureEvent scroll_end = SyntheticWebGestureEventBuilder::Build(
WebInputEvent::kGestureScrollEnd, kSourceDevice);
@@ -348,6 +372,8 @@ TEST_F(TouchActionFilterTest, PanXY) {
filter_.OnSetTouchAction(cc::kTouchActionPan);
WebGestureEvent scroll_begin =
SyntheticWebGestureEventBuilder::BuildScrollBegin(-7, 6, kSourceDevice);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventAllowed);
@@ -369,6 +395,8 @@ TEST_F(TouchActionFilterTest, PanXY) {
filter_.OnSetTouchAction(cc::kTouchActionPan);
WebGestureEvent scroll_begin =
SyntheticWebGestureEventBuilder::BuildScrollBegin(-6, 7, kSourceDevice);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventAllowed);
@@ -391,6 +419,8 @@ TEST_F(TouchActionFilterTest, PanXY) {
WebGestureEvent scroll_begin =
SyntheticWebGestureEventBuilder::BuildScrollBegin(-6, 7, kSourceDevice,
2);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventFiltered);
@@ -420,6 +450,8 @@ TEST_F(TouchActionFilterTest, BitMath) {
}
TEST_F(TouchActionFilterTest, MultiTouch) {
+ WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::kGestureTapDown, kSourceDevice);
WebGestureEvent scroll_begin =
SyntheticWebGestureEventBuilder::BuildScrollBegin(2, 3, kSourceDevice);
const float kDeltaX = 5;
@@ -434,6 +466,8 @@ TEST_F(TouchActionFilterTest, MultiTouch) {
filter_.ResetTouchAction();
filter_.OnSetTouchAction(cc::kTouchActionNone);
filter_.OnSetTouchAction(cc::kTouchActionAuto);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventFiltered);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_update),
@@ -450,6 +484,8 @@ TEST_F(TouchActionFilterTest, MultiTouch) {
filter_.OnSetTouchAction(cc::kTouchActionPanX);
filter_.OnSetTouchAction(cc::kTouchActionPanY);
filter_.OnSetTouchAction(cc::kTouchActionPan);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventFiltered);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_update),
@@ -461,8 +497,11 @@ TEST_F(TouchActionFilterTest, MultiTouch) {
class TouchActionFilterPinchTest : public testing::Test {
public:
void RunTest(bool force_enable_zoom) {
+ filter_.OnHasTouchEventHandlers(true);
filter_.SetForceEnableZoom(force_enable_zoom);
+ WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::kGestureTapDown, kSourceDevice);
WebGestureEvent scroll_begin =
SyntheticWebGestureEventBuilder::BuildScrollBegin(2, 3, kSourceDevice,
2);
@@ -479,6 +518,8 @@ class TouchActionFilterPinchTest : public testing::Test {
// Pinch is allowed with touch-action: auto.
filter_.ResetTouchAction();
filter_.OnSetTouchAction(cc::kTouchActionAuto);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&pinch_begin),
@@ -493,6 +534,8 @@ class TouchActionFilterPinchTest : public testing::Test {
// Pinch is not allowed with touch-action: none.
filter_.ResetTouchAction();
filter_.OnSetTouchAction(cc::kTouchActionNone);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventFiltered);
EXPECT_EQ(filter_.FilterGestureEvent(&pinch_begin),
@@ -514,6 +557,8 @@ class TouchActionFilterPinchTest : public testing::Test {
// enable zoom.
filter_.ResetTouchAction();
filter_.OnSetTouchAction(cc::kTouchActionPan);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_NE(filter_.FilterGestureEvent(&scroll_begin),
force_enable_zoom
? FilterGestureEventResult::kFilterGestureEventFiltered
@@ -538,6 +583,8 @@ class TouchActionFilterPinchTest : public testing::Test {
// Pinch is allowed with touch-action: manipulation.
filter_.ResetTouchAction();
filter_.OnSetTouchAction(cc::kTouchActionManipulation);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&pinch_begin),
@@ -552,6 +599,8 @@ class TouchActionFilterPinchTest : public testing::Test {
// Pinch state is automatically reset at the end of a scroll.
filter_.ResetTouchAction();
filter_.OnSetTouchAction(cc::kTouchActionAuto);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&pinch_begin),
@@ -566,6 +615,8 @@ class TouchActionFilterPinchTest : public testing::Test {
// Pinching is only computed at GestureScrollBegin time.
filter_.ResetTouchAction();
filter_.OnSetTouchAction(cc::kTouchActionAuto);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&pinch_begin),
@@ -595,6 +646,8 @@ class TouchActionFilterPinchTest : public testing::Test {
// gestures since it is computed in GestureScrollBegin.
filter_.ResetTouchAction();
filter_.OnSetTouchAction(cc::kTouchActionAuto);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&pinch_begin),
@@ -616,6 +669,8 @@ class TouchActionFilterPinchTest : public testing::Test {
// Scrolling is allowed when two fingers are down.
filter_.ResetTouchAction();
filter_.OnSetTouchAction(cc::kTouchActionPinchZoom);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&pinch_begin),
@@ -632,6 +687,8 @@ class TouchActionFilterPinchTest : public testing::Test {
scroll_begin.data.scroll_begin.pointer_count = 1;
filter_.ResetTouchAction();
filter_.OnSetTouchAction(cc::kTouchActionPinchZoom);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventFiltered);
EXPECT_EQ(filter_.FilterGestureEvent(&pinch_begin),
@@ -772,6 +829,8 @@ TEST_F(TouchActionFilterTest, TouchActionResetsOnResetTouchAction) {
filter_.ResetTouchAction();
filter_.OnSetTouchAction(cc::kTouchActionNone);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventFiltered);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
@@ -786,11 +845,16 @@ TEST_F(TouchActionFilterTest, TouchActionResetsOnResetTouchAction) {
filter_.ResetTouchAction();
filter_.OnSetTouchAction(cc::kTouchActionAuto);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventAllowed);
}
TEST_F(TouchActionFilterTest, TouchActionResetMidSequence) {
+ filter_.OnHasTouchEventHandlers(true);
+ WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::kGestureTapDown, kSourceDevice);
WebGestureEvent scroll_begin =
SyntheticWebGestureEventBuilder::BuildScrollBegin(2, 3, kSourceDevice);
WebGestureEvent pinch_begin = SyntheticWebGestureEventBuilder::Build(
@@ -804,6 +868,8 @@ TEST_F(TouchActionFilterTest, TouchActionResetMidSequence) {
WebInputEvent::kGestureScrollEnd, kSourceDevice);
filter_.OnSetTouchAction(cc::kTouchActionNone);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventFiltered);
EXPECT_EQ(filter_.FilterGestureEvent(&pinch_begin),
@@ -871,25 +937,203 @@ TEST_F(TouchActionFilterTest, TouchActionNotResetWithinGestureSequence) {
filter_.ReportAndResetTouchAction();
EXPECT_FALSE(filter_.allowed_touch_action().has_value());
EXPECT_EQ(cc::kTouchActionPanY, ScrollingTouchAction().value());
+ // In fling or fling boosting case, we will see ScrollUpdate after the touch
+ // end.
+ EXPECT_EQ(filter_.FilterGestureEvent(&scroll_update),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
FilterGestureEventResult::kFilterGestureEventAllowed);
// The |allowed_touch_action_| should have been reset, but not the
// |scrolling_touch_action_|.
EXPECT_FALSE(filter_.allowed_touch_action().has_value());
EXPECT_EQ(cc::kTouchActionPanY, ScrollingTouchAction().value());
+}
+
+// The following 3 tests ensures that when the IPC message
+// OnHasTouchEventHandlers is received in the middle of a gesture sequence, the
+// touch action is not reset.
+TEST_F(TouchActionFilterTest, OnHasTouchEventHandlersReceivedDuringTap) {
+ filter_.OnHasTouchEventHandlers(false);
+
+ WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::kGestureTapDown, kSourceDevice);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
+ filter_.OnHasTouchEventHandlers(true);
+ EXPECT_TRUE(ScrollingTouchAction().has_value());
+
+ filter_.OnSetTouchAction(cc::kTouchActionPan);
+ // Simulate a simple tap gesture.
+ WebGestureEvent tap = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::kGestureTap, kSourceDevice);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
+ // Gesture tap indicates that there is no scroll in progress, so this should
+ // reset the |allowed_touch_action_|.
+ filter_.ResetTouchAction();
+ EXPECT_FALSE(filter_.allowed_touch_action().has_value());
+}
- // In the fling boosting case, we won't get a TapDown after the previous GSE.
+TEST_F(TouchActionFilterTest, OnHasTouchEventHandlersReceivedDuringDoubleTap) {
+ filter_.OnHasTouchEventHandlers(false);
+
+ WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::kGestureTapDown, kSourceDevice);
+ WebGestureEvent tap_cancel = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::kGestureTapCancel, kSourceDevice);
+ WebGestureEvent double_tap = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::kGestureDoubleTap, kSourceDevice);
+
+ // Simulate a double tap gesture: GTD-->GTC-->GTD-->GTC-->GDT.
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
+ EXPECT_EQ(ScrollingTouchAction().value(), cc::kTouchActionAuto);
+ filter_.OnHasTouchEventHandlers(true);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_cancel),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
+ EXPECT_TRUE(ScrollingTouchAction().has_value());
+ filter_.OnSetTouchAction(cc::kTouchActionPan);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
+ EXPECT_EQ(ScrollingTouchAction().value(), cc::kTouchActionPan);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_cancel),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
+ EXPECT_EQ(filter_.FilterGestureEvent(&double_tap),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
+}
+
+TEST_F(TouchActionFilterTest, OnHasTouchEventHandlersReceivedDuringScroll) {
+ filter_.OnHasTouchEventHandlers(false);
+
+ WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::kGestureTapDown, kSourceDevice);
+ WebGestureEvent tap_cancel = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::kGestureTapCancel, kSourceDevice);
+ WebGestureEvent scroll_begin =
+ SyntheticWebGestureEventBuilder::BuildScrollBegin(5, 0, kSourceDevice);
+ WebGestureEvent scroll_update =
+ SyntheticWebGestureEventBuilder::BuildScrollUpdate(5, 0, 0,
+ kSourceDevice);
+ WebGestureEvent scroll_end = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::kGestureScrollEnd, kSourceDevice);
+
+ // Simulate a gesture scroll: GTD-->GTC-->GSB-->GSU-->GSE.
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_cancel),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
+ filter_.OnHasTouchEventHandlers(true);
+ filter_.OnSetTouchAction(cc::kTouchActionPan);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
FilterGestureEventResult::kFilterGestureEventAllowed);
+ EXPECT_EQ(ScrollingTouchAction().value(), cc::kTouchActionPan);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_update),
FilterGestureEventResult::kFilterGestureEventAllowed);
EXPECT_EQ(filter_.FilterGestureEvent(&scroll_end),
FilterGestureEventResult::kFilterGestureEventAllowed);
+}
+
+// If OnHasTouchEventHandlers IPC is received after LongTap or TwoFingerTap,
+// the touch action should be reset.
+TEST_F(TouchActionFilterTest,
+ OnHasTouchEventHandlersReceivedAfterLongTapOrTwoFingerTap) {
+ filter_.OnHasTouchEventHandlers(false);
+ WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::kGestureTapDown, kSourceDevice);
+ WebGestureEvent tap_cancel = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::kGestureTapCancel, kSourceDevice);
+ WebGestureEvent long_tap = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::kGestureLongTap, kSourceDevice);
EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
FilterGestureEventResult::kFilterGestureEventAllowed);
- EXPECT_TRUE(filter_.allowed_touch_action().has_value());
- EXPECT_TRUE(ScrollingTouchAction().has_value());
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_cancel),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
+ EXPECT_EQ(filter_.FilterGestureEvent(&long_tap),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
+ EXPECT_EQ(ScrollingTouchAction().value(), cc::kTouchActionAuto);
+
+ filter_.OnHasTouchEventHandlers(true);
+ EXPECT_FALSE(ScrollingTouchAction().has_value());
+
+ filter_.OnHasTouchEventHandlers(false);
+ WebGestureEvent two_finger_tap = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::kGestureTwoFingerTap, kSourceDevice);
+
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_cancel),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
+ EXPECT_EQ(filter_.FilterGestureEvent(&two_finger_tap),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
+ EXPECT_EQ(ScrollingTouchAction().value(), cc::kTouchActionAuto);
+
+ filter_.OnHasTouchEventHandlers(true);
+ EXPECT_FALSE(ScrollingTouchAction().has_value());
+}
+
+TEST_F(TouchActionFilterTest, OnHasTouchEventHandlersReceivedAfterTouchStart) {
+ filter_.OnHasTouchEventHandlers(true);
+ EXPECT_FALSE(ScrollingTouchAction().has_value());
+ EXPECT_FALSE(filter_.allowed_touch_action().has_value());
+
+ // Receive a touch start ack, set the touch action.
+ filter_.OnSetTouchAction(cc::kTouchActionPanY);
+ filter_.SetActiveTouchInProgress(true);
+ filter_.OnHasTouchEventHandlers(false);
+ EXPECT_EQ(ScrollingTouchAction().value(), cc::kTouchActionPanY);
+ EXPECT_EQ(filter_.allowed_touch_action().value(), cc::kTouchActionPanY);
+ filter_.OnHasTouchEventHandlers(true);
+ EXPECT_EQ(ScrollingTouchAction().value(), cc::kTouchActionPanY);
+ EXPECT_EQ(filter_.allowed_touch_action().value(), cc::kTouchActionPanY);
+}
+
+// If the renderer is busy, the gesture event might have come before the
+// OnHasTouchEventHanlders IPC is received. In this case, we should allow all
+// the gestures.
+TEST_F(TouchActionFilterTest, GestureArrivesBeforeHasHandlerSet) {
+ WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::kGestureTapDown, kSourceDevice);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
+}
+
+TEST_F(TouchActionFilterTest, ResetBeforeHasHandlerSet) {
+ // This should not crash, and should set touch action to auto.
+ filter_.ResetTouchAction();
+ WebGestureEvent tap_down = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::kGestureTapDown, kSourceDevice);
+ EXPECT_EQ(filter_.FilterGestureEvent(&tap_down),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
+}
+
+// Having a gesture scroll begin without tap down should set touch action to
+// Auto.
+TEST_F(TouchActionFilterTest, ScrollBeginWithoutTapDown) {
+ filter_.OnHasTouchEventHandlers(true);
+ EXPECT_FALSE(ScrollingTouchAction().has_value());
+ EXPECT_FALSE(filter_.allowed_touch_action().has_value());
+
+ WebGestureEvent scroll_begin =
+ SyntheticWebGestureEventBuilder::BuildScrollBegin(5, 0, kSourceDevice);
+ EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
+ EXPECT_EQ(ScrollingTouchAction().value(), cc::kTouchActionAuto);
+ EXPECT_EQ(filter_.allowed_touch_action().value(), cc::kTouchActionAuto);
+}
+
+TEST_F(TouchActionFilterTest, ScrollBeginWithoutTapDownWithKnownTouchAction) {
+ filter_.OnHasTouchEventHandlers(true);
+ EXPECT_FALSE(ScrollingTouchAction().has_value());
+ EXPECT_FALSE(filter_.allowed_touch_action().has_value());
+
+ filter_.OnSetTouchAction(cc::kTouchActionPan);
+ WebGestureEvent scroll_begin =
+ SyntheticWebGestureEventBuilder::BuildScrollBegin(5, 0, kSourceDevice);
+ EXPECT_EQ(filter_.FilterGestureEvent(&scroll_begin),
+ FilterGestureEventResult::kFilterGestureEventAllowed);
+ EXPECT_EQ(ScrollingTouchAction().value(), cc::kTouchActionPan);
+ EXPECT_EQ(filter_.allowed_touch_action().value(), cc::kTouchActionPan);
}
TEST_F(TouchActionFilterTest, TouchpadScroll) {
diff --git a/chromium/content/browser/renderer_host/input/touch_emulator.cc b/chromium/content/browser/renderer_host/input/touch_emulator.cc
index bb6fb67ff9f..e5cfa600cf5 100644
--- a/chromium/content/browser/renderer_host/input/touch_emulator.cc
+++ b/chromium/content/browser/renderer_host/input/touch_emulator.cc
@@ -363,14 +363,7 @@ void TouchEmulator::OnGestureEvent(const ui::GestureEventData& gesture) {
WebGestureEvent gesture_event =
ui::CreateWebGestureEventFromGestureEventData(gesture);
- if (!gesture_event.unique_touch_event_id) {
- // TODO(wjmaclean): Find out why the local GestureProvider puts id=0 on
- // kGestureShowPress. This is a problem for RWHIER as it will cause it to
- // attempt to re-target the event. There must be a nicer solution than
- // setting the id to -1.
- DCHECK(gesture_event.GetType() == blink::WebInputEvent::kGestureShowPress);
- gesture_event.unique_touch_event_id = -1;
- }
+ DCHECK(gesture_event.unique_touch_event_id);
switch (gesture_event.GetType()) {
case WebInputEvent::kUndefined:
@@ -528,11 +521,12 @@ void TouchEmulator::ScrollEnd(const WebGestureEvent& event) {
WebGestureEvent TouchEmulator::GetPinchGestureEvent(
WebInputEvent::Type type,
- const WebInputEvent& original_event) {
+ const WebGestureEvent& original_event) {
WebGestureEvent event(type, ModifiersWithoutMouseButtons(original_event),
original_event.TimeStamp(),
blink::kWebGestureDeviceTouchscreen);
event.SetPositionInWidget(pinch_anchor_);
+ event.unique_touch_event_id = original_event.unique_touch_event_id;
return event;
}
diff --git a/chromium/content/browser/renderer_host/input/touch_emulator.h b/chromium/content/browser/renderer_host/input/touch_emulator.h
index 3ff06e2158b..55fabad3b55 100644
--- a/chromium/content/browser/renderer_host/input/touch_emulator.h
+++ b/chromium/content/browser/renderer_host/input/touch_emulator.h
@@ -105,7 +105,7 @@ class CONTENT_EXPORT TouchEmulator : public ui::GestureProviderClient {
const gfx::PointF& pos_in_root);
blink::WebGestureEvent GetPinchGestureEvent(
blink::WebInputEvent::Type type,
- const blink::WebInputEvent& original_event);
+ const blink::WebGestureEvent& original_event);
// The following methods generate and pass gesture events to the renderer.
void PinchBegin(const blink::WebGestureEvent& event);
diff --git a/chromium/content/browser/renderer_host/input/touch_input_browsertest.cc b/chromium/content/browser/renderer_host/input/touch_input_browsertest.cc
index f223edca1d7..ddab75b7c0a 100644
--- a/chromium/content/browser/renderer_host/input/touch_input_browsertest.cc
+++ b/chromium/content/browser/renderer_host/input/touch_input_browsertest.cc
@@ -10,6 +10,7 @@
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
+#include "components/viz/common/features.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
@@ -22,6 +23,7 @@
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/hit_test_region_observer.h"
#include "content/shell/browser/shell.h"
#include "third_party/blink/public/platform/web_input_event.h"
#include "ui/latency/latency_info.h"
@@ -30,13 +32,6 @@ using blink::WebInputEvent;
namespace {
-void GiveItSomeTime() {
- base::RunLoop run_loop;
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, run_loop.QuitClosure(), base::TimeDelta::FromMilliseconds(10));
- run_loop.Run();
-}
-
const char kTouchEventDataURL[] =
"data:text/html;charset=utf-8,"
#if defined(OS_ANDROID)
@@ -113,11 +108,23 @@ class TouchInputBrowserTest : public ContentBrowserTest {
NavigateToURL(shell(), data_url);
RenderWidgetHostImpl* host = GetWidgetHost();
+ // Wait to confirm a frame was generated from the navigation.
+ RenderFrameSubmissionObserver frame_observer(
+ host->render_frame_metadata_provider());
+ frame_observer.WaitForMetadataChange();
+
+#if !defined(OS_ANDROID)
+ // On non-Android, set a size for the view, and wait for a new frame to be
+ // generated at that size. On Android the size is specified in
+ // kTouchEventDataURL.
host->GetView()->SetSize(gfx::Size(400, 400));
+ frame_observer.WaitForAnyFrameSubmission();
+#endif
- // The page is loaded in the renderer, wait for a new frame to arrive.
- while (!host->RequestRepaintForTesting())
- GiveItSomeTime();
+ if (features::IsVizHitTestingEnabled()) {
+ HitTestRegionObserver observer(host->GetFrameSinkId());
+ observer.WaitForHitTestData();
+ }
}
void SetUpCommandLine(base::CommandLine* cmd) override {
@@ -126,13 +133,7 @@ class TouchInputBrowserTest : public ContentBrowserTest {
}
};
-#if defined(OS_MACOSX)
-// TODO(ccameron): Failing on mac: crbug.com/346363
-#define MAYBE_TouchNoHandler DISABLED_TouchNoHandler
-#else
-#define MAYBE_TouchNoHandler TouchNoHandler
-#endif
-IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, MAYBE_TouchNoHandler) {
+IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, TouchNoHandler) {
LoadURL();
SyntheticWebTouchEvent touch;
@@ -150,13 +151,7 @@ IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, MAYBE_TouchNoHandler) {
SendTouchEvent(&touch);
}
-#if defined(OS_CHROMEOS)
-// crbug.com/514456
-#define MAYBE_TouchHandlerNoConsume DISABLED_TouchHandlerNoConsume
-#else
-#define MAYBE_TouchHandlerNoConsume TouchHandlerNoConsume
-#endif
-IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, MAYBE_TouchHandlerNoConsume) {
+IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, TouchHandlerNoConsume) {
LoadURL();
SyntheticWebTouchEvent touch;
@@ -173,13 +168,7 @@ IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, MAYBE_TouchHandlerNoConsume) {
filter->WaitForAck();
}
-#if defined(OS_CHROMEOS)
-// crbug.com/514456
-#define MAYBE_TouchHandlerConsume DISABLED_TouchHandlerConsume
-#else
-#define MAYBE_TouchHandlerConsume TouchHandlerConsume
-#endif
-IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, MAYBE_TouchHandlerConsume) {
+IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, TouchHandlerConsume) {
LoadURL();
SyntheticWebTouchEvent touch;
@@ -196,16 +185,7 @@ IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, MAYBE_TouchHandlerConsume) {
filter->WaitForAck();
}
-#if defined(OS_CHROMEOS)
-// crbug.com/514456
-#define MAYBE_MultiPointTouchPress DISABLED_MultiPointTouchPress
-#elif defined(OS_MACOSX)
-// TODO(ccameron): Failing on mac: crbug.com/346363
-#define MAYBE_MultiPointTouchPress DISABLED_MultiPointTouchPress
-#else
-#define MAYBE_MultiPointTouchPress MultiPointTouchPress
-#endif
-IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, MAYBE_MultiPointTouchPress) {
+IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, MultiPointTouchPress) {
LoadURL();
SyntheticWebTouchEvent touch;
diff --git a/chromium/content/browser/renderer_host/input/touch_selection_controller_client_aura.h b/chromium/content/browser/renderer_host/input/touch_selection_controller_client_aura.h
index a18886536d5..572c56b0e69 100644
--- a/chromium/content/browser/renderer_host/input/touch_selection_controller_client_aura.h
+++ b/chromium/content/browser/renderer_host/input/touch_selection_controller_client_aura.h
@@ -122,7 +122,7 @@ class CONTENT_EXPORT TouchSelectionControllerClientAura
gfx::SelectionBound manager_selection_start_;
gfx::SelectionBound manager_selection_end_;
- base::ObserverList<TouchSelectionControllerClientManager::Observer>
+ base::ObserverList<TouchSelectionControllerClientManager::Observer>::Unchecked
observers_;
base::RetainingOneShotTimer quick_menu_timer_;
diff --git a/chromium/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc b/chromium/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc
index d8350f38862..86f8645c735 100644
--- a/chromium/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc
+++ b/chromium/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc
@@ -682,8 +682,6 @@ IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
rwhva->selection_controller()->active_status());
EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
- ui::test::EventGeneratorDelegate* generator_delegate =
- ui::test::EventGenerator::default_delegate;
gfx::NativeView native_view = rwhva->GetNativeView();
ui::test::EventGenerator generator(native_view->GetRootWindow());
@@ -694,7 +692,7 @@ IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
gfx::PointF point_f;
ASSERT_TRUE(GetPointInsideTextfield(&point_f));
gfx::Point point = gfx::ToRoundedPoint(point_f);
- generator_delegate->ConvertPointFromTarget(native_view, &point);
+ generator.delegate()->ConvertPointFromTarget(native_view, &point);
generator.GestureTapAt(point);
selection_controller_client()->Wait();
@@ -707,7 +705,7 @@ IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
// Tap on the insertion handle; the quick menu should appear.
gfx::Point handle_center = gfx::ToRoundedPoint(
rwhva->selection_controller()->GetStartHandleRect().CenterPoint());
- generator_delegate->ConvertPointFromTarget(native_view, &handle_center);
+ generator.delegate()->ConvertPointFromTarget(native_view, &handle_center);
generator.GestureTapAt(handle_center);
EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
diff --git a/chromium/content/browser/renderer_host/input/touch_selection_controller_client_manager_android.h b/chromium/content/browser/renderer_host/input/touch_selection_controller_client_manager_android.h
index 9cea813f8d8..b839bddccbf 100644
--- a/chromium/content/browser/renderer_host/input/touch_selection_controller_client_manager_android.h
+++ b/chromium/content/browser/renderer_host/input/touch_selection_controller_client_manager_android.h
@@ -55,7 +55,7 @@ class TouchSelectionControllerClientManagerAndroid
float page_scale_factor_;
gfx::SelectionBound manager_selection_start_;
gfx::SelectionBound manager_selection_end_;
- base::ObserverList<TouchSelectionControllerClientManager::Observer>
+ base::ObserverList<TouchSelectionControllerClientManager::Observer>::Unchecked
observers_;
DISALLOW_COPY_AND_ASSIGN(TouchSelectionControllerClientManagerAndroid);
diff --git a/chromium/content/browser/renderer_host/input/touchpad_pinch_browsertest.cc b/chromium/content/browser/renderer_host/input/touchpad_pinch_browsertest.cc
index 7111ab6ae9c..9d60505dcb8 100644
--- a/chromium/content/browser/renderer_host/input/touchpad_pinch_browsertest.cc
+++ b/chromium/content/browser/renderer_host/input/touchpad_pinch_browsertest.cc
@@ -3,8 +3,10 @@
// found in the LICENSE file.
#include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_features.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
@@ -55,9 +57,18 @@ const char kTouchpadPinchDataURL[] =
namespace content {
-class TouchpadPinchBrowserTest : public ContentBrowserTest {
+class TouchpadPinchBrowserTest : public ContentBrowserTest,
+ public testing::WithParamInterface<bool> {
public:
- TouchpadPinchBrowserTest() = default;
+ TouchpadPinchBrowserTest() {
+ if (GetParam()) {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kTouchpadAsyncPinchEvents);
+ } else {
+ scoped_feature_list_.InitAndDisableFeature(
+ features::kTouchpadAsyncPinchEvents);
+ }
+ }
~TouchpadPinchBrowserTest() override = default;
protected:
@@ -78,10 +89,16 @@ class TouchpadPinchBrowserTest : public ContentBrowserTest {
MainThreadFrameObserver observer(GetRenderWidgetHost());
observer.Wait();
}
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+ DISALLOW_COPY_AND_ASSIGN(TouchpadPinchBrowserTest);
};
+INSTANTIATE_TEST_CASE_P(, TouchpadPinchBrowserTest, testing::Bool());
+
// Performing a touchpad pinch gesture should change the page scale.
-IN_PROC_BROWSER_TEST_F(TouchpadPinchBrowserTest,
+IN_PROC_BROWSER_TEST_P(TouchpadPinchBrowserTest,
TouchpadPinchChangesPageScale) {
LoadURL();
@@ -98,7 +115,7 @@ IN_PROC_BROWSER_TEST_F(TouchpadPinchBrowserTest,
// We should offer synthetic wheel events to the page when a touchpad pinch
// is performed.
-IN_PROC_BROWSER_TEST_F(TouchpadPinchBrowserTest, WheelListenerAllowingPinch) {
+IN_PROC_BROWSER_TEST_P(TouchpadPinchBrowserTest, WheelListenerAllowingPinch) {
LoadURL();
ASSERT_TRUE(
content::ExecuteScript(shell()->web_contents(), "setListener(false);"));
@@ -129,7 +146,7 @@ IN_PROC_BROWSER_TEST_F(TouchpadPinchBrowserTest, WheelListenerAllowingPinch) {
// If the synthetic wheel event for a touchpad pinch is canceled, we should not
// change the page scale.
-IN_PROC_BROWSER_TEST_F(TouchpadPinchBrowserTest, WheelListenerPreventingPinch) {
+IN_PROC_BROWSER_TEST_P(TouchpadPinchBrowserTest, WheelListenerPreventingPinch) {
LoadURL();
// Perform an initial pinch so we can figure out the page scale we're
diff --git a/chromium/content/browser/renderer_host/input/touchpad_pinch_event_queue.cc b/chromium/content/browser/renderer_host/input/touchpad_pinch_event_queue.cc
index f0279ae7225..fa6ca271fa9 100644
--- a/chromium/content/browser/renderer_host/input/touchpad_pinch_event_queue.cc
+++ b/chromium/content/browser/renderer_host/input/touchpad_pinch_event_queue.cc
@@ -5,6 +5,7 @@
#include "content/browser/renderer_host/input/touchpad_pinch_event_queue.h"
#include "base/trace_event/trace_event.h"
+#include "content/public/common/content_features.h"
#include "third_party/blink/public/platform/web_mouse_wheel_event.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/blink/blink_event_util.h"
@@ -15,8 +16,29 @@ namespace content {
namespace {
blink::WebMouseWheelEvent CreateSyntheticWheelFromTouchpadPinchEvent(
- const blink::WebGestureEvent& pinch_event) {
- DCHECK_EQ(blink::WebInputEvent::kGesturePinchUpdate, pinch_event.GetType());
+ const blink::WebGestureEvent& pinch_event,
+ blink::WebMouseWheelEvent::Phase phase,
+ bool cancelable) {
+ DCHECK(pinch_event.GetType() == blink::WebInputEvent::kGesturePinchUpdate ||
+ pinch_event.GetType() == blink::WebInputEvent::kGesturePinchEnd);
+ float delta_y = 0.0f;
+ float wheel_ticks_y = 0.0f;
+
+ // The function to convert scales to deltaY values is designed to be
+ // compatible with websites existing use of wheel events, and with existing
+ // Windows trackpad behavior. In particular, we want:
+ // - deltas should accumulate via addition: f(s1*s2)==f(s1)+f(s2)
+ // - deltas should invert via negation: f(1/s) == -f(s)
+ // - zoom in should be positive: f(s) > 0 iff s > 1
+ // - magnitude roughly matches wheels: f(2) > 25 && f(2) < 100
+ // - a formula that's relatively easy to use from JavaScript
+ // Note that 'wheel' event deltaY values have their sign inverted. So to
+ // convert a wheel deltaY back to a scale use Math.exp(-deltaY/100).
+ if (pinch_event.GetType() == blink::WebInputEvent::kGesturePinchUpdate) {
+ DCHECK_GT(pinch_event.data.pinch_update.scale, 0);
+ delta_y = 100.0f * log(pinch_event.data.pinch_update.scale);
+ wheel_ticks_y = pinch_event.data.pinch_update.scale > 1 ? 1 : -1;
+ }
// For pinch gesture events, similar to ctrl+wheel zooming, allow content to
// prevent the browser from zooming by sending fake wheel events with the ctrl
@@ -29,22 +51,18 @@ blink::WebMouseWheelEvent CreateSyntheticWheelFromTouchpadPinchEvent(
wheel_event.SetPositionInWidget(pinch_event.PositionInWidget());
wheel_event.SetPositionInScreen(pinch_event.PositionInScreen());
wheel_event.delta_x = 0;
+ wheel_event.delta_y = delta_y;
- // The function to convert scales to deltaY values is designed to be
- // compatible with websites existing use of wheel events, and with existing
- // Windows trackpad behavior. In particular, we want:
- // - deltas should accumulate via addition: f(s1*s2)==f(s1)+f(s2)
- // - deltas should invert via negation: f(1/s) == -f(s)
- // - zoom in should be positive: f(s) > 0 iff s > 1
- // - magnitude roughly matches wheels: f(2) > 25 && f(2) < 100
- // - a formula that's relatively easy to use from JavaScript
- // Note that 'wheel' event deltaY values have their sign inverted. So to
- // convert a wheel deltaY back to a scale use Math.exp(-deltaY/100).
- DCHECK_GT(pinch_event.data.pinch_update.scale, 0);
- wheel_event.delta_y = 100.0f * log(pinch_event.data.pinch_update.scale);
wheel_event.has_precise_scrolling_deltas = true;
+
+ wheel_event.phase = phase;
wheel_event.wheel_ticks_x = 0;
- wheel_event.wheel_ticks_y = pinch_event.data.pinch_update.scale > 1 ? 1 : -1;
+ wheel_event.wheel_ticks_y = wheel_ticks_y;
+
+ if (cancelable)
+ wheel_event.dispatch_type = blink::WebInputEvent::kBlocking;
+ else
+ wheel_event.dispatch_type = blink::WebInputEvent::kEventNonBlocking;
return wheel_event;
}
@@ -71,7 +89,9 @@ class QueuedTouchpadPinchEvent : public GestureEventWithLatencyInfo {
TouchpadPinchEventQueue::TouchpadPinchEventQueue(
TouchpadPinchEventQueueClient* client)
- : client_(client) {
+ : touchpad_async_pinch_events_(
+ base::FeatureList::IsEnabled(features::kTouchpadAsyncPinchEvents)),
+ client_(client) {
DCHECK(client_);
}
@@ -110,6 +130,11 @@ void TouchpadPinchEventQueue::ProcessMouseWheelAck(
if (!pinch_event_awaiting_ack_)
return;
+ if (pinch_event_awaiting_ack_->event.GetType() ==
+ blink::WebInputEvent::kGesturePinchUpdate &&
+ !first_event_prevented_.has_value())
+ first_event_prevented_ = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED);
+
pinch_event_awaiting_ack_->latency.AddNewLatencyFrom(latency_info);
client_->OnGestureEventForPinchAck(*pinch_event_awaiting_ack_, ack_source,
ack_result);
@@ -129,15 +154,7 @@ void TouchpadPinchEventQueue::TryForwardNextEventToRenderer() {
pinch_queue_.pop_front();
if (pinch_event_awaiting_ack_->event.GetType() ==
- blink::WebInputEvent::kGesturePinchBegin ||
- pinch_event_awaiting_ack_->event.GetType() ==
- blink::WebInputEvent::kGesturePinchEnd) {
- // Wheel event listeners are given individual events with no phase
- // information, so we don't need to do anything at the beginning or
- // end of a pinch.
- // TODO(565980): Consider sending the rest of the wheel events as
- // non-blocking if the first wheel event of the pinch sequence is not
- // consumed.
+ blink::WebInputEvent::kGesturePinchBegin) {
client_->OnGestureEventForPinchAck(*pinch_event_awaiting_ack_,
InputEventAckSource::BROWSER,
INPUT_EVENT_ACK_STATE_IGNORED);
@@ -146,9 +163,34 @@ void TouchpadPinchEventQueue::TryForwardNextEventToRenderer() {
return;
}
+ blink::WebMouseWheelEvent::Phase phase =
+ blink::WebMouseWheelEvent::kPhaseNone;
+ bool cancelable = true;
+
+ if (pinch_event_awaiting_ack_->event.GetType() ==
+ blink::WebInputEvent::kGesturePinchEnd) {
+ first_event_prevented_.reset();
+ phase = blink::WebMouseWheelEvent::kPhaseEnded;
+ cancelable = false;
+ } else {
+ DCHECK_EQ(pinch_event_awaiting_ack_->event.GetType(),
+ blink::WebInputEvent::kGesturePinchUpdate);
+ // The first pinch update event should send a synthetic wheel with phase
+ // began.
+ if (!first_event_prevented_.has_value()) {
+ phase = blink::WebMouseWheelEvent::kPhaseBegan;
+ cancelable = true;
+ } else {
+ phase = blink::WebMouseWheelEvent::kPhaseChanged;
+ cancelable =
+ !touchpad_async_pinch_events_ || first_event_prevented_.value();
+ }
+ }
+
+ DCHECK_NE(phase, blink::WebMouseWheelEvent::kPhaseNone);
const MouseWheelEventWithLatencyInfo synthetic_wheel(
CreateSyntheticWheelFromTouchpadPinchEvent(
- pinch_event_awaiting_ack_->event),
+ pinch_event_awaiting_ack_->event, phase, cancelable),
pinch_event_awaiting_ack_->latency);
client_->SendMouseWheelEventForPinchImmediately(synthetic_wheel);
diff --git a/chromium/content/browser/renderer_host/input/touchpad_pinch_event_queue.h b/chromium/content/browser/renderer_host/input/touchpad_pinch_event_queue.h
index f7def2c8636..4fbbb71f1d0 100644
--- a/chromium/content/browser/renderer_host/input/touchpad_pinch_event_queue.h
+++ b/chromium/content/browser/renderer_host/input/touchpad_pinch_event_queue.h
@@ -8,6 +8,7 @@
#include <memory>
#include "base/containers/circular_deque.h"
+#include "base/optional.h"
#include "content/common/content_export.h"
#include "content/common/input/event_with_latency_info.h"
#include "content/public/common/input_event_ack_source.h"
@@ -63,10 +64,12 @@ class CONTENT_EXPORT TouchpadPinchEventQueue {
private:
void TryForwardNextEventToRenderer();
+ const bool touchpad_async_pinch_events_;
TouchpadPinchEventQueueClient* client_;
base::circular_deque<std::unique_ptr<QueuedTouchpadPinchEvent>> pinch_queue_;
std::unique_ptr<QueuedTouchpadPinchEvent> pinch_event_awaiting_ack_;
+ base::Optional<bool> first_event_prevented_;
DISALLOW_COPY_AND_ASSIGN(TouchpadPinchEventQueue);
};
diff --git a/chromium/content/browser/renderer_host/input/touchpad_pinch_event_queue_unittest.cc b/chromium/content/browser/renderer_host/input/touchpad_pinch_event_queue_unittest.cc
index 73c6424a06e..e273c29e681 100644
--- a/chromium/content/browser/renderer_host/input/touchpad_pinch_event_queue_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/touchpad_pinch_event_queue_unittest.cc
@@ -6,7 +6,9 @@
#include <string>
+#include "base/test/scoped_feature_list.h"
#include "content/common/input/event_with_latency_info.h"
+#include "content/public/common/content_features.h"
#include "content/public/common/input_event_ack_source.h"
#include "content/public/common/input_event_ack_state.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -30,13 +32,22 @@ class MockTouchpadPinchEventQueueClient : public TouchpadPinchEventQueueClient {
InputEventAckState ack_result));
};
-class TouchpadPinchEventQueueTest : public ::testing::Test {
+class TouchpadPinchEventQueueTest : public testing::TestWithParam<bool> {
protected:
- TouchpadPinchEventQueueTest() : queue_(&mock_client_) {}
+ TouchpadPinchEventQueueTest() : async_events_enabled_(GetParam()) {
+ if (async_events_enabled_) {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kTouchpadAsyncPinchEvents);
+ } else {
+ scoped_feature_list_.InitAndDisableFeature(
+ features::kTouchpadAsyncPinchEvents);
+ }
+ queue_ = std::make_unique<TouchpadPinchEventQueue>(&mock_client_);
+ }
~TouchpadPinchEventQueueTest() = default;
void QueueEvent(const blink::WebGestureEvent& event) {
- queue_.QueueEvent(GestureEventWithLatencyInfo(event));
+ queue_->QueueEvent(GestureEventWithLatencyInfo(event));
}
void QueuePinchBegin() {
@@ -79,13 +90,17 @@ class TouchpadPinchEventQueueTest : public ::testing::Test {
void SendWheelEventAck(InputEventAckSource ack_source,
InputEventAckState ack_result) {
- queue_.ProcessMouseWheelAck(ack_source, ack_result, ui::LatencyInfo());
+ queue_->ProcessMouseWheelAck(ack_source, ack_result, ui::LatencyInfo());
}
+ base::test::ScopedFeatureList scoped_feature_list_;
testing::StrictMock<MockTouchpadPinchEventQueueClient> mock_client_;
- TouchpadPinchEventQueue queue_;
+ std::unique_ptr<TouchpadPinchEventQueue> queue_;
+ const bool async_events_enabled_;
};
+INSTANTIATE_TEST_CASE_P(, TouchpadPinchEventQueueTest, ::testing::Bool());
+
MATCHER_P(EventHasType,
type,
std::string(negation ? "does not have" : "has") + " type " +
@@ -93,6 +108,13 @@ MATCHER_P(EventHasType,
return arg.event.GetType() == type;
}
+MATCHER_P(EventHasPhase,
+ phase,
+ std::string(negation ? "does not have" : "has") + " phase " +
+ ::testing::PrintToString(phase)) {
+ return arg.event.phase == phase;
+}
+
MATCHER(EventHasCtrlModifier,
std::string(negation ? "does not have" : "has") + " control modifier") {
return (arg.event.GetModifiers() & blink::WebInputEvent::kControlKey) != 0;
@@ -105,7 +127,7 @@ MATCHER(EventIsBlocking,
// Ensure that when the queue receives a touchpad pinch sequence, it sends a
// synthetic mouse wheel event and acks the pinch events back to the client.
-TEST_F(TouchpadPinchEventQueueTest, Basic) {
+TEST_P(TouchpadPinchEventQueueTest, Basic) {
::testing::InSequence sequence;
EXPECT_CALL(mock_client_,
OnGestureEventForPinchAck(
@@ -120,6 +142,9 @@ TEST_F(TouchpadPinchEventQueueTest, Basic) {
InputEventAckSource::COMPOSITOR_THREAD,
INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS));
EXPECT_CALL(mock_client_,
+ SendMouseWheelEventForPinchImmediately(::testing::AllOf(
+ EventHasCtrlModifier(), ::testing::Not(EventIsBlocking()))));
+ EXPECT_CALL(mock_client_,
OnGestureEventForPinchAck(
EventHasType(blink::WebInputEvent::kGesturePinchEnd),
InputEventAckSource::BROWSER, INPUT_EVENT_ACK_STATE_IGNORED));
@@ -129,11 +154,60 @@ TEST_F(TouchpadPinchEventQueueTest, Basic) {
SendWheelEventAck(InputEventAckSource::COMPOSITOR_THREAD,
INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
QueuePinchEnd();
+ SendWheelEventAck(InputEventAckSource::BROWSER,
+ INPUT_EVENT_ACK_STATE_IGNORED);
+}
+
+// Ensure the queue sends the wheel events with phase information.
+TEST_P(TouchpadPinchEventQueueTest, MouseWheelPhase) {
+ ::testing::InSequence sequence;
+ EXPECT_CALL(mock_client_,
+ OnGestureEventForPinchAck(
+ EventHasType(blink::WebInputEvent::kGesturePinchBegin),
+ InputEventAckSource::BROWSER, INPUT_EVENT_ACK_STATE_IGNORED));
+ EXPECT_CALL(mock_client_,
+ SendMouseWheelEventForPinchImmediately(
+ EventHasPhase(blink::WebMouseWheelEvent::kPhaseBegan)));
+ EXPECT_CALL(mock_client_,
+ OnGestureEventForPinchAck(
+ EventHasType(blink::WebInputEvent::kGesturePinchUpdate),
+ InputEventAckSource::COMPOSITOR_THREAD,
+ INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS));
+ EXPECT_CALL(mock_client_,
+ SendMouseWheelEventForPinchImmediately(
+ EventHasPhase(blink::WebMouseWheelEvent::kPhaseChanged)));
+ EXPECT_CALL(mock_client_,
+ OnGestureEventForPinchAck(
+ EventHasType(blink::WebInputEvent::kGesturePinchUpdate),
+ testing::_, testing::_));
+ EXPECT_CALL(mock_client_,
+ SendMouseWheelEventForPinchImmediately(
+ EventHasPhase(blink::WebMouseWheelEvent::kPhaseEnded)));
+ EXPECT_CALL(mock_client_,
+ OnGestureEventForPinchAck(
+ EventHasType(blink::WebInputEvent::kGesturePinchEnd),
+ InputEventAckSource::BROWSER, INPUT_EVENT_ACK_STATE_IGNORED));
+
+ QueuePinchBegin();
+ QueuePinchUpdate(1.23, false);
+ SendWheelEventAck(InputEventAckSource::COMPOSITOR_THREAD,
+ INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ QueuePinchUpdate(1.23, false);
+ if (async_events_enabled_) {
+ SendWheelEventAck(InputEventAckSource::BROWSER,
+ INPUT_EVENT_ACK_STATE_IGNORED);
+ } else {
+ SendWheelEventAck(InputEventAckSource::COMPOSITOR_THREAD,
+ INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ }
+ QueuePinchEnd();
+ SendWheelEventAck(InputEventAckSource::BROWSER,
+ INPUT_EVENT_ACK_STATE_IGNORED);
}
// Ensure that if the renderer consumes the synthetic wheel event, the ack of
// the GesturePinchUpdate reflects this.
-TEST_F(TouchpadPinchEventQueueTest, Consumed) {
+TEST_P(TouchpadPinchEventQueueTest, Consumed) {
::testing::InSequence sequence;
EXPECT_CALL(mock_client_,
OnGestureEventForPinchAck(
@@ -147,6 +221,11 @@ TEST_F(TouchpadPinchEventQueueTest, Consumed) {
OnGestureEventForPinchAck(
EventHasType(blink::WebInputEvent::kGesturePinchUpdate),
InputEventAckSource::MAIN_THREAD, INPUT_EVENT_ACK_STATE_CONSUMED));
+
+ EXPECT_CALL(mock_client_,
+ SendMouseWheelEventForPinchImmediately(::testing::AllOf(
+ EventHasCtrlModifier(), ::testing::Not(EventIsBlocking()))));
+
EXPECT_CALL(mock_client_,
OnGestureEventForPinchAck(
EventHasType(blink::WebInputEvent::kGesturePinchEnd),
@@ -157,11 +236,13 @@ TEST_F(TouchpadPinchEventQueueTest, Consumed) {
SendWheelEventAck(InputEventAckSource::MAIN_THREAD,
INPUT_EVENT_ACK_STATE_CONSUMED);
QueuePinchEnd();
+ SendWheelEventAck(InputEventAckSource::BROWSER,
+ INPUT_EVENT_ACK_STATE_IGNORED);
}
// Ensure that the queue sends wheel events for updates with |zoom_disabled| as
// well.
-TEST_F(TouchpadPinchEventQueueTest, ZoomDisabled) {
+TEST_P(TouchpadPinchEventQueueTest, ZoomDisabled) {
::testing::InSequence sequence;
EXPECT_CALL(mock_client_,
OnGestureEventForPinchAck(
@@ -175,6 +256,11 @@ TEST_F(TouchpadPinchEventQueueTest, ZoomDisabled) {
EventHasType(blink::WebInputEvent::kGesturePinchUpdate),
InputEventAckSource::COMPOSITOR_THREAD,
INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS));
+
+ EXPECT_CALL(mock_client_,
+ SendMouseWheelEventForPinchImmediately(::testing::AllOf(
+ EventHasCtrlModifier(), ::testing::Not(EventIsBlocking()))));
+
EXPECT_CALL(mock_client_,
OnGestureEventForPinchAck(
EventHasType(blink::WebInputEvent::kGesturePinchEnd),
@@ -185,16 +271,18 @@ TEST_F(TouchpadPinchEventQueueTest, ZoomDisabled) {
SendWheelEventAck(InputEventAckSource::COMPOSITOR_THREAD,
INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
QueuePinchEnd();
+ SendWheelEventAck(InputEventAckSource::BROWSER,
+ INPUT_EVENT_ACK_STATE_IGNORED);
}
-TEST_F(TouchpadPinchEventQueueTest, MultipleSequences) {
+TEST_P(TouchpadPinchEventQueueTest, MultipleSequences) {
EXPECT_CALL(mock_client_,
OnGestureEventForPinchAck(
EventHasType(blink::WebInputEvent::kGesturePinchBegin),
InputEventAckSource::BROWSER, INPUT_EVENT_ACK_STATE_IGNORED))
.Times(2);
EXPECT_CALL(mock_client_, SendMouseWheelEventForPinchImmediately(testing::_))
- .Times(2);
+ .Times(4);
EXPECT_CALL(mock_client_,
OnGestureEventForPinchAck(
EventHasType(blink::WebInputEvent::kGesturePinchUpdate),
@@ -212,17 +300,21 @@ TEST_F(TouchpadPinchEventQueueTest, MultipleSequences) {
SendWheelEventAck(InputEventAckSource::COMPOSITOR_THREAD,
INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
QueuePinchEnd();
+ SendWheelEventAck(InputEventAckSource::BROWSER,
+ INPUT_EVENT_ACK_STATE_IGNORED);
QueuePinchBegin();
QueuePinchUpdate(1.23, false);
SendWheelEventAck(InputEventAckSource::COMPOSITOR_THREAD,
INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
QueuePinchEnd();
+ SendWheelEventAck(InputEventAckSource::BROWSER,
+ INPUT_EVENT_ACK_STATE_IGNORED);
}
// Ensure we can queue additional pinch event sequences while the queue is
// waiting for a wheel event ack.
-TEST_F(TouchpadPinchEventQueueTest, MultipleQueuedSequences) {
+TEST_P(TouchpadPinchEventQueueTest, MultipleQueuedSequences) {
EXPECT_CALL(mock_client_,
OnGestureEventForPinchAck(
EventHasType(blink::WebInputEvent::kGesturePinchBegin),
@@ -255,9 +347,13 @@ TEST_F(TouchpadPinchEventQueueTest, MultipleQueuedSequences) {
OnGestureEventForPinchAck(
EventHasType(blink::WebInputEvent::kGesturePinchBegin),
InputEventAckSource::BROWSER, INPUT_EVENT_ACK_STATE_IGNORED));
- EXPECT_CALL(mock_client_, SendMouseWheelEventForPinchImmediately(testing::_));
+ EXPECT_CALL(mock_client_, SendMouseWheelEventForPinchImmediately(testing::_))
+ .Times(2);
SendWheelEventAck(InputEventAckSource::COMPOSITOR_THREAD,
INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ // ACK for end event.
+ SendWheelEventAck(InputEventAckSource::BROWSER,
+ INPUT_EVENT_ACK_STATE_IGNORED);
// After acking the first wheel event, the queue continues.
testing::Mock::VerifyAndClearExpectations(&mock_client_);
@@ -271,25 +367,61 @@ TEST_F(TouchpadPinchEventQueueTest, MultipleQueuedSequences) {
OnGestureEventForPinchAck(
EventHasType(blink::WebInputEvent::kGesturePinchEnd),
InputEventAckSource::BROWSER, INPUT_EVENT_ACK_STATE_IGNORED));
+ EXPECT_CALL(mock_client_, SendMouseWheelEventForPinchImmediately(testing::_));
SendWheelEventAck(InputEventAckSource::COMPOSITOR_THREAD,
INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ // ACK for end event.
+ SendWheelEventAck(InputEventAckSource::BROWSER,
+ INPUT_EVENT_ACK_STATE_IGNORED);
}
// Ensure the queue handles pinch event sequences with multiple updates.
-TEST_F(TouchpadPinchEventQueueTest, MultipleUpdatesInSequence) {
+TEST_P(TouchpadPinchEventQueueTest, MultipleUpdatesInSequence) {
EXPECT_CALL(mock_client_,
OnGestureEventForPinchAck(
EventHasType(blink::WebInputEvent::kGesturePinchBegin),
InputEventAckSource::BROWSER, INPUT_EVENT_ACK_STATE_IGNORED));
- EXPECT_CALL(mock_client_,
- SendMouseWheelEventForPinchImmediately(EventHasCtrlModifier()))
- .Times(3);
- EXPECT_CALL(mock_client_,
- OnGestureEventForPinchAck(
- EventHasType(blink::WebInputEvent::kGesturePinchUpdate),
- InputEventAckSource::COMPOSITOR_THREAD,
- INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS))
- .Times(3);
+ if (async_events_enabled_) {
+ // Only first wheel event is cancelable.
+ // Here the second and the third wheel events are not blocking because we
+ // ack the first wheel event as unconsumed.
+ EXPECT_CALL(mock_client_,
+ SendMouseWheelEventForPinchImmediately(::testing::AllOf(
+ EventHasCtrlModifier(), EventIsBlocking())));
+ EXPECT_CALL(mock_client_,
+ SendMouseWheelEventForPinchImmediately(::testing::AllOf(
+ EventHasCtrlModifier(), ::testing::Not(EventIsBlocking()))))
+ .Times(3);
+ } else {
+ EXPECT_CALL(mock_client_,
+ SendMouseWheelEventForPinchImmediately(::testing::AllOf(
+ EventHasCtrlModifier(), EventIsBlocking())))
+ .Times(3);
+ EXPECT_CALL(
+ mock_client_,
+ SendMouseWheelEventForPinchImmediately(::testing::AllOf(
+ EventHasCtrlModifier(), ::testing::Not(EventIsBlocking()))));
+ }
+ if (async_events_enabled_) {
+ EXPECT_CALL(mock_client_,
+ OnGestureEventForPinchAck(
+ EventHasType(blink::WebInputEvent::kGesturePinchUpdate),
+ InputEventAckSource::COMPOSITOR_THREAD,
+ INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS));
+ EXPECT_CALL(
+ mock_client_,
+ OnGestureEventForPinchAck(
+ EventHasType(blink::WebInputEvent::kGesturePinchUpdate),
+ InputEventAckSource::BROWSER, INPUT_EVENT_ACK_STATE_IGNORED))
+ .Times(2);
+ } else {
+ EXPECT_CALL(mock_client_,
+ OnGestureEventForPinchAck(
+ EventHasType(blink::WebInputEvent::kGesturePinchUpdate),
+ InputEventAckSource::COMPOSITOR_THREAD,
+ INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS))
+ .Times(3);
+ }
EXPECT_CALL(mock_client_,
OnGestureEventForPinchAck(
EventHasType(blink::WebInputEvent::kGesturePinchEnd),
@@ -300,29 +432,72 @@ TEST_F(TouchpadPinchEventQueueTest, MultipleUpdatesInSequence) {
SendWheelEventAck(InputEventAckSource::COMPOSITOR_THREAD,
INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
QueuePinchUpdate(1.23, false);
- SendWheelEventAck(InputEventAckSource::COMPOSITOR_THREAD,
- INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ if (async_events_enabled_) {
+ SendWheelEventAck(InputEventAckSource::BROWSER,
+ INPUT_EVENT_ACK_STATE_IGNORED);
+ } else {
+ SendWheelEventAck(InputEventAckSource::COMPOSITOR_THREAD,
+ INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ }
QueuePinchUpdate(1.23, false);
- SendWheelEventAck(InputEventAckSource::COMPOSITOR_THREAD,
- INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ if (async_events_enabled_) {
+ SendWheelEventAck(InputEventAckSource::BROWSER,
+ INPUT_EVENT_ACK_STATE_IGNORED);
+ } else {
+ SendWheelEventAck(InputEventAckSource::COMPOSITOR_THREAD,
+ INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ }
QueuePinchEnd();
+ SendWheelEventAck(InputEventAckSource::BROWSER,
+ INPUT_EVENT_ACK_STATE_IGNORED);
}
// Ensure the queue coalesces pinch update events.
-TEST_F(TouchpadPinchEventQueueTest, MultipleUpdatesCoalesced) {
+TEST_P(TouchpadPinchEventQueueTest, MultipleUpdatesCoalesced) {
EXPECT_CALL(mock_client_,
OnGestureEventForPinchAck(
EventHasType(blink::WebInputEvent::kGesturePinchBegin),
InputEventAckSource::BROWSER, INPUT_EVENT_ACK_STATE_IGNORED));
- EXPECT_CALL(mock_client_,
- SendMouseWheelEventForPinchImmediately(EventHasCtrlModifier()))
- .Times(2);
- EXPECT_CALL(mock_client_,
- OnGestureEventForPinchAck(
- EventHasType(blink::WebInputEvent::kGesturePinchUpdate),
- InputEventAckSource::COMPOSITOR_THREAD,
- INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS))
- .Times(2);
+ if (async_events_enabled_) {
+ // Only the first wheel event is cancelable.
+ // Here the second wheel is not blocking because we ack the first wheel
+ // event as unconsumed.
+ EXPECT_CALL(mock_client_,
+ SendMouseWheelEventForPinchImmediately(::testing::AllOf(
+ EventHasCtrlModifier(), EventIsBlocking())));
+ EXPECT_CALL(mock_client_,
+ SendMouseWheelEventForPinchImmediately(::testing::AllOf(
+ EventHasCtrlModifier(), ::testing::Not(EventIsBlocking()))))
+ .Times(2);
+ } else {
+ EXPECT_CALL(mock_client_,
+ SendMouseWheelEventForPinchImmediately(::testing::AllOf(
+ EventHasCtrlModifier(), EventIsBlocking())))
+ .Times(2);
+ EXPECT_CALL(
+ mock_client_,
+ SendMouseWheelEventForPinchImmediately(::testing::AllOf(
+ EventHasCtrlModifier(), ::testing::Not(EventIsBlocking()))));
+ }
+ if (async_events_enabled_) {
+ EXPECT_CALL(mock_client_,
+ OnGestureEventForPinchAck(
+ EventHasType(blink::WebInputEvent::kGesturePinchUpdate),
+ InputEventAckSource::COMPOSITOR_THREAD,
+ INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS));
+ EXPECT_CALL(
+ mock_client_,
+ OnGestureEventForPinchAck(
+ EventHasType(blink::WebInputEvent::kGesturePinchUpdate),
+ InputEventAckSource::BROWSER, INPUT_EVENT_ACK_STATE_IGNORED));
+ } else {
+ EXPECT_CALL(mock_client_,
+ OnGestureEventForPinchAck(
+ EventHasType(blink::WebInputEvent::kGesturePinchUpdate),
+ InputEventAckSource::COMPOSITOR_THREAD,
+ INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS))
+ .Times(2);
+ }
EXPECT_CALL(mock_client_,
OnGestureEventForPinchAck(
EventHasType(blink::WebInputEvent::kGesturePinchEnd),
@@ -342,9 +517,57 @@ TEST_F(TouchpadPinchEventQueueTest, MultipleUpdatesCoalesced) {
SendWheelEventAck(InputEventAckSource::COMPOSITOR_THREAD,
INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
// Ack for the wheel event corresponding to the second and third updates.
- SendWheelEventAck(InputEventAckSource::COMPOSITOR_THREAD,
- INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
- EXPECT_FALSE(queue_.has_pending());
+ if (async_events_enabled_) {
+ SendWheelEventAck(InputEventAckSource::BROWSER,
+ INPUT_EVENT_ACK_STATE_IGNORED);
+ } else {
+ SendWheelEventAck(InputEventAckSource::COMPOSITOR_THREAD,
+ INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ }
+ // ACK for end event.
+ SendWheelEventAck(InputEventAckSource::BROWSER,
+ INPUT_EVENT_ACK_STATE_IGNORED);
+ EXPECT_FALSE(queue_->has_pending());
+}
+
+// Ensure the queue handles pinch event sequences with multiple canceled
+// updates.
+TEST_P(TouchpadPinchEventQueueTest, MultipleCanceledUpdatesInSequence) {
+ EXPECT_CALL(mock_client_,
+ OnGestureEventForPinchAck(
+ EventHasType(blink::WebInputEvent::kGesturePinchBegin),
+ InputEventAckSource::BROWSER, INPUT_EVENT_ACK_STATE_IGNORED));
+ EXPECT_CALL(mock_client_,
+ SendMouseWheelEventForPinchImmediately(
+ ::testing::AllOf(EventHasCtrlModifier(), EventIsBlocking())))
+ .Times(3);
+ EXPECT_CALL(
+ mock_client_,
+ OnGestureEventForPinchAck(
+ EventHasType(blink::WebInputEvent::kGesturePinchUpdate),
+ InputEventAckSource::MAIN_THREAD, INPUT_EVENT_ACK_STATE_CONSUMED))
+ .Times(3);
+ EXPECT_CALL(mock_client_,
+ SendMouseWheelEventForPinchImmediately(::testing::AllOf(
+ EventHasCtrlModifier(), ::testing::Not(EventIsBlocking()))));
+ EXPECT_CALL(mock_client_,
+ OnGestureEventForPinchAck(
+ EventHasType(blink::WebInputEvent::kGesturePinchEnd),
+ InputEventAckSource::BROWSER, INPUT_EVENT_ACK_STATE_IGNORED));
+
+ QueuePinchBegin();
+ QueuePinchUpdate(1.23, false);
+ SendWheelEventAck(InputEventAckSource::MAIN_THREAD,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+ QueuePinchUpdate(1.23, false);
+ SendWheelEventAck(InputEventAckSource::MAIN_THREAD,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+ QueuePinchUpdate(1.23, false);
+ SendWheelEventAck(InputEventAckSource::MAIN_THREAD,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+ QueuePinchEnd();
+ SendWheelEventAck(InputEventAckSource::BROWSER,
+ INPUT_EVENT_ACK_STATE_IGNORED);
}
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/web_input_event_builders_android.cc b/chromium/content/browser/renderer_host/input/web_input_event_builders_android.cc
index 5a0fe4d5439..7972b781664 100644
--- a/chromium/content/browser/renderer_host/input/web_input_event_builders_android.cc
+++ b/chromium/content/browser/renderer_host/input/web_input_event_builders_android.cc
@@ -143,7 +143,9 @@ WebMouseEvent WebMouseEventBuilder::Build(
ui::SetWebPointerPropertiesFromMotionEventData(
result, motion_event.GetPointerId(0), motion_event.GetPressure(0),
motion_event.GetOrientation(0), motion_event.GetTiltX(0),
- motion_event.GetTiltY(0), button, motion_event.GetToolType(0));
+ motion_event.GetTiltY(0), motion_event.GetTwist(0),
+ motion_event.GetTangentialPressure(0), button,
+ motion_event.GetToolType(0));
return result;
}
diff --git a/chromium/content/browser/renderer_host/input/web_input_event_builders_mac.h b/chromium/content/browser/renderer_host/input/web_input_event_builders_mac.h
index d5755a74318..99f0d8695c1 100644
--- a/chromium/content/browser/renderer_host/input/web_input_event_builders_mac.h
+++ b/chromium/content/browser/renderer_host/input/web_input_event_builders_mac.h
@@ -10,6 +10,7 @@
#include "third_party/blink/public/platform/web_input_event.h"
#include "third_party/blink/public/platform/web_keyboard_event.h"
#include "third_party/blink/public/platform/web_mouse_wheel_event.h"
+#include "third_party/blink/public/platform/web_touch_event.h"
@class NSEvent;
@class NSView;
@@ -41,6 +42,11 @@ class CONTENT_EXPORT WebGestureEventBuilder {
static blink::WebGestureEvent Build(NSEvent*, NSView*);
};
+class CONTENT_EXPORT WebTouchEventBuilder {
+ public:
+ static blink::WebTouchEvent Build(NSEvent* event, NSView* view);
+};
+
} // namespace content
#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_WEB_INPUT_EVENT_BUILDERS_MAC_H_
diff --git a/chromium/content/browser/renderer_host/input/web_input_event_builders_mac.mm b/chromium/content/browser/renderer_host/input/web_input_event_builders_mac.mm
index be7624b1be3..cb734666c35 100644
--- a/chromium/content/browser/renderer_host/input/web_input_event_builders_mac.mm
+++ b/chromium/content/browser/renderer_host/input/web_input_event_builders_mac.mm
@@ -571,4 +571,72 @@ blink::WebGestureEvent WebGestureEventBuilder::Build(NSEvent* event,
return result;
}
+// WebTouchEvent --------------------------------------------------------------
+
+blink::WebTouchEvent WebTouchEventBuilder::Build(NSEvent* event, NSView* view) {
+ blink::WebInputEvent::Type event_type =
+ blink::WebInputEvent::Type::kUndefined;
+ NSEventType type = [event type];
+ blink::WebTouchPoint::State state = blink::WebTouchPoint::kStateUndefined;
+ switch (type) {
+ case NSLeftMouseDown:
+ event_type = blink::WebInputEvent::kTouchStart;
+ state = blink::WebTouchPoint::kStatePressed;
+ break;
+ case NSLeftMouseUp:
+ event_type = blink::WebInputEvent::kTouchEnd;
+ state = blink::WebTouchPoint::kStateReleased;
+ break;
+ case NSLeftMouseDragged:
+ case NSRightMouseDragged:
+ case NSOtherMouseDragged:
+ case NSMouseMoved:
+ case NSRightMouseDown:
+ case NSOtherMouseDown:
+ case NSRightMouseUp:
+ case NSOtherMouseUp:
+ event_type = blink::WebInputEvent::kTouchMove;
+ state = blink::WebTouchPoint::kStateMoved;
+ break;
+ default:
+ NOTREACHED() << "Invalid types for touch events." << type;
+ }
+
+ blink::WebTouchEvent result(event_type, ModifiersFromEvent(event),
+ ui::EventTimeStampFromSeconds([event timestamp]));
+ result.hovering = event_type == blink::WebInputEvent::kTouchEnd;
+ result.unique_touch_event_id = ui::GetNextTouchEventId();
+ result.touches_length = 1;
+
+ // Use a temporary WebMouseEvent to get the location.
+ blink::WebMouseEvent temp;
+ SetWebEventLocationFromEventInView(&temp, event, view);
+ result.touches[0].SetPositionInWidget(temp.PositionInWidget());
+ result.touches[0].SetPositionInScreen(temp.PositionInScreen());
+ result.touches[0].movement_x = temp.movement_x;
+ result.touches[0].movement_y = temp.movement_y;
+
+ result.touches[0].state = state;
+ result.touches[0].pointer_type =
+ blink::WebPointerProperties::PointerType::kPen;
+ result.touches[0].id = [event pointingDeviceID];
+ result.touches[0].force = [event pressure];
+ NSPoint tilt = [event tilt];
+ result.touches[0].tilt_x = lround(tilt.x * 90);
+ result.touches[0].tilt_y = lround(tilt.y * 90);
+ result.touches[0].tangential_pressure = [event tangentialPressure];
+ // NSEvent spec doesn't specify the range of rotation, we make sure that
+ // this value is in the range of [0,359].
+ int twist = (int)[event rotation];
+ twist = twist % 360;
+ if (twist < 0)
+ twist += 360;
+ result.touches[0].twist = twist;
+ float rotation_angle = twist % 180;
+ if (rotation_angle > 90)
+ rotation_angle = 180.f - rotation_angle;
+ result.touches[0].rotation_angle = rotation_angle;
+ return result;
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/web_input_event_builders_mac_unittest.mm b/chromium/content/browser/renderer_host/input/web_input_event_builders_mac_unittest.mm
index 2b619cc0a7e..bad84541740 100644
--- a/chromium/content/browser/renderer_host/input/web_input_event_builders_mac_unittest.mm
+++ b/chromium/content/browser/renderer_host/input/web_input_event_builders_mac_unittest.mm
@@ -66,6 +66,31 @@ NSEvent* BuildFakeKeyEvent(NSUInteger key_code,
keyCode:key_code];
}
+#if !defined(MAC_OS_X_VERSION_10_12)
+NSEvent* BuildFakeMouseEvent(CGEventType mouse_type,
+ CGPoint location,
+ CGMouseButton button,
+ CGEventMouseSubtype subtype,
+ float rotation = 0.0,
+ float pressure = 0.0,
+ float tilt_x = 0.0,
+ float tilt_y = 0.0,
+ float tangential_pressure = 0.0) {
+ CGEventRef cg_event =
+ CGEventCreateMouseEvent(NULL, mouse_type, location, button);
+ CGEventSetIntegerValueField(cg_event, kCGMouseEventSubtype, subtype);
+ CGEventSetDoubleValueField(cg_event, kCGTabletEventRotation, rotation);
+ CGEventSetDoubleValueField(cg_event, kCGMouseEventPressure, pressure);
+ CGEventSetDoubleValueField(cg_event, kCGTabletEventTiltX, tilt_x);
+ CGEventSetDoubleValueField(cg_event, kCGTabletEventTiltY, tilt_y);
+ CGEventSetDoubleValueField(cg_event, kCGTabletEventTangentialPressure,
+ tangential_pressure);
+ NSEvent* event = [NSEvent eventWithCGEvent:cg_event];
+ CFRelease(cg_event);
+ return event;
+}
+#endif // MAC_OS_X_VERSION_10_12
+
} // namespace
// Test that arrow keys don't have numpad modifier set.
@@ -647,3 +672,113 @@ TEST(WebInputEventBuilderMacTest, ScrollWheelMatchesUIEvent) {
EXPECT_EQ(web_event.PositionInWidget().y, ui_event.y());
[window close];
}
+
+#if !defined(MAC_OS_X_VERSION_10_12)
+// Test if the value of twist and rotation_angle are set correctly when the
+// NSEvent's rotation is less than 90.
+TEST(WebInputEventBuilderMacTest, TouchEventsWithPointerTypePenRotationLess90) {
+ NSEvent* mac_event =
+ BuildFakeMouseEvent(kCGEventLeftMouseDown, {6, 9}, kCGMouseButtonLeft,
+ kCGEventMouseSubtypeTabletPoint, 60.0);
+ // Create a dummy window, but don't show it. It will be released when closed.
+ NSWindow* window =
+ [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+ blink::WebTouchEvent touch_event =
+ content::WebTouchEventBuilder::Build(mac_event, [window contentView]);
+ EXPECT_EQ(60, touch_event.touches[0].twist);
+ EXPECT_EQ(60, touch_event.touches[0].rotation_angle);
+}
+
+// Test if the value of twist and rotation_angle are set correctly when the
+// NSEvent's rotation is between 90 and 180.
+TEST(WebInputEventBuilderMacTest,
+ TouchEventsWithPointerTypePenRotationLess180) {
+ NSEvent* mac_event =
+ BuildFakeMouseEvent(kCGEventLeftMouseDown, {6, 9}, kCGMouseButtonLeft,
+ kCGEventMouseSubtypeTabletPoint, 160.0);
+ // Create a dummy window, but don't show it. It will be released when closed.
+ NSWindow* window =
+ [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+ blink::WebTouchEvent touch_event =
+ content::WebTouchEventBuilder::Build(mac_event, [window contentView]);
+ EXPECT_EQ(160, touch_event.touches[0].twist);
+ EXPECT_EQ(20, touch_event.touches[0].rotation_angle);
+}
+
+// Test if the value of twist and rotation_angle are set correctly when the
+// NSEvent's rotation is between 180 and 360.
+TEST(WebInputEventBuilderMacTest,
+ TouchEventsWithPointerTypePenRotationLess360) {
+ NSEvent* mac_event =
+ BuildFakeMouseEvent(kCGEventLeftMouseDown, {6, 9}, kCGMouseButtonLeft,
+ kCGEventMouseSubtypeTabletPoint, 260.0);
+ // Create a dummy window, but don't show it. It will be released when closed.
+ NSWindow* window =
+ [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+ blink::WebTouchEvent touch_event =
+ content::WebTouchEventBuilder::Build(mac_event, [window contentView]);
+ EXPECT_EQ(260, touch_event.touches[0].twist);
+ EXPECT_EQ(80, touch_event.touches[0].rotation_angle);
+}
+
+// Test if the value of twist and rotation_angle are set correctly when the
+// NSEvent's rotation is greater than 360.
+TEST(WebInputEventBuilderMacTest,
+ TouchEventsWithPointerTypePenRotationGreater360) {
+ NSEvent* mac_event =
+ BuildFakeMouseEvent(kCGEventLeftMouseDown, {6, 9}, kCGMouseButtonLeft,
+ kCGEventMouseSubtypeTabletPoint, 390.0);
+ // Create a dummy window, but don't show it. It will be released when closed.
+ NSWindow* window =
+ [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+ blink::WebTouchEvent touch_event =
+ content::WebTouchEventBuilder::Build(mac_event, [window contentView]);
+ EXPECT_EQ(30, touch_event.touches[0].twist);
+ EXPECT_EQ(30, touch_event.touches[0].rotation_angle);
+}
+
+// Test if all the values of a WebTouchEvent are set correctly.
+TEST(WebInputEventBuilderMacTest, BuildWebTouchEvents) {
+ NSEvent* mac_event = BuildFakeMouseEvent(
+ kCGEventLeftMouseDown, {6, 9}, kCGMouseButtonLeft,
+ kCGEventMouseSubtypeTabletPoint, /* rotation */ 60.0,
+ /* pressure */ 0.3, /* tilt_x */ 0.5, /* tilt_y */ 0.6,
+ /* tangential_pressure */ 0.7);
+ // Create a dummy window, but don't show it. It will be released when closed.
+ NSWindow* window =
+ [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+ blink::WebTouchEvent touch_event =
+ content::WebTouchEventBuilder::Build(mac_event, [window contentView]);
+ EXPECT_EQ(blink::WebInputEvent::kTouchStart, touch_event.GetType());
+ EXPECT_FALSE(touch_event.hovering);
+ EXPECT_EQ(1U, touch_event.touches_length);
+ EXPECT_EQ(blink::WebFloatPoint(6, 9),
+ touch_event.touches[0].PositionInScreen());
+ EXPECT_EQ(blink::WebTouchPoint::kStatePressed, touch_event.touches[0].state);
+ EXPECT_EQ(blink::WebPointerProperties::PointerType::kPen,
+ touch_event.touches[0].pointer_type);
+ EXPECT_EQ(0, touch_event.touches[0].id);
+ EXPECT_FLOAT_EQ(0.3, std::round(touch_event.touches[0].force * 10) / 10);
+ EXPECT_EQ(0.5 * 90, touch_event.touches[0].tilt_x);
+ EXPECT_EQ(0.6 * 90, touch_event.touches[0].tilt_y);
+ EXPECT_FLOAT_EQ(
+ 0.7, std::round(touch_event.touches[0].tangential_pressure * 10) / 10);
+ EXPECT_EQ(60, touch_event.touches[0].twist);
+ EXPECT_FLOAT_EQ(60.0, touch_event.touches[0].rotation_angle);
+}
+#endif // MAC_OS_X_VERSION_10_12 \ No newline at end of file
diff --git a/chromium/content/browser/renderer_host/input/web_input_event_util_unittest.cc b/chromium/content/browser/renderer_host/input/web_input_event_util_unittest.cc
index 48b6e1e8d3f..ce88a3261db 100644
--- a/chromium/content/browser/renderer_host/input/web_input_event_util_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/web_input_event_util_unittest.cc
@@ -36,6 +36,8 @@ TEST(WebInputEventUtilTest, MotionEventConversion) {
pointer.orientation = -base::kPiFloat / 2;
pointer.tilt_x = 60;
pointer.tilt_y = 70;
+ pointer.twist = 160;
+ pointer.tangential_pressure = 0;
for (MotionEvent::ToolType tool_type : tool_types) {
pointer.tool_type = tool_type;
MotionEventGeneric event(MotionEvent::Action::DOWN, base::TimeTicks::Now(),
@@ -60,6 +62,8 @@ TEST(WebInputEventUtilTest, MotionEventConversion) {
if (tool_type == MotionEvent::ToolType::STYLUS) {
expected_pointer.tilt_x = 60;
expected_pointer.tilt_y = 70;
+ expected_pointer.twist = 160;
+ expected_pointer.tangential_pressure = 0;
} else {
expected_pointer.tilt_x = 0;
expected_pointer.tilt_y = 0;
diff --git a/chromium/content/browser/renderer_host/input/wheel_event_listener_browsertest.cc b/chromium/content/browser/renderer_host/input/wheel_event_listener_browsertest.cc
new file mode 100644
index 00000000000..d72cafc5941
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/wheel_event_listener_browsertest.cc
@@ -0,0 +1,135 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_feature_list.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/common/content_features.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/shell/browser/shell.h"
+#include "third_party/blink/public/platform/web_input_event.h"
+
+using blink::WebInputEvent;
+
+namespace {
+
+const std::string kWheelEventListenerDataURL = R"HTML(
+ <!DOCTYPE html>
+ <meta name='viewport' content='width=device-width'/>
+ <style>
+ html, body {
+ margin: 0;
+ }
+ .spacer { height: 10000px; }
+ </style>
+ <div class=spacer></div>
+ <script>
+ window.addEventListener('wheel', () => { while (true); });
+ document.title='ready';
+ </script>)HTML";
+
+const std::string kMouseWheelEventListenerDataURL = R"HTML(
+ <!DOCTYPE html>
+ <meta name='viewport' content='width=device-width'/>
+ <style>
+ html, body {
+ margin: 0;
+ }
+ .spacer { height: 10000px; }
+ </style>
+ <div class=spacer></div>
+ <script>
+ document.addEventListener('mousewheel', () => { while (true); });
+ document.title='ready';
+ </script>)HTML";
+} // namespace
+
+namespace content {
+
+class WheelEventListenerBrowserTest : public ContentBrowserTest {
+ public:
+ WheelEventListenerBrowserTest() {
+ feature_list_.InitWithFeatures(
+ {features::kPassiveDocumentWheelEventListeners}, {});
+ }
+ ~WheelEventListenerBrowserTest() override {}
+
+ protected:
+ RenderWidgetHostImpl* GetWidgetHost() {
+ return RenderWidgetHostImpl::From(
+ shell()->web_contents()->GetRenderViewHost()->GetWidget());
+ }
+
+ void LoadURL(const std::string& page_data) {
+ const GURL data_url("data:text/html," + page_data);
+ NavigateToURL(shell(), data_url);
+
+ RenderWidgetHostImpl* host = GetWidgetHost();
+ host->GetView()->SetSize(gfx::Size(400, 400));
+
+ base::string16 ready_title(base::ASCIIToUTF16("ready"));
+ TitleWatcher watcher(shell()->web_contents(), ready_title);
+ ignore_result(watcher.WaitAndGetTitle());
+
+ MainThreadFrameObserver main_thread_sync(host);
+ main_thread_sync.Wait();
+ }
+
+ void ScrollByMouseWheel() {
+ // Send a wheel event and wait for its ack.
+ auto wheel_msg_watcher = std::make_unique<InputMsgWatcher>(
+ GetWidgetHost(), blink::WebInputEvent::kMouseWheel);
+ double x = 10;
+ double y = 10;
+ blink::WebMouseWheelEvent wheel_event =
+ SyntheticWebMouseWheelEventBuilder::Build(x, y, x, y, -20, -20, 0,
+ true);
+ wheel_event.phase = blink::WebMouseWheelEvent::kPhaseBegan;
+ GetWidgetHost()->ForwardWheelEvent(wheel_event);
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING,
+ wheel_msg_watcher->WaitForAck());
+ }
+
+ void WaitForScroll() {
+ RenderFrameSubmissionObserver observer(
+ GetWidgetHost()->render_frame_metadata_provider());
+ gfx::Vector2dF default_scroll_offset;
+ while (observer.LastRenderFrameMetadata()
+ .root_scroll_offset.value_or(default_scroll_offset)
+ .y() <= 0) {
+ observer.WaitForMetadataChange();
+ }
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+ DISALLOW_COPY_AND_ASSIGN(WheelEventListenerBrowserTest);
+};
+
+IN_PROC_BROWSER_TEST_F(WheelEventListenerBrowserTest,
+ DocumentWheelEventListenersPassiveByDefault) {
+ LoadURL(kWheelEventListenerDataURL);
+
+ // Send a wheel event and wait for its ack.
+ ScrollByMouseWheel();
+
+ // Wait for the page to scroll, the test will timeout if the wheel event
+ // listener added to window is not treated as passive.
+ WaitForScroll();
+}
+
+IN_PROC_BROWSER_TEST_F(WheelEventListenerBrowserTest,
+ DocumentMouseWheelEventListenersPassiveByDefault) {
+ LoadURL(kMouseWheelEventListenerDataURL);
+
+ // Send a wheel event and wait for its ack.
+ ScrollByMouseWheel();
+
+ // Wait for the page to scroll, the test will timeout if the mousewheel event
+ // listener added to document is not treated as passive.
+ WaitForScroll();
+}
+
+} // namespace content \ No newline at end of file
diff --git a/chromium/content/browser/renderer_host/legacy_render_widget_host_win.cc b/chromium/content/browser/renderer_host/legacy_render_widget_host_win.cc
index 71f08b4a2bc..f80b0a6e812 100644
--- a/chromium/content/browser/renderer_host/legacy_render_widget_host_win.cc
+++ b/chromium/content/browser/renderer_host/legacy_render_widget_host_win.cc
@@ -139,11 +139,6 @@ void LegacyRenderWidgetHostHWND::SetBounds(const gfx::Rect& bounds) {
direct_manipulation_helper_->SetSize(bounds_in_pixel.size());
}
-void LegacyRenderWidgetHostHWND::MoveCaretTo(const gfx::Rect& bounds) {
- DCHECK(ax_system_caret_);
- ax_system_caret_->MoveCaretTo(bounds);
-}
-
void LegacyRenderWidgetHostHWND::OnFinalMessage(HWND hwnd) {
if (host_) {
host_->OnLegacyWindowDestroyed();
@@ -182,7 +177,7 @@ bool LegacyRenderWidgetHostHWND::Init() {
DCHECK(SUCCEEDED(hr));
ui::AXMode mode =
- BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode();
+ BrowserAccessibilityStateImpl::GetInstance()->GetAccessibilityMode();
if (!mode.has_mode(ui::AXMode::kNativeAPIs)) {
// Attempt to detect screen readers or other clients who want full
// accessibility support, by seeing if they respond to this event.
diff --git a/chromium/content/browser/renderer_host/legacy_render_widget_host_win.h b/chromium/content/browser/renderer_host/legacy_render_widget_host_win.h
index 79bad955ddc..1e154cbc424 100644
--- a/chromium/content/browser/renderer_host/legacy_render_widget_host_win.h
+++ b/chromium/content/browser/renderer_host/legacy_render_widget_host_win.h
@@ -5,15 +5,14 @@
#ifndef CONTENT_BROWSER_RENDERER_HOST_LEGACY_RENDER_WIDGET_HOST_WIN_H_
#define CONTENT_BROWSER_RENDERER_HOST_LEGACY_RENDER_WIDGET_HOST_WIN_H_
-#include <atlbase.h>
#include <atlcrack.h>
-#include <atlwin.h>
#include <oleacc.h>
#include <wrl/client.h>
#include <memory>
#include "base/macros.h"
+#include "base/win/atl.h"
#include "content/common/content_export.h"
#include "ui/compositor/compositor_animation_observer.h"
#include "ui/gfx/geometry/rect.h"
@@ -124,9 +123,6 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND
host_ = host;
}
- // Changes the position of the system caret used for accessibility.
- void MoveCaretTo(const gfx::Rect& bounds);
-
// DirectManipulation needs to poll for new events every frame while finger
// gesturing on touchpad.
void PollForNextEvent();
diff --git a/chromium/content/browser/renderer_host/media/audio_input_delegate_impl.cc b/chromium/content/browser/renderer_host/media/audio_input_delegate_impl.cc
index d01a24bd4bf..718bb1a6e5a 100644
--- a/chromium/content/browser/renderer_host/media/audio_input_delegate_impl.cc
+++ b/chromium/content/browser/renderer_host/media/audio_input_delegate_impl.cc
@@ -192,9 +192,9 @@ AudioInputDelegateImpl::AudioInputDelegateImpl(
const std::string& device_id = device->id;
if (WebContentsMediaCaptureId::Parse(device_id, nullptr)) {
- // For MEDIA_DESKTOP_AUDIO_CAPTURE, the source is selected from picker
- // window, we do not mute the source audio.
- // For MEDIA_TAB_AUDIO_CAPTURE, the probable use case is Cast, we mute
+ // For MEDIA_GUM_DESKTOP_AUDIO_CAPTURE, the source is selected from
+ // picker window, we do not mute the source audio. For
+ // MEDIA_GUM_TAB_AUDIO_CAPTURE, the probable use case is Cast, we mute
// the source audio.
// TODO(qiangchen): Analyze audio constraints to make a duplicating or
// diverting decision. It would give web developer more flexibility.
@@ -206,7 +206,7 @@ AudioInputDelegateImpl::AudioInputDelegateImpl(
writer_.get(), user_input_monitor);
DCHECK(controller_);
// Only count for captures from desktop media picker dialog.
- if (device->type == MEDIA_DESKTOP_AUDIO_CAPTURE)
+ if (device->type == MEDIA_GUM_DESKTOP_AUDIO_CAPTURE)
IncrementDesktopCaptureCounter(TAB_AUDIO_CAPTURER_CREATED);
} else {
controller_ = media::AudioInputController::Create(
@@ -216,7 +216,7 @@ AudioInputDelegateImpl::AudioInputDelegateImpl(
// Only count for captures from desktop media picker dialog and system loop
// back audio.
- if (device->type == MEDIA_DESKTOP_AUDIO_CAPTURE &&
+ if (device->type == MEDIA_GUM_DESKTOP_AUDIO_CAPTURE &&
(media::AudioDeviceDescription::IsLoopbackDevice(device_id))) {
IncrementDesktopCaptureCounter(SYSTEM_LOOPBACK_AUDIO_CAPTURER_CREATED);
}
diff --git a/chromium/content/browser/renderer_host/media/audio_input_device_manager.cc b/chromium/content/browser/renderer_host/media/audio_input_device_manager.cc
index db018e66062..2e72505f818 100644
--- a/chromium/content/browser/renderer_host/media/audio_input_device_manager.cc
+++ b/chromium/content/browser/renderer_host/media/audio_input_device_manager.cc
@@ -94,7 +94,7 @@ int AudioInputDeviceManager::Open(const MediaStreamDevice& device) {
base::Optional<media::AudioParameters>()));
} else {
// TODO(tommi): As is, we hit this code path when device.type is
- // MEDIA_TAB_AUDIO_CAPTURE and the device id is not a device that
+ // MEDIA_GUM_TAB_AUDIO_CAPTURE and the device id is not a device that
// the AudioManager can know about. This currently does not fail because
// the implementation of GetInputStreamParameters returns valid parameters
// by default for invalid devices. That behavior is problematic because it
diff --git a/chromium/content/browser/renderer_host/media/audio_input_device_manager.h b/chromium/content/browser/renderer_host/media/audio_input_device_manager.h
index b22666bf9af..2f20d07aebc 100644
--- a/chromium/content/browser/renderer_host/media/audio_input_device_manager.h
+++ b/chromium/content/browser/renderer_host/media/audio_input_device_manager.h
@@ -111,7 +111,7 @@ class CONTENT_EXPORT AudioInputDeviceManager : public MediaStreamProvider {
MediaStreamDevices::iterator GetDevice(int session_id);
// Only accessed on Browser::IO thread.
- base::ObserverList<MediaStreamProviderListener> listeners_;
+ base::ObserverList<MediaStreamProviderListener>::Unchecked listeners_;
int next_capture_session_id_;
MediaStreamDevices devices_;
diff --git a/chromium/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc b/chromium/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc
index ffac149e26c..499484ab8b7 100644
--- a/chromium/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc
@@ -50,7 +50,8 @@ class MockAudioInputDeviceManagerListener
// TODO(henrika): there are special restrictions for Android since
// AudioInputDeviceManager::Open() must be called on the audio thread.
// This test suite must be modified to run on Android.
-#if defined(OS_ANDROID)
+// Flaky on Linux. See http://crbug.com/867397.
+#if defined(OS_ANDROID) || defined(OS_LINUX)
#define MAYBE_AudioInputDeviceManagerTest DISABLED_AudioInputDeviceManagerTest
#else
#define MAYBE_AudioInputDeviceManagerTest AudioInputDeviceManagerTest
@@ -311,9 +312,9 @@ class AudioInputDeviceManagerNoDevicesTest
std::make_unique<media::AudioThreadImpl>());
// Devices to request from AudioInputDeviceManager.
- devices_.emplace_back(MEDIA_TAB_AUDIO_CAPTURE, "tab_capture",
+ devices_.emplace_back(MEDIA_GUM_TAB_AUDIO_CAPTURE, "tab_capture",
"Tab capture");
- devices_.emplace_back(MEDIA_DESKTOP_AUDIO_CAPTURE, "desktop_capture",
+ devices_.emplace_back(MEDIA_GUM_DESKTOP_AUDIO_CAPTURE, "desktop_capture",
"Desktop capture");
devices_.emplace_back(MEDIA_DEVICE_AUDIO_CAPTURE, "fake_device",
"Fake Device");
diff --git a/chromium/content/browser/renderer_host/media/audio_output_authorization_handler.cc b/chromium/content/browser/renderer_host/media/audio_output_authorization_handler.cc
index 239c8be2a1e..5d888b45bed 100644
--- a/chromium/content/browser/renderer_host/media/audio_output_authorization_handler.cc
+++ b/chromium/content/browser/renderer_host/media/audio_output_authorization_handler.cc
@@ -254,8 +254,8 @@ void AudioOutputAuthorizationHandler::AccessChecked(
media_stream_manager_->media_devices_manager()->EnumerateDevices(
devices_to_enumerate,
base::BindOnce(&AudioOutputAuthorizationHandler::TranslateDeviceID,
- weak_factory_.GetWeakPtr(), base::Passed(&trace_scope),
- base::Passed(&cb), device_id, std::move(salt),
+ weak_factory_.GetWeakPtr(), std::move(trace_scope),
+ std::move(cb), device_id, std::move(salt),
std::move(security_origin)));
}
diff --git a/chromium/content/browser/renderer_host/media/audio_output_authorization_handler_unittest.cc b/chromium/content/browser/renderer_host/media/audio_output_authorization_handler_unittest.cc
index 5a72602b62c..15a70a66df8 100644
--- a/chromium/content/browser/renderer_host/media/audio_output_authorization_handler_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/audio_output_authorization_handler_unittest.cc
@@ -167,7 +167,7 @@ class AudioOutputAuthorizationHandlerTest : public RenderViewHostTestHarness {
media_stream_manager_->media_devices_manager()->EnumerateDevices(
devices_to_enumerate,
- base::Bind(
+ base::BindOnce(
[](std::string* out, const MediaDeviceEnumeration& result) {
// Index 0 is default, so use 1.
CHECK(result[MediaDeviceType::MEDIA_DEVICE_TYPE_AUDIO_OUTPUT]
diff --git a/chromium/content/browser/renderer_host/media/audio_output_delegate_impl_unittest.cc b/chromium/content/browser/renderer_host/media/audio_output_delegate_impl_unittest.cc
index 62a7132a451..ac462bdb117 100644
--- a/chromium/content/browser/renderer_host/media/audio_output_delegate_impl_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/audio_output_delegate_impl_unittest.cc
@@ -129,6 +129,7 @@ class DummyMojoAudioLogImpl : public media::mojom::AudioLog {
void OnClosed() override {}
void OnError() override {}
void OnSetVolume(double volume) override {}
+ void OnProcessingStateChanged(const std::string& message) override {}
void OnLogMessage(const std::string& message) override {}
};
diff --git a/chromium/content/browser/renderer_host/media/audio_service_listener.cc b/chromium/content/browser/renderer_host/media/audio_service_listener.cc
index a97377898da..2a7a25a0255 100644
--- a/chromium/content/browser/renderer_host/media/audio_service_listener.cc
+++ b/chromium/content/browser/renderer_host/media/audio_service_listener.cc
@@ -182,7 +182,7 @@ void AudioServiceListener::OnServiceStopped(
void AudioServiceListener::BrowserChildProcessHostDisconnected(
const ChildProcessData& data) {
DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
- if (base::GetProcId(data.handle) != process_id_)
+ if (base::GetProcId(data.GetHandle()) != process_id_)
return;
process_id_ = base::kNullProcessId;
metrics_.ServiceProcessTerminated(
@@ -193,7 +193,7 @@ void AudioServiceListener::BrowserChildProcessCrashed(
const ChildProcessData& data,
const ChildProcessTerminationInfo& info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
- if (base::GetProcId(data.handle) != process_id_)
+ if (base::GetProcId(data.GetHandle()) != process_id_)
return;
process_id_ = base::kNullProcessId;
metrics_.ServiceProcessTerminated(
@@ -204,7 +204,7 @@ void AudioServiceListener::BrowserChildProcessKilled(
const ChildProcessData& data,
const ChildProcessTerminationInfo& info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
- if (base::GetProcId(data.handle) != process_id_)
+ if (base::GetProcId(data.GetHandle()) != process_id_)
return;
process_id_ = base::kNullProcessId;
metrics_.ServiceProcessTerminated(
diff --git a/chromium/content/browser/renderer_host/media/audio_service_listener_unittest.cc b/chromium/content/browser/renderer_host/media/audio_service_listener_unittest.cc
index d6a66a9d5b4..d43d2541a02 100644
--- a/chromium/content/browser/renderer_host/media/audio_service_listener_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/audio_service_listener_unittest.cc
@@ -194,7 +194,7 @@ TEST(AudioServiceListenerTest,
MakeTestServiceInfo(audio_service_identity, pid));
audio_service_listener.OnServiceStarted(audio_service_identity, pid);
ChildProcessData data(content::ProcessType::PROCESS_TYPE_UTILITY);
- data.handle = handle;
+ data.SetHandle(handle);
audio_service_listener.BrowserChildProcessHostDisconnected(data);
histogram_tester.ExpectUniqueSample(
"Media.AudioService.ObservedProcessTerminationStatus",
@@ -215,7 +215,7 @@ TEST(AudioServiceListenerTest,
MakeTestServiceInfo(audio_service_identity, pid));
audio_service_listener.OnServiceStarted(audio_service_identity, pid);
ChildProcessData data(content::ProcessType::PROCESS_TYPE_UTILITY);
- data.handle = handle;
+ data.SetHandle(handle);
audio_service_listener.BrowserChildProcessCrashed(
data, content::ChildProcessTerminationInfo());
histogram_tester.ExpectUniqueSample(
@@ -236,7 +236,7 @@ TEST(AudioServiceListenerTest,
MakeTestServiceInfo(audio_service_identity, pid));
audio_service_listener.OnServiceStarted(audio_service_identity, pid);
ChildProcessData data(content::ProcessType::PROCESS_TYPE_UTILITY);
- data.handle = handle;
+ data.SetHandle(handle);
audio_service_listener.BrowserChildProcessKilled(
data, content::ChildProcessTerminationInfo());
histogram_tester.ExpectUniqueSample(
diff --git a/chromium/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc b/chromium/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
index 77742e8cd19..ffa3e8c0062 100644
--- a/chromium/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
+++ b/chromium/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
@@ -4,6 +4,10 @@
#include "content/browser/renderer_host/media/in_process_video_capture_device_launcher.h"
+#include <utility>
+#include <vector>
+
+#include "base/command_line.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
@@ -11,8 +15,12 @@
#include "content/browser/renderer_host/media/video_capture_controller.h"
#include "content/browser/renderer_host/media/video_capture_dependencies.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/desktop_media_id.h"
#include "content/public/common/media_stream_request.h"
#include "media/base/bind_to_current_loop.h"
+#include "media/base/media_switches.h"
+#include "media/capture/video/fake_video_capture_device.h"
+#include "media/capture/video/fake_video_capture_device_factory.h"
#include "media/capture/video/video_capture_buffer_pool_impl.h"
#include "media/capture/video/video_capture_buffer_tracker_factory_impl.h"
#include "media/capture/video/video_capture_device_client.h"
@@ -22,7 +30,6 @@
#if defined(ENABLE_SCREEN_CAPTURE)
#include "content/browser/media/capture/desktop_capture_device_uma_types.h"
-#include "content/public/browser/desktop_media_id.h"
#if defined(OS_ANDROID)
#include "content/browser/media/capture/screen_capture_device_android.h"
#else
@@ -123,7 +130,7 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync(
#if defined(ENABLE_SCREEN_CAPTURE)
#if !defined(OS_ANDROID)
- case MEDIA_TAB_VIDEO_CAPTURE:
+ case MEDIA_GUM_TAB_VIDEO_CAPTURE:
start_capture_closure = base::BindOnce(
&InProcessVideoCaptureDeviceLauncher::DoStartTabCaptureOnDeviceThread,
base::Unretained(this), device_id, params, std::move(receiver),
@@ -131,7 +138,9 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync(
break;
#endif // !defined(OS_ANDROID)
- case MEDIA_DESKTOP_VIDEO_CAPTURE: {
+ case MEDIA_GUM_DESKTOP_VIDEO_CAPTURE:
+ FALLTHROUGH;
+ case MEDIA_DISPLAY_VIDEO_CAPTURE: {
const DesktopMediaID desktop_id = DesktopMediaID::Parse(device_id);
if (desktop_id.is_null()) {
DLOG(ERROR) << "Desktop media ID is null";
@@ -140,6 +149,18 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync(
break;
}
+ if (desktop_id.id == DesktopMediaID::kFakeId) {
+ start_capture_closure = base::BindOnce(
+ &InProcessVideoCaptureDeviceLauncher::
+ DoStartFakeDisplayCaptureOnDeviceThread,
+ base::Unretained(this), desktop_id, params,
+ CreateDeviceClient(media::VideoCaptureBufferType::kSharedMemory,
+ kMaxNumberOfBuffers, std::move(receiver),
+ std::move(receiver_on_io_thread)),
+ std::move(after_start_capture_callback));
+ break;
+ }
+
#if !defined(OS_ANDROID)
if (desktop_id.type == DesktopMediaID::TYPE_WEB_CONTENTS) {
after_start_capture_callback = base::BindOnce(
@@ -240,7 +261,9 @@ void InProcessVideoCaptureDeviceLauncher::OnDeviceStarted(
if (!device) {
switch (state_copy) {
case State::DEVICE_START_IN_PROGRESS:
- callbacks->OnDeviceLaunchFailed();
+ callbacks->OnDeviceLaunchFailed(
+ media::VideoCaptureError::
+ kInProcessDeviceLauncherFailedToCreateDeviceInstance);
base::ResetAndReturn(&done_cb).Run();
return;
case State::DEVICE_START_ABORTING:
@@ -369,4 +392,40 @@ void InProcessVideoCaptureDeviceLauncher::DoStartDesktopCaptureOnDeviceThread(
#endif // defined(ENABLE_SCREEN_CAPTURE)
+void InProcessVideoCaptureDeviceLauncher::
+ DoStartFakeDisplayCaptureOnDeviceThread(
+ const DesktopMediaID& desktop_id,
+ const media::VideoCaptureParams& params,
+ std::unique_ptr<media::VideoCaptureDeviceClient> device_client,
+ ReceiveDeviceCallback result_callback) {
+ DCHECK(device_task_runner_->BelongsToCurrentThread());
+ DCHECK_EQ(DesktopMediaID::kFakeId, desktop_id.id);
+
+ auto fake_device_factory =
+ std::make_unique<media::FakeVideoCaptureDeviceFactory>();
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ if (command_line &&
+ command_line->HasSwitch(switches::kUseFakeDeviceForMediaStream)) {
+ std::vector<media::FakeVideoCaptureDeviceSettings> config;
+ media::FakeVideoCaptureDeviceFactory::
+ ParseFakeDevicesConfigFromOptionsString(
+ command_line->GetSwitchValueASCII(
+ switches::kUseFakeDeviceForMediaStream),
+ &config);
+ fake_device_factory->SetToCustomDevicesConfig(config);
+ }
+ media::VideoCaptureDeviceDescriptors device_descriptors;
+ fake_device_factory->GetDeviceDescriptors(&device_descriptors);
+ if (device_descriptors.empty()) {
+ LOG(ERROR) << "Cannot start with no fake device config";
+ std::move(result_callback).Run(nullptr);
+ return;
+ }
+ auto video_capture_device =
+ fake_device_factory->CreateDevice(device_descriptors.front());
+ video_capture_device->AllocateAndStart(params, std::move(device_client));
+ std::move(result_callback).Run(std::move(video_capture_device));
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/media/in_process_video_capture_device_launcher.h b/chromium/content/browser/renderer_host/media/in_process_video_capture_device_launcher.h
index ce862c58484..67c77f9a050 100644
--- a/chromium/content/browser/renderer_host/media/in_process_video_capture_device_launcher.h
+++ b/chromium/content/browser/renderer_host/media/in_process_video_capture_device_launcher.h
@@ -5,6 +5,9 @@
#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_IN_PROCESS_VIDEO_CAPTURE_DEVICE_LAUNCHER_H_
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_IN_PROCESS_VIDEO_CAPTURE_DEVICE_LAUNCHER_H_
+#include <memory>
+#include <string>
+
#include "base/single_thread_task_runner.h"
#include "content/browser/renderer_host/media/video_capture_controller.h"
#include "content/browser/renderer_host/media/video_capture_provider.h"
@@ -84,6 +87,12 @@ class InProcessVideoCaptureDeviceLauncher : public VideoCaptureDeviceLauncher {
std::unique_ptr<media::VideoCaptureDeviceClient> client,
ReceiveDeviceCallback result_callback);
+ void DoStartFakeDisplayCaptureOnDeviceThread(
+ const DesktopMediaID& desktop_id,
+ const media::VideoCaptureParams& params,
+ std::unique_ptr<media::VideoCaptureDeviceClient> client,
+ ReceiveDeviceCallback result_callback);
+
const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_;
media::VideoCaptureSystem* const video_capture_system_;
State state_;
diff --git a/chromium/content/browser/renderer_host/media/media_devices_dispatcher_host.cc b/chromium/content/browser/renderer_host/media/media_devices_dispatcher_host.cc
index c87ff868818..1812e217cec 100644
--- a/chromium/content/browser/renderer_host/media/media_devices_dispatcher_host.cc
+++ b/chromium/content/browser/renderer_host/media/media_devices_dispatcher_host.cc
@@ -207,7 +207,7 @@ void MediaDevicesDispatcherHost::GotDefaultVideoInputDeviceID(
requested_types,
base::BindOnce(
&MediaDevicesDispatcherHost::FinalizeGetVideoInputCapabilities,
- weak_factory_.GetWeakPtr(), base::Passed(&client_callback),
+ weak_factory_.GetWeakPtr(), std::move(client_callback),
std::move(salt_and_origin), std::move(default_device_id)));
}
diff --git a/chromium/content/browser/renderer_host/media/media_devices_dispatcher_host_unittest.cc b/chromium/content/browser/renderer_host/media/media_devices_dispatcher_host_unittest.cc
index 228ef4575cb..1d705047016 100644
--- a/chromium/content/browser/renderer_host/media/media_devices_dispatcher_host_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/media_devices_dispatcher_host_unittest.cc
@@ -149,8 +149,8 @@ class MediaDevicesDispatcherHostTest : public testing::TestWithParam<GURL> {
devices_to_enumerate[MEDIA_DEVICE_TYPE_AUDIO_OUTPUT] = true;
media_stream_manager_->media_devices_manager()->EnumerateDevices(
devices_to_enumerate,
- base::Bind(&PhysicalDevicesEnumerated, run_loop.QuitClosure(),
- &physical_devices_));
+ base::BindOnce(&PhysicalDevicesEnumerated, run_loop.QuitClosure(),
+ &physical_devices_));
run_loop.Run();
ASSERT_GT(physical_devices_[MEDIA_DEVICE_TYPE_AUDIO_INPUT].size(), 0u);
diff --git a/chromium/content/browser/renderer_host/media/media_devices_manager.cc b/chromium/content/browser/renderer_host/media/media_devices_manager.cc
index c9fcb5e765b..307115c6d57 100644
--- a/chromium/content/browser/renderer_host/media/media_devices_manager.cc
+++ b/chromium/content/browser/renderer_host/media/media_devices_manager.cc
@@ -666,7 +666,7 @@ void MediaDevicesManager::OnPermissionsCheckDone(
internal_requested_types,
base::BindOnce(&MediaDevicesManager::OnDevicesEnumerated,
weak_factory_.GetWeakPtr(), requested_types,
- request_video_input_capabilities, base::Passed(&callback),
+ request_video_input_capabilities, std::move(callback),
std::move(salt_and_origin), has_permissions));
}
@@ -693,7 +693,7 @@ void MediaDevicesManager::OnDevicesEnumerated(
}
}
- std::move(callback).Run(std::move(result),
+ std::move(callback).Run(result,
video_input_capabilities_requested
? ComputeVideoInputCapabilities(
enumeration[MEDIA_DEVICE_TYPE_VIDEO_INPUT],
@@ -829,7 +829,10 @@ void MediaDevicesManager::UpdateSnapshot(
if (old_snapshot.size() != new_snapshot.size() ||
!std::equal(new_snapshot.begin(), new_snapshot.end(),
old_snapshot.begin(),
- ignore_group_id ? operator== : EqualDeviceAndGroupID)) {
+ ignore_group_id
+ ? [](const MediaDeviceInfo& lhs,
+ const MediaDeviceInfo& rhs) { return lhs == rhs; }
+ : EqualDeviceAndGroupID)) {
// Prevent sending notifications until group IDs are updated using
// a heuristic in ProcessRequests().
// TODO(crbug.com/627793): Remove |is_video_with_group_ids| and the
diff --git a/chromium/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc b/chromium/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
index 688ce189a4a..a1cd9c20c51 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
@@ -185,7 +185,7 @@ class MockMediaStreamDispatcherHost : public MediaStreamDispatcherHost,
void OnDeviceStoppedInternal(const std::string& label,
const MediaStreamDevice& device) {
- if (IsVideoMediaType(device.type))
+ if (IsVideoInputMediaType(device.type))
EXPECT_TRUE(device.IsSameDevice(video_devices_[0]));
if (IsAudioInputMediaType(device.type))
EXPECT_TRUE(device.IsSameDevice(audio_devices_[0]));
@@ -298,8 +298,8 @@ class MediaStreamDispatcherHostTest : public testing::Test {
devices_to_enumerate[MEDIA_DEVICE_TYPE_AUDIO_INPUT] = true;
media_stream_manager_->media_devices_manager()->EnumerateDevices(
devices_to_enumerate,
- base::Bind(&AudioInputDevicesEnumerated, run_loop.QuitClosure(),
- &audio_device_descriptions_));
+ base::BindOnce(&AudioInputDevicesEnumerated, run_loop.QuitClosure(),
+ &audio_device_descriptions_));
run_loop.Run();
ASSERT_GT(audio_device_descriptions_.size(), 0u);
diff --git a/chromium/content/browser/renderer_host/media/media_stream_manager.cc b/chromium/content/browser/renderer_host/media/media_stream_manager.cc
index 71f785312be..a154e72ac00 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/chromium/content/browser/renderer_host/media/media_stream_manager.cc
@@ -10,6 +10,7 @@
#include <algorithm>
#include <cctype>
#include <list>
+#include <vector>
#include "base/bind.h"
#include "base/command_line.h"
@@ -27,7 +28,6 @@
#include "base/threading/thread_local.h"
#include "build/build_config.h"
#include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
#include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/renderer_host/media/audio_input_device_manager.h"
#include "content/browser/renderer_host/media/audio_service_listener.h"
@@ -43,6 +43,7 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/desktop_media_id.h"
+#include "content/public/browser/desktop_streams_registry.h"
#include "content/public/browser/media_observer.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents_media_capture_id.h"
@@ -56,6 +57,8 @@
#include "media/base/channel_layout.h"
#include "media/base/media_switches.h"
#include "media/capture/video/create_video_capture_device_factory.h"
+#include "media/capture/video/fake_video_capture_device.h"
+#include "media/capture/video/fake_video_capture_device_factory.h"
#include "media/capture/video/video_capture_system_impl.h"
#include "services/video_capture/public/uma/video_capture_service_event.h"
#include "url/gurl.h"
@@ -67,6 +70,7 @@
#if defined(OS_CHROMEOS)
#include "chromeos/audio/cras_audio_handler.h"
+#include "content/browser/gpu/gpu_memory_buffer_manager_singleton.h"
#include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h"
#include "media/capture/video/chromeos/public/cros_features.h"
#include "media/capture/video/chromeos/video_capture_device_factory_chromeos.h"
@@ -100,47 +104,6 @@ std::string RandomLabel() {
return label;
}
-void ParseStreamType(const StreamControls& controls,
- MediaStreamType* audio_type,
- MediaStreamType* video_type) {
- *audio_type = MEDIA_NO_SERVICE;
- *video_type = MEDIA_NO_SERVICE;
- const bool audio_support_flag_for_desktop_share =
- !base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableAudioSupportForDesktopShare);
- if (controls.audio.requested) {
- if (!controls.audio.stream_source.empty()) {
- // This is tab or screen capture.
- if (controls.audio.stream_source == kMediaStreamSourceTab) {
- *audio_type = MEDIA_TAB_AUDIO_CAPTURE;
- } else if (controls.audio.stream_source == kMediaStreamSourceSystem) {
- *audio_type = MEDIA_DESKTOP_AUDIO_CAPTURE;
- } else if (audio_support_flag_for_desktop_share &&
- controls.audio.stream_source == kMediaStreamSourceDesktop) {
- *audio_type = MEDIA_DESKTOP_AUDIO_CAPTURE;
- }
- } else {
- // This is normal audio device capture.
- *audio_type = MEDIA_DEVICE_AUDIO_CAPTURE;
- }
- }
- if (controls.video.requested) {
- if (!controls.video.stream_source.empty()) {
- // This is tab or screen capture.
- if (controls.video.stream_source == kMediaStreamSourceTab) {
- *video_type = MEDIA_TAB_VIDEO_CAPTURE;
- } else if (controls.video.stream_source == kMediaStreamSourceScreen) {
- *video_type = MEDIA_DESKTOP_VIDEO_CAPTURE;
- } else if (controls.video.stream_source == kMediaStreamSourceDesktop) {
- *video_type = MEDIA_DESKTOP_VIDEO_CAPTURE;
- }
- } else {
- // This is normal video device capture.
- *video_type = MEDIA_DEVICE_VIDEO_CAPTURE;
- }
- }
-}
-
// Turns off available audio effects (removes the flag) if the options
// explicitly turn them off.
void FilterAudioEffects(const StreamControls& controls, int* effects) {
@@ -216,6 +179,59 @@ void SendVideoCaptureLogMessage(const std::string& message) {
MediaStreamManager::SendMessageToNativeLog("video capture: " + message);
}
+MediaStreamType AdjustAudioStreamTypeBasedOnCommandLineSwitches(
+ MediaStreamType stream_type) {
+ if (stream_type != MEDIA_GUM_DESKTOP_AUDIO_CAPTURE)
+ return stream_type;
+ const bool audio_support_flag_for_desktop_share =
+ !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableAudioSupportForDesktopShare);
+ return audio_support_flag_for_desktop_share ? MEDIA_GUM_DESKTOP_AUDIO_CAPTURE
+ : MEDIA_NO_SERVICE;
+}
+
+// Returns DesktopMediaID with fake initializers if
+// |kUseFakeDeviceForMediaStream| is set. Returns the default DesktopMediaID
+// otherwise.
+DesktopMediaID FindDesktopMediaIDFromFakeDeviceConfig() {
+ // TODO(emircan): When getDisplayMedia() accepts constraints, pick
+ // the corresponding type.
+ DesktopMediaID media_id =
+ DesktopMediaID(DesktopMediaID::TYPE_SCREEN, DesktopMediaID::kNullId);
+
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ if (command_line &&
+ command_line->HasSwitch(switches::kUseFakeDeviceForMediaStream)) {
+ std::vector<media::FakeVideoCaptureDeviceSettings> config;
+ media::FakeVideoCaptureDeviceFactory::
+ ParseFakeDevicesConfigFromOptionsString(
+ command_line->GetSwitchValueASCII(
+ switches::kUseFakeDeviceForMediaStream),
+ &config);
+ if (config.empty())
+ return media_id;
+
+ DesktopMediaID::Type desktop_media_type = DesktopMediaID::TYPE_NONE;
+ switch (config[0].display_media_type) {
+ case media::FakeVideoCaptureDevice::DisplayMediaType::ANY:
+ desktop_media_type = DesktopMediaID::TYPE_SCREEN;
+ break;
+ case media::FakeVideoCaptureDevice::DisplayMediaType::MONITOR:
+ desktop_media_type = DesktopMediaID::TYPE_SCREEN;
+ break;
+ case media::FakeVideoCaptureDevice::DisplayMediaType::WINDOW:
+ desktop_media_type = DesktopMediaID::TYPE_WINDOW;
+ break;
+ case media::FakeVideoCaptureDevice::DisplayMediaType::BROWSER:
+ desktop_media_type = DesktopMediaID::TYPE_WEB_CONTENTS;
+ break;
+ }
+ media_id = DesktopMediaID(desktop_media_type, DesktopMediaID::kFakeId);
+ }
+ return media_id;
+}
+
} // namespace
// MediaStreamManager::DeviceRequest represents a request to either enumerate
@@ -259,7 +275,7 @@ class MediaStreamManager::DeviceRequest {
MediaStreamType audio_type() const { return audio_type_; }
void SetVideoType(MediaStreamType video_type) {
- DCHECK(IsVideoMediaType(video_type) || video_type == MEDIA_NO_SERVICE);
+ DCHECK(IsVideoInputMediaType(video_type) || video_type == MEDIA_NO_SERVICE);
video_type_ = video_type;
}
@@ -466,7 +482,7 @@ MediaStreamManager::MediaStreamManager(
#if defined(OS_CHROMEOS)
if (media::ShouldUseCrosCameraService()) {
media::VideoCaptureDeviceFactoryChromeOS::SetGpuBufferManager(
- BrowserGpuMemoryBufferManager::current());
+ GpuMemoryBufferManagerSingleton::GetInstance());
media::CameraHalDispatcherImpl::GetInstance()->Start(
base::BindRepeating(
&VideoCaptureDependencies::CreateJpegDecodeAccelerator),
@@ -588,7 +604,7 @@ std::string MediaStreamManager::MakeMediaAccessRequest(
// MediaStreamManager is deleted on the UI thread, after the IO thread has
// been stopped.
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
- base::BindOnce(&MediaStreamManager::SetupRequest,
+ base::BindOnce(&MediaStreamManager::SetUpRequest,
base::Unretained(this), label));
return label;
}
@@ -632,7 +648,7 @@ void MediaStreamManager::GenerateStream(
// MediaStreamManager is deleted on the UI thread, after the IO thread has
// been stopped.
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
- base::BindOnce(&MediaStreamManager::SetupRequest,
+ base::BindOnce(&MediaStreamManager::SetUpRequest,
base::Unretained(this), label));
}
@@ -809,9 +825,11 @@ void MediaStreamManager::OpenDevice(int render_process_id,
StreamControls controls;
if (IsAudioInputMediaType(type)) {
controls.audio.requested = true;
+ controls.audio.stream_type = type;
controls.audio.device_id = device_id;
- } else if (IsVideoMediaType(type)) {
+ } else if (IsVideoInputMediaType(type)) {
controls.video.requested = true;
+ controls.video.stream_type = type;
controls.video.device_id = device_id;
} else {
NOTREACHED();
@@ -830,7 +848,7 @@ void MediaStreamManager::OpenDevice(int render_process_id,
// MediaStreamManager is deleted on the UI thread, after the IO thread has
// been stopped.
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
- base::BindOnce(&MediaStreamManager::SetupRequest,
+ base::BindOnce(&MediaStreamManager::SetUpRequest,
base::Unretained(this), label));
}
@@ -968,8 +986,9 @@ void MediaStreamManager::StartEnumeration(DeviceRequest* request,
devices_to_enumerate[MEDIA_DEVICE_TYPE_VIDEO_INPUT] = request_video_input;
media_devices_manager_->EnumerateDevices(
devices_to_enumerate,
- base::Bind(&MediaStreamManager::DevicesEnumerated, base::Unretained(this),
- request_audio_input, request_video_input, label));
+ base::BindOnce(&MediaStreamManager::DevicesEnumerated,
+ base::Unretained(this), request_audio_input,
+ request_video_input, label));
}
std::string MediaStreamManager::AddRequest(DeviceRequest* request) {
@@ -1016,10 +1035,11 @@ void MediaStreamManager::ReadOutputParamsAndPostRequestToUI(
const MediaDeviceEnumeration& enumeration) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- // Actual audio parameters are required only for MEDIA_TAB_AUDIO_CAPTURE.
- // TODO(guidou): MEDIA_TAB_AUDIO_CAPTURE should not be a special case. See
- // crbug.com/584287.
- if (request->audio_type() == MEDIA_TAB_AUDIO_CAPTURE) {
+ // Actual audio parameters are required only for
+ // MEDIA_GUM_TAB_AUDIO_CAPTURE.
+ // TODO(guidou): MEDIA_GUM_TAB_AUDIO_CAPTURE should not be a special
+ // case. See https://crbug.com/584287.
+ if (request->audio_type() == MEDIA_GUM_TAB_AUDIO_CAPTURE) {
// Using base::Unretained is safe: |audio_system_| will post
// PostRequestToUI() to IO thread, and MediaStreamManager is deleted on the
// UI thread, after the IO thread has been stopped.
@@ -1052,14 +1072,14 @@ void MediaStreamManager::PostRequestToUI(
// Post the request to UI and set the state.
if (IsAudioInputMediaType(audio_type))
request->SetState(audio_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
- if (IsVideoMediaType(video_type))
+ if (IsVideoInputMediaType(video_type))
request->SetState(video_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
// If using the fake UI, it will just auto-select from the available devices.
// The fake UI doesn't work for desktop sharing requests since we can't see
// its devices from here; always use the real UI for such requests.
if (fake_ui_factory_ &&
- request->video_type() != MEDIA_DESKTOP_VIDEO_CAPTURE) {
+ request->video_type() != MEDIA_GUM_DESKTOP_VIDEO_CAPTURE) {
MediaStreamDevices devices = ConvertToMediaStreamDevices(
request->audio_type(), enumeration[MEDIA_DEVICE_TYPE_AUDIO_INPUT]);
MediaStreamDevices video_devices = ConvertToMediaStreamDevices(
@@ -1067,6 +1087,13 @@ void MediaStreamManager::PostRequestToUI(
devices.reserve(devices.size() + video_devices.size());
devices.insert(devices.end(), video_devices.begin(), video_devices.end());
+ if (request->video_type() == MEDIA_DISPLAY_VIDEO_CAPTURE) {
+ DCHECK(devices.empty());
+ DesktopMediaID media_id = FindDesktopMediaIDFromFakeDeviceConfig();
+ devices.push_back(MediaStreamDevice(MEDIA_DISPLAY_VIDEO_CAPTURE,
+ media_id.ToString(),
+ media_id.ToString()));
+ }
std::unique_ptr<FakeMediaStreamUIProxy> fake_ui = fake_ui_factory_.Run();
fake_ui->SetAvailableDevices(devices);
@@ -1083,42 +1110,51 @@ void MediaStreamManager::PostRequestToUI(
media::AudioParameters::UnavailableDeviceParams())));
}
-void MediaStreamManager::SetupRequest(const std::string& label) {
+void MediaStreamManager::SetUpRequest(const std::string& label) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DeviceRequest* request = FindRequest(label);
if (!request) {
- DVLOG(1) << "SetupRequest label " << label << " doesn't exist!!";
+ DVLOG(1) << "SetUpRequest label " << label << " doesn't exist!!";
return; // This can happen if the request has been canceled.
}
- MediaStreamType audio_type = MEDIA_NO_SERVICE;
- MediaStreamType video_type = MEDIA_NO_SERVICE;
- ParseStreamType(request->controls, &audio_type, &video_type);
- request->SetAudioType(audio_type);
- request->SetVideoType(video_type);
+ request->SetAudioType(AdjustAudioStreamTypeBasedOnCommandLineSwitches(
+ request->controls.audio.stream_type));
+ request->SetVideoType(request->controls.video.stream_type);
- const bool is_web_contents_capture = audio_type == MEDIA_TAB_AUDIO_CAPTURE ||
- video_type == MEDIA_TAB_VIDEO_CAPTURE;
- if (is_web_contents_capture && !SetupTabCaptureRequest(request)) {
- FinalizeRequestFailed(label, request, MEDIA_DEVICE_TAB_CAPTURE_FAILURE);
+ const bool is_display_capture =
+ request->video_type() == MEDIA_DISPLAY_VIDEO_CAPTURE;
+ if (is_display_capture && !SetUpDisplayCaptureRequest(request)) {
+ FinalizeRequestFailed(label, request, MEDIA_DEVICE_SCREEN_CAPTURE_FAILURE);
+ return;
+ }
+
+ const bool is_tab_capture =
+ request->audio_type() == MEDIA_GUM_TAB_AUDIO_CAPTURE ||
+ request->video_type() == MEDIA_GUM_TAB_VIDEO_CAPTURE;
+ if (is_tab_capture) {
+ if (!SetUpTabCaptureRequest(request, label)) {
+ FinalizeRequestFailed(label, request, MEDIA_DEVICE_TAB_CAPTURE_FAILURE);
+ }
return;
}
- const bool is_screen_capture = video_type == MEDIA_DESKTOP_VIDEO_CAPTURE;
- if (is_screen_capture && !SetupScreenCaptureRequest(request)) {
+ const bool is_screen_capture =
+ request->video_type() == MEDIA_GUM_DESKTOP_VIDEO_CAPTURE;
+ if (is_screen_capture && !SetUpScreenCaptureRequest(request)) {
FinalizeRequestFailed(label, request, MEDIA_DEVICE_SCREEN_CAPTURE_FAILURE);
return;
}
- if (!is_web_contents_capture && !is_screen_capture) {
- if (audio_type == MEDIA_DEVICE_AUDIO_CAPTURE ||
- video_type == MEDIA_DEVICE_VIDEO_CAPTURE) {
+ if (!is_tab_capture && !is_screen_capture && !is_display_capture) {
+ if (IsDeviceMediaType(request->audio_type()) ||
+ IsDeviceMediaType(request->video_type())) {
StartEnumeration(request, label);
return;
}
// If no actual device capture is requested, set up the request with an
// empty device list.
- if (!SetupDeviceCaptureRequest(request, MediaDeviceEnumeration())) {
+ if (!SetUpDeviceCaptureRequest(request, MediaDeviceEnumeration())) {
FinalizeRequestFailed(label, request, MEDIA_DEVICE_NO_HARDWARE);
return;
}
@@ -1126,7 +1162,27 @@ void MediaStreamManager::SetupRequest(const std::string& label) {
ReadOutputParamsAndPostRequestToUI(label, request, MediaDeviceEnumeration());
}
-bool MediaStreamManager::SetupDeviceCaptureRequest(
+bool MediaStreamManager::SetUpDisplayCaptureRequest(DeviceRequest* request) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(request->video_type() == MEDIA_DISPLAY_VIDEO_CAPTURE);
+
+ // getDisplayMedia function does not permit the use of constraints for
+ // selection of a source, see
+ // https://w3c.github.io/mediacapture-screen-share/#constraints.
+ if (!request->controls.video.requested ||
+ !request->controls.video.device_id.empty()) {
+ LOG(ERROR) << "Invalid display media request.";
+ return false;
+ }
+
+ request->CreateUIRequest(std::string() /* requested_audio_device_id */,
+ std::string() /* requested_video_device_id */);
+ DVLOG(3) << "Audio requested " << request->controls.audio.requested
+ << " Video requested " << request->controls.video.requested;
+ return true;
+}
+
+bool MediaStreamManager::SetUpDeviceCaptureRequest(
DeviceRequest* request,
const MediaDeviceEnumeration& enumeration) {
DCHECK((request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE ||
@@ -1156,9 +1212,10 @@ bool MediaStreamManager::SetupDeviceCaptureRequest(
return true;
}
-bool MediaStreamManager::SetupTabCaptureRequest(DeviceRequest* request) {
- DCHECK(request->audio_type() == MEDIA_TAB_AUDIO_CAPTURE ||
- request->video_type() == MEDIA_TAB_VIDEO_CAPTURE);
+bool MediaStreamManager::SetUpTabCaptureRequest(DeviceRequest* request,
+ const std::string& label) {
+ DCHECK(request->audio_type() == MEDIA_GUM_TAB_AUDIO_CAPTURE ||
+ request->video_type() == MEDIA_GUM_TAB_VIDEO_CAPTURE);
std::string capture_device_id;
if (!request->controls.audio.device_id.empty()) {
@@ -1169,17 +1226,56 @@ bool MediaStreamManager::SetupTabCaptureRequest(DeviceRequest* request) {
return false;
}
- // Customize controls for a WebContents based capture.
- WebContentsMediaCaptureId web_id;
- bool has_valid_device_id =
- WebContentsMediaCaptureId::Parse(capture_device_id, &web_id);
- if (!has_valid_device_id ||
- (request->audio_type() != MEDIA_TAB_AUDIO_CAPTURE &&
+ if ((request->audio_type() != MEDIA_GUM_TAB_AUDIO_CAPTURE &&
request->audio_type() != MEDIA_NO_SERVICE) ||
- (request->video_type() != MEDIA_TAB_VIDEO_CAPTURE &&
+ (request->video_type() != MEDIA_GUM_TAB_VIDEO_CAPTURE &&
request->video_type() != MEDIA_NO_SERVICE)) {
return false;
}
+
+ BrowserThread::PostTaskAndReplyWithResult(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&MediaStreamManager::ResolveTabCaptureDeviceIdOnUIThread,
+ base::Unretained(this), capture_device_id,
+ request->requesting_process_id,
+ request->requesting_frame_id,
+ request->salt_and_origin.origin.GetURL()),
+ base::BindOnce(
+ &MediaStreamManager::FinishTabCaptureRequestSetupWithDeviceId,
+ base::Unretained(this), label));
+ return true;
+}
+
+DesktopMediaID MediaStreamManager::ResolveTabCaptureDeviceIdOnUIThread(
+ const std::string& capture_device_id,
+ int requesting_process_id,
+ int requesting_frame_id,
+ const GURL& origin) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ // Resolve DesktopMediaID for the specified device id.
+ return DesktopStreamsRegistry::GetInstance()->RequestMediaForStreamId(
+ capture_device_id, requesting_process_id, requesting_frame_id, origin,
+ nullptr, kRegistryStreamTypeTab);
+}
+
+void MediaStreamManager::FinishTabCaptureRequestSetupWithDeviceId(
+ const std::string& label,
+ const DesktopMediaID& device_id) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ DeviceRequest* request = FindRequest(label);
+ if (!request) {
+ DVLOG(1) << "SetUpRequest label " << label << " doesn't exist!!";
+ return; // This can happen if the request has been canceled.
+ }
+
+ // Received invalid device id.
+ if (device_id.type != content::DesktopMediaID::TYPE_WEB_CONTENTS) {
+ FinalizeRequestFailed(label, request, MEDIA_DEVICE_TAB_CAPTURE_FAILURE);
+ return;
+ }
+
+ content::WebContentsMediaCaptureId web_id = device_id.web_contents_id;
web_id.disable_local_echo = request->controls.disable_local_echo;
request->tab_capture_device_id = web_id.ToString();
@@ -1187,43 +1283,39 @@ bool MediaStreamManager::SetupTabCaptureRequest(DeviceRequest* request) {
request->CreateTabCaptureUIRequest(web_id.render_process_id,
web_id.main_render_frame_id);
- DVLOG(3) << "SetupTabCaptureRequest "
- << ", {capture_device_id = " << capture_device_id << "}"
+ DVLOG(3) << "SetUpTabCaptureRequest "
+ << ", {capture_device_id = " << web_id.ToString() << "}"
<< ", {target_render_process_id = " << web_id.render_process_id
<< "}"
<< ", {target_render_frame_id = " << web_id.main_render_frame_id
<< "}";
- return true;
+
+ ReadOutputParamsAndPostRequestToUI(label, request, MediaDeviceEnumeration());
}
-bool MediaStreamManager::SetupScreenCaptureRequest(DeviceRequest* request) {
- DCHECK(request->audio_type() == MEDIA_DESKTOP_AUDIO_CAPTURE ||
- request->video_type() == MEDIA_DESKTOP_VIDEO_CAPTURE);
+bool MediaStreamManager::SetUpScreenCaptureRequest(DeviceRequest* request) {
+ DCHECK(request->audio_type() == MEDIA_GUM_DESKTOP_AUDIO_CAPTURE ||
+ request->video_type() == MEDIA_GUM_DESKTOP_VIDEO_CAPTURE);
// For screen capture we only support two valid combinations:
// (1) screen video capture only, or
// (2) screen video capture with loopback audio capture.
- if (request->video_type() != MEDIA_DESKTOP_VIDEO_CAPTURE ||
+ if (request->video_type() != MEDIA_GUM_DESKTOP_VIDEO_CAPTURE ||
(request->audio_type() != MEDIA_NO_SERVICE &&
- request->audio_type() != MEDIA_DESKTOP_AUDIO_CAPTURE)) {
+ request->audio_type() != MEDIA_GUM_DESKTOP_AUDIO_CAPTURE)) {
LOG(ERROR) << "Invalid screen capture request.";
return false;
}
std::string video_device_id;
- if (request->video_type() == MEDIA_DESKTOP_VIDEO_CAPTURE) {
- const std::string& video_stream_source =
- request->controls.video.stream_source;
-
- if (video_stream_source == kMediaStreamSourceDesktop &&
- !request->controls.video.device_id.empty()) {
- video_device_id = request->controls.video.device_id;
- }
+ if (request->video_type() == MEDIA_GUM_DESKTOP_VIDEO_CAPTURE &&
+ !request->controls.video.device_id.empty()) {
+ video_device_id = request->controls.video.device_id;
}
const std::string audio_device_id =
- request->audio_type() == MEDIA_DESKTOP_AUDIO_CAPTURE ? video_device_id
- : "";
+ request->audio_type() == MEDIA_GUM_DESKTOP_AUDIO_CAPTURE ? video_device_id
+ : "";
request->CreateUIRequest(audio_device_id, video_device_id);
return true;
@@ -1285,7 +1377,7 @@ void MediaStreamManager::FinalizeGenerateStream(const std::string& label,
for (const MediaStreamDevice& device : request->devices) {
if (IsAudioInputMediaType(device.type))
audio_devices.push_back(device);
- else if (IsVideoMediaType(device.type))
+ else if (IsVideoInputMediaType(device.type))
video_devices.push_back(device);
else
NOTREACHED();
@@ -1410,7 +1502,7 @@ void MediaStreamManager::Opened(MediaStreamType stream_type,
for (MediaStreamDevice& device : request->devices) {
if (device.type == stream_type &&
device.session_id == capture_session_id) {
- CHECK(request->state(device.type) == MEDIA_REQUEST_STATE_OPENING);
+ CHECK_EQ(request->state(device.type), MEDIA_REQUEST_STATE_OPENING);
// We've found a matching request.
request->SetState(device.type, MEDIA_REQUEST_STATE_DONE);
@@ -1418,7 +1510,7 @@ void MediaStreamManager::Opened(MediaStreamType stream_type,
// Store the native audio parameters in the device struct.
// TODO(xians): Handle the tab capture sample rate/channel layout
// in AudioInputDeviceManager::Open().
- if (device.type != MEDIA_TAB_AUDIO_CAPTURE) {
+ if (device.type != MEDIA_GUM_TAB_AUDIO_CAPTURE) {
const MediaStreamDevice* opened_device =
audio_input_device_manager_->GetOpenedDeviceById(
device.session_id);
@@ -1493,7 +1585,7 @@ void MediaStreamManager::DevicesEnumerated(
}
}
- if (!SetupDeviceCaptureRequest(request, enumeration))
+ if (!SetUpDeviceCaptureRequest(request, enumeration))
FinalizeRequestFailed(label, request, MEDIA_DEVICE_NO_HARDWARE);
else
ReadOutputParamsAndPostRequestToUI(label, request, enumeration);
@@ -1587,16 +1679,16 @@ void MediaStreamManager::HandleAccessRequestResponse(
for (const MediaStreamDevice& media_stream_device : devices) {
MediaStreamDevice device = media_stream_device;
- if (device.type == MEDIA_TAB_VIDEO_CAPTURE ||
- device.type == MEDIA_TAB_AUDIO_CAPTURE) {
+ if (device.type == MEDIA_GUM_TAB_VIDEO_CAPTURE ||
+ device.type == MEDIA_GUM_TAB_AUDIO_CAPTURE) {
device.id = request->tab_capture_device_id;
}
// Initialize the sample_rate and channel_layout here since for audio
// mirroring, we don't go through EnumerateDevices where these are usually
// initialized.
- if (device.type == MEDIA_TAB_AUDIO_CAPTURE ||
- device.type == MEDIA_DESKTOP_AUDIO_CAPTURE) {
+ if (device.type == MEDIA_GUM_TAB_AUDIO_CAPTURE ||
+ device.type == MEDIA_GUM_DESKTOP_AUDIO_CAPTURE) {
int sample_rate = output_parameters.sample_rate();
// If we weren't able to get the native sampling rate or the sample_rate
// is outside the valid range for input devices set reasonable defaults.
@@ -1649,7 +1741,7 @@ void MediaStreamManager::HandleAccessRequestResponse(
DVLOG(1) << "Set no audio found label " << label;
}
- if (!found_video && IsVideoMediaType(request->video_type()))
+ if (!found_video && IsVideoInputMediaType(request->video_type()))
request->SetState(request->video_type(), MEDIA_REQUEST_STATE_ERROR);
if (RequestDone(*request))
@@ -1707,7 +1799,7 @@ void MediaStreamManager::NotifyDevicesChanged(
new_devices);
if (media_observer)
media_observer->OnAudioCaptureDevicesChanged();
- } else if (IsVideoMediaType(stream_type)) {
+ } else if (IsVideoInputMediaType(stream_type)) {
MediaCaptureDevicesImpl::GetInstance()->OnVideoCaptureDevicesChanged(
new_devices);
if (media_observer)
@@ -1721,7 +1813,7 @@ bool MediaStreamManager::RequestDone(const DeviceRequest& request) const {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
const bool requested_audio = IsAudioInputMediaType(request.audio_type());
- const bool requested_video = IsVideoMediaType(request.video_type());
+ const bool requested_video = IsVideoInputMediaType(request.video_type());
const bool audio_done =
!requested_audio ||
@@ -1742,7 +1834,7 @@ bool MediaStreamManager::RequestDone(const DeviceRequest& request) const {
MediaStreamProvider* MediaStreamManager::GetDeviceManager(
MediaStreamType stream_type) {
- if (IsVideoMediaType(stream_type))
+ if (IsVideoInputMediaType(stream_type))
return video_capture_manager();
else if (IsAudioInputMediaType(stream_type))
return audio_input_device_manager();
@@ -1758,13 +1850,13 @@ void MediaStreamManager::OnMediaStreamUIWindowId(
if (!window_id)
return;
- if (video_type != MEDIA_DESKTOP_VIDEO_CAPTURE)
+ if (video_type != MEDIA_GUM_DESKTOP_VIDEO_CAPTURE)
return;
// Pass along for desktop screen and window capturing when
// DesktopCaptureDevice is used.
for (const MediaStreamDevice& device : devices) {
- if (device.type != MEDIA_DESKTOP_VIDEO_CAPTURE)
+ if (device.type != MEDIA_GUM_DESKTOP_VIDEO_CAPTURE)
continue;
DesktopMediaID media_id = DesktopMediaID::Parse(device.id);
diff --git a/chromium/content/browser/renderer_host/media/media_stream_manager.h b/chromium/content/browser/renderer_host/media/media_stream_manager.h
index c73c8d60c26..2c0afbaa7fb 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_manager.h
+++ b/chromium/content/browser/renderer_host/media/media_stream_manager.h
@@ -49,6 +49,7 @@
#include "content/common/content_export.h"
#include "content/common/media/media_devices.h"
#include "content/common/media/media_stream_controls.h"
+#include "content/public/browser/desktop_media_id.h"
#include "content/public/browser/media_request_state.h"
#include "content/public/common/media_stream_request.h"
#include "media/base/video_facing.h"
@@ -351,20 +352,32 @@ class CONTENT_EXPORT MediaStreamManager
void DeleteRequest(const std::string& label);
// Prepare the request with label |label| by starting device enumeration if
// needed.
- void SetupRequest(const std::string& label);
+ void SetUpRequest(const std::string& label);
// Prepare |request| of type MEDIA_DEVICE_AUDIO_CAPTURE and/or
// MEDIA_DEVICE_VIDEO_CAPTURE for being posted to the UI by parsing
// StreamControls for requested device IDs.
- bool SetupDeviceCaptureRequest(DeviceRequest* request,
+ bool SetUpDeviceCaptureRequest(DeviceRequest* request,
const MediaDeviceEnumeration& enumeration);
- // Prepare |request| of type MEDIA_TAB_AUDIO_CAPTURE and/or
- // MEDIA_TAB_VIDEO_CAPTURE for being posted to the UI by parsing
- // StreamControls for requested tab capture IDs.
- bool SetupTabCaptureRequest(DeviceRequest* request);
- // Prepare |request| of type MEDIA_DESKTOP_AUDIO_CAPTURE and/or
- // MEDIA_DESKTOP_VIDEO_CAPTURE for being posted to the UI by parsing
+ // Prepare |request| of type MEDIA_DISPLAY_CAPTURE.
+ bool SetUpDisplayCaptureRequest(DeviceRequest* request);
+ // Prepare |request| of type MEDIA_GUM_DESKTOP_AUDIO_CAPTURE and/or
+ // MEDIA_GUM_DESKTOP_VIDEO_CAPTURE for being posted to the UI by parsing
// StreamControls for the requested desktop ID.
- bool SetupScreenCaptureRequest(DeviceRequest* request);
+ bool SetUpScreenCaptureRequest(DeviceRequest* request);
+ // Resolve the random device ID of tab capture on UI thread before proceeding
+ // with the tab capture UI request.
+ bool SetUpTabCaptureRequest(DeviceRequest* request, const std::string& label);
+ DesktopMediaID ResolveTabCaptureDeviceIdOnUIThread(
+ const std::string& capture_device_id,
+ int requesting_process_id,
+ int requesting_frame_id,
+ const GURL& origin);
+ // Prepare |request| of type MEDIA_GUM_TAB_AUDIO_CAPTURE and/or
+ // MEDIA_GUM_TAB_VIDEO_CAPTURE for being posted to the UI after the
+ // requested tab capture IDs are resolved from registry.
+ void FinishTabCaptureRequestSetupWithDeviceId(
+ const std::string& label,
+ const DesktopMediaID& device_id);
// Called when a request has been setup and devices have been enumerated if
// needed.
void ReadOutputParamsAndPostRequestToUI(
diff --git a/chromium/content/browser/renderer_host/media/media_stream_manager_unittest.cc b/chromium/content/browser/renderer_host/media/media_stream_manager_unittest.cc
index 14d12b8b1a9..fae5c3ca81c 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_manager_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/media_stream_manager_unittest.cc
@@ -156,6 +156,20 @@ class TestBrowserClient : public ContentBrowserClient {
MediaObserver* media_observer_;
};
+class MockMediaStreamUIProxy : public FakeMediaStreamUIProxy {
+ public:
+ MockMediaStreamUIProxy()
+ : FakeMediaStreamUIProxy(/*tests_use_fake_render_frame_hosts=*/true) {}
+ void RequestAccess(std::unique_ptr<MediaStreamRequest> request,
+ ResponseCallback response_callback) override {
+ MockRequestAccess(request, response_callback);
+ }
+
+ MOCK_METHOD2(MockRequestAccess,
+ void(std::unique_ptr<MediaStreamRequest>& request,
+ ResponseCallback& response_callback));
+};
+
} // namespace
class MediaStreamManagerTest : public ::testing::Test {
@@ -250,17 +264,20 @@ TEST_F(MediaStreamManagerTest, MakeAndCancelMediaAccessRequest) {
EXPECT_CALL(*media_observer_,
OnMediaRequestStateChanged(_, _, _, _, MEDIA_DEVICE_VIDEO_CAPTURE,
MEDIA_REQUEST_STATE_CLOSING));
- EXPECT_CALL(*media_observer_,
- OnMediaRequestStateChanged(_, _, _, _, MEDIA_TAB_AUDIO_CAPTURE,
- MEDIA_REQUEST_STATE_CLOSING));
- EXPECT_CALL(*media_observer_,
- OnMediaRequestStateChanged(_, _, _, _, MEDIA_TAB_VIDEO_CAPTURE,
- MEDIA_REQUEST_STATE_CLOSING));
EXPECT_CALL(*media_observer_, OnMediaRequestStateChanged(
- _, _, _, _, MEDIA_DESKTOP_VIDEO_CAPTURE,
+ _, _, _, _, MEDIA_GUM_TAB_AUDIO_CAPTURE,
+ MEDIA_REQUEST_STATE_CLOSING));
+ EXPECT_CALL(*media_observer_, OnMediaRequestStateChanged(
+ _, _, _, _, MEDIA_GUM_TAB_VIDEO_CAPTURE,
+ MEDIA_REQUEST_STATE_CLOSING));
+ EXPECT_CALL(*media_observer_, OnMediaRequestStateChanged(
+ _, _, _, _, MEDIA_GUM_DESKTOP_VIDEO_CAPTURE,
+ MEDIA_REQUEST_STATE_CLOSING));
+ EXPECT_CALL(*media_observer_, OnMediaRequestStateChanged(
+ _, _, _, _, MEDIA_GUM_DESKTOP_AUDIO_CAPTURE,
MEDIA_REQUEST_STATE_CLOSING));
EXPECT_CALL(*media_observer_, OnMediaRequestStateChanged(
- _, _, _, _, MEDIA_DESKTOP_AUDIO_CAPTURE,
+ _, _, _, _, MEDIA_DISPLAY_VIDEO_CAPTURE,
MEDIA_REQUEST_STATE_CLOSING));
media_stream_manager_->CancelRequest(label);
run_loop_.RunUntilIdle();
@@ -301,17 +318,20 @@ TEST_F(MediaStreamManagerTest, MakeAndCancelMultipleRequests) {
EXPECT_CALL(*media_observer_,
OnMediaRequestStateChanged(_, _, _, _, MEDIA_DEVICE_VIDEO_CAPTURE,
MEDIA_REQUEST_STATE_CLOSING));
- EXPECT_CALL(*media_observer_,
- OnMediaRequestStateChanged(_, _, _, _, MEDIA_TAB_AUDIO_CAPTURE,
- MEDIA_REQUEST_STATE_CLOSING));
- EXPECT_CALL(*media_observer_,
- OnMediaRequestStateChanged(_, _, _, _, MEDIA_TAB_VIDEO_CAPTURE,
- MEDIA_REQUEST_STATE_CLOSING));
EXPECT_CALL(*media_observer_, OnMediaRequestStateChanged(
- _, _, _, _, MEDIA_DESKTOP_VIDEO_CAPTURE,
+ _, _, _, _, MEDIA_GUM_TAB_AUDIO_CAPTURE,
+ MEDIA_REQUEST_STATE_CLOSING));
+ EXPECT_CALL(*media_observer_, OnMediaRequestStateChanged(
+ _, _, _, _, MEDIA_GUM_TAB_VIDEO_CAPTURE,
+ MEDIA_REQUEST_STATE_CLOSING));
+ EXPECT_CALL(*media_observer_, OnMediaRequestStateChanged(
+ _, _, _, _, MEDIA_GUM_DESKTOP_VIDEO_CAPTURE,
+ MEDIA_REQUEST_STATE_CLOSING));
+ EXPECT_CALL(*media_observer_, OnMediaRequestStateChanged(
+ _, _, _, _, MEDIA_GUM_DESKTOP_AUDIO_CAPTURE,
MEDIA_REQUEST_STATE_CLOSING));
EXPECT_CALL(*media_observer_, OnMediaRequestStateChanged(
- _, _, _, _, MEDIA_DESKTOP_AUDIO_CAPTURE,
+ _, _, _, _, MEDIA_DISPLAY_VIDEO_CAPTURE,
MEDIA_REQUEST_STATE_CLOSING));
media_stream_manager_->CancelRequest(label1);
@@ -374,4 +394,90 @@ TEST_F(MediaStreamManagerTest, DeviceID) {
EXPECT_TRUE(base::IsAsciiDigit(c) || (c >= 'a' && c <= 'f'));
}
+TEST_F(MediaStreamManagerTest, GetDisplayMediaRequest) {
+ media_stream_manager_->UseFakeUIFactoryForTests(base::BindRepeating([]() {
+ return std::make_unique<FakeMediaStreamUIProxy>(
+ /*tests_use_fake_render_frame_hosts=*/true);
+ }));
+
+ StreamControls controls(false /* request_audio */, true /* request_video */);
+ controls.video.stream_type = MEDIA_DISPLAY_VIDEO_CAPTURE;
+ const int render_process_id = 1;
+ const int render_frame_id = 1;
+ const int page_request_id = 1;
+
+ MediaStreamDevice video_device;
+ MediaStreamManager::GenerateStreamCallback generate_stream_callback =
+ base::BindOnce(
+ [](base::RunLoop* wait_loop, MediaStreamDevice* video_device,
+ MediaStreamRequestResult result, const std::string& label,
+ const MediaStreamDevices& audio_devices,
+ const MediaStreamDevices& video_devices) {
+ EXPECT_EQ(0u, audio_devices.size());
+ ASSERT_EQ(1u, video_devices.size());
+ *video_device = video_devices[0];
+ wait_loop->Quit();
+ },
+ &run_loop_, &video_device);
+ MediaStreamManager::DeviceStoppedCallback stopped_callback;
+ EXPECT_CALL(*media_observer_, OnMediaRequestStateChanged(
+ _, _, _, _, MEDIA_DISPLAY_VIDEO_CAPTURE,
+ MEDIA_REQUEST_STATE_PENDING_APPROVAL));
+ EXPECT_CALL(*media_observer_, OnMediaRequestStateChanged(
+ _, _, _, _, MEDIA_DISPLAY_VIDEO_CAPTURE,
+ MEDIA_REQUEST_STATE_OPENING));
+ EXPECT_CALL(*media_observer_, OnMediaRequestStateChanged(
+ _, _, _, _, MEDIA_DISPLAY_VIDEO_CAPTURE,
+ MEDIA_REQUEST_STATE_DONE));
+ media_stream_manager_->GenerateStream(
+ render_process_id, render_frame_id, page_request_id, controls,
+ MediaDeviceSaltAndOrigin(), false /* user_gesture */,
+ std::move(generate_stream_callback), std::move(stopped_callback));
+ run_loop_.Run();
+
+ EXPECT_EQ(MEDIA_DISPLAY_VIDEO_CAPTURE, video_device.type);
+ EXPECT_CALL(*media_observer_, OnMediaRequestStateChanged(
+ _, _, _, _, MEDIA_DISPLAY_VIDEO_CAPTURE,
+ MEDIA_REQUEST_STATE_CLOSING));
+ media_stream_manager_->StopStreamDevice(render_process_id, render_frame_id,
+ video_device.id,
+ video_device.session_id);
+}
+
+TEST_F(MediaStreamManagerTest, GetDisplayMediaRequestCallsUIProxy) {
+ media_stream_manager_->UseFakeUIFactoryForTests(base::BindRepeating(
+ [](base::RunLoop* run_loop) {
+ auto mock_ui = std::make_unique<MockMediaStreamUIProxy>();
+ EXPECT_CALL(*mock_ui, MockRequestAccess(_, _))
+ .WillOnce(testing::Invoke(
+ [run_loop](std::unique_ptr<MediaStreamRequest>& request,
+ testing::Unused) {
+ EXPECT_EQ(MEDIA_DISPLAY_VIDEO_CAPTURE, request->video_type);
+ run_loop->Quit();
+ }));
+ return std::unique_ptr<FakeMediaStreamUIProxy>(std::move(mock_ui));
+ },
+ &run_loop_));
+ StreamControls controls(false /* request_audio */, true /* request_video */);
+ controls.video.stream_type = MEDIA_DISPLAY_VIDEO_CAPTURE;
+
+ MediaStreamManager::GenerateStreamCallback generate_stream_callback =
+ base::BindOnce([](MediaStreamRequestResult result,
+ const std::string& label,
+ const MediaStreamDevices& audio_devices,
+ const MediaStreamDevices& video_devices) {});
+ EXPECT_CALL(*media_observer_, OnMediaRequestStateChanged(
+ _, _, _, _, MEDIA_DISPLAY_VIDEO_CAPTURE,
+ MEDIA_REQUEST_STATE_PENDING_APPROVAL));
+ media_stream_manager_->GenerateStream(
+ 0, 0, 0, controls, MediaDeviceSaltAndOrigin(), false /* user_gesture */,
+ std::move(generate_stream_callback),
+ MediaStreamManager::DeviceStoppedCallback());
+ run_loop_.Run();
+
+ EXPECT_CALL(*media_observer_, OnMediaRequestStateChanged(_, _, _, _, _, _))
+ .Times(testing::AtLeast(1));
+ media_stream_manager_->CancelAllRequests(0, 0);
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/media/media_stream_ui_proxy.cc b/chromium/content/browser/renderer_host/media/media_stream_ui_proxy.cc
index 2f13d1d2045..43c3b83d83d 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_ui_proxy.cc
+++ b/chromium/content/browser/renderer_host/media/media_stream_ui_proxy.cc
@@ -7,13 +7,11 @@
#include <utility>
#include "base/command_line.h"
-#include "base/feature_list.h"
#include "base/macros.h"
#include "content/browser/frame_host/frame_tree_node.h"
#include "content/browser/frame_host/render_frame_host_delegate.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "media/capture/video/fake_video_capture_device.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom.h"
@@ -25,9 +23,6 @@ namespace content {
bool IsFeatureEnabled(RenderFrameHost* rfh,
bool tests_use_fake_render_frame_hosts,
blink::mojom::FeaturePolicyFeature feature) {
- if (!base::FeatureList::IsEnabled(features::kUseFeaturePolicyForPermissions))
- return true;
-
// Some tests don't (or can't) set up the RenderFrameHost. In these cases we
// just ignore feature policy checks (there is no feature policy to test).
if (!rfh && tests_use_fake_render_frame_hosts)
@@ -125,9 +120,9 @@ void MediaStreamUIProxy::Core::RequestAccess(
render_delegate->RequestMediaAccessPermission(
*request,
- base::Bind(&Core::ProcessAccessRequestResponse,
- weak_factory_.GetWeakPtr(), request->render_process_id,
- request->render_frame_id));
+ base::BindOnce(&Core::ProcessAccessRequestResponse,
+ weak_factory_.GetWeakPtr(), request->render_process_id,
+ request->render_frame_id));
}
void MediaStreamUIProxy::Core::OnStarted(gfx::NativeViewId* window_id) {
@@ -324,9 +319,8 @@ void FakeMediaStreamUIProxy::RequestAccess(
request->requested_audio_device_id == it->id)) {
devices_to_use.push_back(*it);
accepted_audio = true;
- } else if (!accepted_video &&
- IsVideoMediaType(request->video_type) &&
- IsVideoMediaType(it->type) &&
+ } else if (!accepted_video && IsVideoInputMediaType(request->video_type) &&
+ IsVideoInputMediaType(it->type) &&
(request->requested_video_device_id.empty() ||
request->requested_video_device_id == it->id)) {
devices_to_use.push_back(*it);
diff --git a/chromium/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc b/chromium/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc
index 0acf2f42c16..54c050bceba 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc
@@ -9,10 +9,8 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
-#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "content/browser/frame_host/render_frame_host_delegate.h"
-#include "content/public/common/content_features.h"
#include "content/public/test/test_browser_thread.h"
#include "content/test/test_render_frame_host.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -262,7 +260,7 @@ TEST_F(MediaStreamUIProxyTest, MAYBE_WindowIdCallbackCalled) {
std::unique_ptr<MediaStreamRequest> request(new MediaStreamRequest(
0, 0, 0, GURL("http://origin/"), false, MEDIA_GENERATE_STREAM,
std::string(), std::string(), MEDIA_NO_SERVICE,
- MEDIA_DESKTOP_VIDEO_CAPTURE, false));
+ MEDIA_GUM_DESKTOP_VIDEO_CAPTURE, false));
MediaStreamRequest* request_ptr = request.get();
proxy_->RequestAccess(
@@ -403,8 +401,6 @@ class MediaStreamUIProxyFeaturePolicyTest
};
TEST_F(MediaStreamUIProxyFeaturePolicyTest, FeaturePolicy) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(features::kUseFeaturePolicyForPermissions);
MediaStreamDevices devices;
MediaStreamRequestResult result;
@@ -448,19 +444,6 @@ TEST_F(MediaStreamUIProxyFeaturePolicyTest, FeaturePolicy) {
&devices, &result);
EXPECT_EQ(MEDIA_DEVICE_PERMISSION_DENIED, result);
ASSERT_EQ(0u, devices.size());
-
- // Ensure that the policy is ignored if kUseFeaturePolicyForPermissions is
- // disabled.
- base::test::ScopedFeatureList empty_feature_list;
- empty_feature_list.InitAndDisableFeature(
- features::kUseFeaturePolicyForPermissions);
- GetResultForRequest(CreateRequest(main_rfh(), MEDIA_DEVICE_AUDIO_CAPTURE,
- MEDIA_DEVICE_VIDEO_CAPTURE),
- &devices, &result);
- EXPECT_EQ(MEDIA_DEVICE_OK, result);
- ASSERT_EQ(2u, devices.size());
- EXPECT_EQ(MEDIA_DEVICE_AUDIO_CAPTURE, devices[0].type);
- EXPECT_EQ(MEDIA_DEVICE_VIDEO_CAPTURE, devices[1].type);
}
} // namespace content
diff --git a/chromium/content/browser/renderer_host/media/old_render_frame_audio_input_stream_factory.cc b/chromium/content/browser/renderer_host/media/old_render_frame_audio_input_stream_factory.cc
index 6e33963efe7..5093cee0282 100644
--- a/chromium/content/browser/renderer_host/media/old_render_frame_audio_input_stream_factory.cc
+++ b/chromium/content/browser/renderer_host/media/old_render_frame_audio_input_stream_factory.cc
@@ -125,9 +125,12 @@ void OldRenderFrameAudioInputStreamFactory::CreateStream(
int32_t session_id,
const media::AudioParameters& audio_params,
bool automatic_gain_control,
- uint32_t shared_memory_count) {
+ uint32_t shared_memory_count,
+ audio::mojom::AudioProcessingConfigPtr processing_config) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
+// |processing_config| gets dropped here. It's not supported outside of the
+// audio service. As this class is slated for removal, it will not be updated
+// to support audio processing.
#if defined(OS_CHROMEOS)
if (audio_params.channel_layout() ==
media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) {
diff --git a/chromium/content/browser/renderer_host/media/old_render_frame_audio_input_stream_factory.h b/chromium/content/browser/renderer_host/media/old_render_frame_audio_input_stream_factory.h
index 629b75e508b..01fb38b0bb6 100644
--- a/chromium/content/browser/renderer_host/media/old_render_frame_audio_input_stream_factory.h
+++ b/chromium/content/browser/renderer_host/media/old_render_frame_audio_input_stream_factory.h
@@ -69,11 +69,13 @@ class CONTENT_EXPORT OldRenderFrameAudioInputStreamFactory
base::UniquePtrComparator>;
// mojom::RendererAudioInputStreamFactory implementation.
- void CreateStream(mojom::RendererAudioInputStreamFactoryClientPtr client,
- int32_t session_id,
- const media::AudioParameters& audio_params,
- bool automatic_gain_control,
- uint32_t shared_memory_count) override;
+ void CreateStream(
+ mojom::RendererAudioInputStreamFactoryClientPtr client,
+ int32_t session_id,
+ const media::AudioParameters& audio_params,
+ bool automatic_gain_control,
+ uint32_t shared_memory_count,
+ audio::mojom::AudioProcessingConfigPtr processing_config) override;
void DoCreateStream(mojom::RendererAudioInputStreamFactoryClientPtr client,
int session_id,
diff --git a/chromium/content/browser/renderer_host/media/old_render_frame_audio_input_stream_factory_unittest.cc b/chromium/content/browser/renderer_host/media/old_render_frame_audio_input_stream_factory_unittest.cc
index fb2e934df02..76f0caebe61 100644
--- a/chromium/content/browser/renderer_host/media/old_render_frame_audio_input_stream_factory_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/old_render_frame_audio_input_stream_factory_unittest.cc
@@ -154,8 +154,8 @@ class OldOldRenderFrameAudioInputStreamFactoryTest : public testing::Test {
TEST_F(OldOldRenderFrameAudioInputStreamFactoryTest, CreateStream) {
factory_ptr_->CreateStream(std::move(client_ptr_), kSessionId,
- GetTestAudioParameters(), kAGC,
- kSharedMemoryCount);
+ GetTestAudioParameters(), kAGC, kSharedMemoryCount,
+ nullptr);
// Wait for delegate to be created and |event_handler| set.
base::RunLoop().RunUntilIdle();
diff --git a/chromium/content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory_unittest.cc b/chromium/content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory_unittest.cc
index b4f527af64f..8277d2d73d3 100644
--- a/chromium/content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory_unittest.cc
@@ -235,7 +235,11 @@ TEST(OldRenderFrameAudioOutputStreamFactoryTest, CreateStream) {
GetTestAudioParameters().AsHumanReadableString());
EXPECT_TRUE(id.empty());
- provider->Acquire(params, client.MakeProviderClientPtr());
+ // Ensure that we don't blow up getting a processing ID, despite not using it.
+ const base::UnguessableToken kUnusedProcessingId =
+ base::UnguessableToken::Create();
+ provider->Acquire(params, client.MakeProviderClientPtr(),
+ kUnusedProcessingId);
base::RunLoop().RunUntilIdle();
ASSERT_NE(event_handler, nullptr);
@@ -295,7 +299,8 @@ TEST(OldRenderFrameAudioOutputStreamFactoryTest,
const std::string& id) {}));
base::RunLoop().RunUntilIdle();
- provider->Acquire(GetTestAudioParameters(), client.MakeProviderClientPtr());
+ provider->Acquire(GetTestAudioParameters(), client.MakeProviderClientPtr(),
+ base::nullopt);
base::RunLoop().RunUntilIdle();
ASSERT_NE(event_handler, nullptr);
EXPECT_FALSE(delegate_is_destructed);
@@ -325,7 +330,8 @@ TEST(OldRenderFrameAudioOutputStreamFactoryTest, DelegateError_DeletesStream) {
const std::string& id) {}));
base::RunLoop().RunUntilIdle();
- provider->Acquire(GetTestAudioParameters(), client.MakeProviderClientPtr());
+ provider->Acquire(GetTestAudioParameters(), client.MakeProviderClientPtr(),
+ base::nullopt);
base::RunLoop().RunUntilIdle();
ASSERT_NE(event_handler, nullptr);
EXPECT_FALSE(delegate_is_destructed);
diff --git a/chromium/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.cc b/chromium/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.cc
index a07394101ea..d4d96fb5bfe 100644
--- a/chromium/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.cc
+++ b/chromium/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.cc
@@ -90,7 +90,8 @@ void RenderFrameAudioInputStreamFactory::CreateStream(
int32_t session_id,
const media::AudioParameters& audio_params,
bool automatic_gain_control,
- uint32_t shared_memory_count) {
+ uint32_t shared_memory_count,
+ audio::mojom::AudioProcessingConfigPtr processing_config) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
TRACE_EVENT_INSTANT1("audio",
"RenderFrameAudioInputStreamFactory::CreateStream",
@@ -105,7 +106,7 @@ void RenderFrameAudioInputStreamFactory::CreateStream(
CreateStreamAfterLookingUpDevice,
weak_ptr_factory_.GetWeakPtr(), std::move(client),
audio_params, automatic_gain_control,
- shared_memory_count)));
+ shared_memory_count, std::move(processing_config))));
}
void RenderFrameAudioInputStreamFactory::CreateStreamAfterLookingUpDevice(
@@ -113,6 +114,7 @@ void RenderFrameAudioInputStreamFactory::CreateStreamAfterLookingUpDevice(
const media::AudioParameters& audio_params,
bool automatic_gain_control,
uint32_t shared_memory_count,
+ audio::mojom::AudioProcessingConfigPtr processing_config,
const MediaStreamDevice& device) {
TRACE_EVENT1(
"audio",
@@ -126,9 +128,9 @@ void RenderFrameAudioInputStreamFactory::CreateStreamAfterLookingUpDevice(
WebContentsMediaCaptureId capture_id;
if (WebContentsMediaCaptureId::Parse(device.id, &capture_id)) {
- // For MEDIA_DESKTOP_AUDIO_CAPTURE, the source is selected from picker
- // window, we do not mute the source audio.
- // For MEDIA_TAB_AUDIO_CAPTURE, the probable use case is Cast, we mute
+ // For MEDIA_GUM_DESKTOP_AUDIO_CAPTURE, the source is selected from
+ // picker window, we do not mute the source audio. For
+ // MEDIA_GUM_TAB_AUDIO_CAPTURE, the probable use case is Cast, we mute
// the source audio.
// TODO(qiangchen): Analyze audio constraints to make a duplicating or
// diverting decision. It would give web developer more flexibility.
@@ -144,16 +146,16 @@ void RenderFrameAudioInputStreamFactory::CreateStreamAfterLookingUpDevice(
render_frame_host_, source_host, audio_params, shared_memory_count,
capture_id.disable_local_echo, std::move(client));
- if (device.type == MEDIA_DESKTOP_AUDIO_CAPTURE)
+ if (device.type == MEDIA_GUM_DESKTOP_AUDIO_CAPTURE)
IncrementDesktopCaptureCounter(SYSTEM_LOOPBACK_AUDIO_CAPTURER_CREATED);
} else {
factory->CreateInputStream(render_frame_host_, device.id, audio_params,
shared_memory_count, automatic_gain_control,
- std::move(client));
+ std::move(processing_config), std::move(client));
// Only count for captures from desktop media picker dialog and system loop
// back audio.
- if (device.type == MEDIA_DESKTOP_AUDIO_CAPTURE &&
+ if (device.type == MEDIA_GUM_DESKTOP_AUDIO_CAPTURE &&
(media::AudioDeviceDescription::IsLoopbackDevice(device.id))) {
IncrementDesktopCaptureCounter(SYSTEM_LOOPBACK_AUDIO_CAPTURER_CREATED);
}
diff --git a/chromium/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h b/chromium/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h
index a4597568026..49ec1176c36 100644
--- a/chromium/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h
+++ b/chromium/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h
@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_RENDER_FRAME_AUDIO_INPUT_STREAM_FACTORY_H_
#include <cstdint>
+#include <string>
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
@@ -41,17 +42,20 @@ class CONTENT_EXPORT RenderFrameAudioInputStreamFactory
private:
// mojom::RendererAudioInputStreamFactory implementation.
- void CreateStream(mojom::RendererAudioInputStreamFactoryClientPtr client,
- int32_t session_id,
- const media::AudioParameters& audio_params,
- bool automatic_gain_control,
- uint32_t shared_memory_count) override;
+ void CreateStream(
+ mojom::RendererAudioInputStreamFactoryClientPtr client,
+ int32_t session_id,
+ const media::AudioParameters& audio_params,
+ bool automatic_gain_control,
+ uint32_t shared_memory_count,
+ audio::mojom::AudioProcessingConfigPtr processing_config) override;
void CreateStreamAfterLookingUpDevice(
mojom::RendererAudioInputStreamFactoryClientPtr client,
const media::AudioParameters& audio_params,
bool automatic_gain_control,
uint32_t shared_memory_count,
+ audio::mojom::AudioProcessingConfigPtr processing_config,
const MediaStreamDevice& device);
void AssociateInputAndOutputForAec(
diff --git a/chromium/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc b/chromium/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc
index 0a78c678b37..a5ae3806e45 100644
--- a/chromium/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc
@@ -100,6 +100,7 @@ class RenderFrameAudioInputStreamFactoryTest
uint32_t shared_memory_count,
bool enable_agc,
mojo::ScopedSharedBufferHandle key_press_count_buffer,
+ audio::mojom::AudioProcessingConfigPtr processing_config,
CreateInputStreamCallback created_callback) override {
last_created_callback = std::move(created_callback);
}
@@ -198,7 +199,7 @@ TEST_F(RenderFrameAudioInputStreamFactoryTest,
mojom::RendererAudioInputStreamFactoryClientPtr client;
mojo::MakeRequest(&client);
factory_ptr->CreateStream(std::move(client), session_id, kParams, kAGC,
- kSharedMemoryCount);
+ kSharedMemoryCount, nullptr);
base::RunLoop().RunUntilIdle();
@@ -217,13 +218,13 @@ TEST_F(RenderFrameAudioInputStreamFactoryTest,
WebContentsMediaCaptureId capture_id(main_frame->GetProcess()->GetID(),
main_frame->GetRoutingID());
int session_id = audio_input_device_manager()->Open(MediaStreamDevice(
- MEDIA_TAB_AUDIO_CAPTURE, capture_id.ToString(), kDeviceName));
+ MEDIA_GUM_TAB_AUDIO_CAPTURE, capture_id.ToString(), kDeviceName));
base::RunLoop().RunUntilIdle();
mojom::RendererAudioInputStreamFactoryClientPtr client;
mojo::MakeRequest(&client);
factory_ptr->CreateStream(std::move(client), session_id, kParams, kAGC,
- kSharedMemoryCount);
+ kSharedMemoryCount, nullptr);
base::RunLoop().RunUntilIdle();
@@ -242,14 +243,14 @@ TEST_F(RenderFrameAudioInputStreamFactoryTest,
WebContentsMediaCaptureId capture_id(main_frame->GetProcess()->GetID(),
main_frame->GetRoutingID());
int session_id = audio_input_device_manager()->Open(MediaStreamDevice(
- MEDIA_TAB_AUDIO_CAPTURE, capture_id.ToString(), kDeviceName));
+ MEDIA_GUM_TAB_AUDIO_CAPTURE, capture_id.ToString(), kDeviceName));
base::RunLoop().RunUntilIdle();
source_contents.reset();
mojom::RendererAudioInputStreamFactoryClientPtr client;
mojo::MakeRequest(&client);
factory_ptr->CreateStream(std::move(client), session_id, kParams, kAGC,
- kSharedMemoryCount);
+ kSharedMemoryCount, nullptr);
base::RunLoop().RunUntilIdle();
@@ -268,7 +269,7 @@ TEST_F(RenderFrameAudioInputStreamFactoryTest,
mojo::MakeRequest(&client);
factory_ptr->CreateStream(std::move(client), session_id, kParams, kAGC,
- kSharedMemoryCount);
+ kSharedMemoryCount, nullptr);
base::RunLoop().RunUntilIdle();
diff --git a/chromium/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc b/chromium/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc
index 00642ad3fe9..dadd1cdd502 100644
--- a/chromium/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc
+++ b/chromium/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc
@@ -37,7 +37,8 @@ class RenderFrameAudioOutputStreamFactory::ProviderImpl final
void Acquire(
const media::AudioParameters& params,
- media::mojom::AudioOutputStreamProviderClientPtr provider_client) final {
+ media::mojom::AudioOutputStreamProviderClientPtr provider_client,
+ const base::Optional<base::UnguessableToken>& processing_id) final {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
TRACE_EVENT1("audio",
"RenderFrameAudioOutputStreamFactory::ProviderImpl::Acquire",
@@ -50,7 +51,7 @@ class RenderFrameAudioOutputStreamFactory::ProviderImpl final
// It's possible that |frame| has already been destroyed, in which case we
// don't need to create a stream. In this case, the renderer will get a
// connection error since |provider_client| is dropped.
- factory->CreateOutputStream(frame, device_id_, params,
+ factory->CreateOutputStream(frame, device_id_, params, processing_id,
std::move(provider_client));
}
diff --git a/chromium/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc b/chromium/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc
index 837204a6d62..ed17a87080b 100644
--- a/chromium/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc
@@ -100,6 +100,7 @@ class RenderFrameAudioOutputStreamFactoryTest
const std::string& output_device_id,
const media::AudioParameters& params,
const base::UnguessableToken& group_id,
+ const base::Optional<base::UnguessableToken>& processing_id,
CreateOutputStreamCallback created_callback) override {
last_created_callback = std::move(created_callback);
}
@@ -214,7 +215,7 @@ TEST_F(RenderFrameAudioOutputStreamFactoryTest,
{
media::mojom::AudioOutputStreamProviderClientPtr client;
mojo::MakeRequest(&client);
- provider_ptr->Acquire(kParams, std::move(client));
+ provider_ptr->Acquire(kParams, std::move(client), base::nullopt);
}
audio::mojom::StreamFactory::CreateOutputStreamCallback created_callback;
@@ -251,7 +252,7 @@ TEST_F(RenderFrameAudioOutputStreamFactoryTest,
{
media::mojom::AudioOutputStreamProviderClientPtr client;
mojo::MakeRequest(&client);
- provider_ptr->Acquire(kParams, std::move(client));
+ provider_ptr->Acquire(kParams, std::move(client), base::nullopt);
}
base::RunLoop().RunUntilIdle();
diff --git a/chromium/content/browser/renderer_host/media/service_video_capture_device_launcher.cc b/chromium/content/browser/renderer_host/media/service_video_capture_device_launcher.cc
index c2bf65e7950..07e01aaabe7 100644
--- a/chromium/content/browser/renderer_host/media/service_video_capture_device_launcher.cc
+++ b/chromium/content/browser/renderer_host/media/service_video_capture_device_launcher.cc
@@ -38,6 +38,7 @@ void ConcludeLaunchDeviceWithSuccess(
void ConcludeLaunchDeviceWithFailure(
bool abort_requested,
+ media::VideoCaptureError error,
std::unique_ptr<VideoCaptureFactoryDelegate> device_factory,
VideoCaptureDeviceLauncher::Callbacks* callbacks,
base::OnceClosure done_cb) {
@@ -45,7 +46,7 @@ void ConcludeLaunchDeviceWithFailure(
if (abort_requested)
callbacks->OnDeviceLaunchAborted();
else
- callbacks->OnDeviceLaunchFailed();
+ callbacks->OnDeviceLaunchFailed(error);
base::ResetAndReturn(&done_cb).Run();
}
@@ -84,8 +85,11 @@ void ServiceVideoCaptureDeviceLauncher::LaunchDeviceAsync(
// This can happen when the ServiceVideoCaptureProvider owning
// |device_factory_| loses connection to the service process and resets
// |device_factory_|.
- ConcludeLaunchDeviceWithFailure(false, std::move(device_factory_),
- callbacks, std::move(done_cb));
+ ConcludeLaunchDeviceWithFailure(
+ false,
+ media::VideoCaptureError::
+ kServiceDeviceLauncherLostConnectionToDeviceFactoryDuringDeviceStart,
+ std::move(device_factory_), callbacks, std::move(done_cb));
return;
}
@@ -157,9 +161,11 @@ void ServiceVideoCaptureDeviceLauncher::OnCreateDeviceCallback(
return;
case video_capture::mojom::DeviceAccessResultCode::ERROR_DEVICE_NOT_FOUND:
case video_capture::mojom::DeviceAccessResultCode::NOT_INITIALIZED:
- ConcludeLaunchDeviceWithFailure(abort_requested,
- std::move(device_factory_), callbacks,
- std::move(done_cb_));
+ ConcludeLaunchDeviceWithFailure(
+ abort_requested,
+ media::VideoCaptureError::
+ kServiceDeviceLauncherServiceRespondedWithDeviceNotFound,
+ std::move(device_factory_), callbacks, std::move(done_cb_));
return;
}
}
@@ -172,8 +178,11 @@ void ServiceVideoCaptureDeviceLauncher::
state_ = State::READY_TO_LAUNCH;
Callbacks* callbacks = callbacks_;
callbacks_ = nullptr;
- ConcludeLaunchDeviceWithFailure(abort_requested, std::move(device_factory_),
- callbacks, std::move(done_cb_));
+ ConcludeLaunchDeviceWithFailure(
+ abort_requested,
+ media::VideoCaptureError::
+ kServiceDeviceLauncherConnectionLostWhileWaitingForCallback,
+ std::move(device_factory_), callbacks, std::move(done_cb_));
}
} // namespace content
diff --git a/chromium/content/browser/renderer_host/media/service_video_capture_device_launcher_unittest.cc b/chromium/content/browser/renderer_host/media/service_video_capture_device_launcher_unittest.cc
index 2c04a18d030..37c732611ce 100644
--- a/chromium/content/browser/renderer_host/media/service_video_capture_device_launcher_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/service_video_capture_device_launcher_unittest.cc
@@ -74,7 +74,7 @@ class MockVideoCaptureDeviceLauncherCallbacks
MOCK_METHOD1(DoOnDeviceLaunched,
void(std::unique_ptr<LaunchedVideoCaptureDevice>* device));
- MOCK_METHOD0(OnDeviceLaunchFailed, void());
+ MOCK_METHOD1(OnDeviceLaunchFailed, void(media::VideoCaptureError error));
MOCK_METHOD0(OnDeviceLaunchAborted, void());
};
@@ -157,7 +157,7 @@ TEST_F(ServiceVideoCaptureDeviceLauncherTest, LaunchingDeviceSucceeds) {
EXPECT_CALL(mock_callbacks_, DoOnDeviceLaunched(_)).Times(1);
EXPECT_CALL(mock_callbacks_, OnDeviceLaunchAborted()).Times(0);
- EXPECT_CALL(mock_callbacks_, OnDeviceLaunchFailed()).Times(0);
+ EXPECT_CALL(mock_callbacks_, OnDeviceLaunchFailed(_)).Times(0);
EXPECT_CALL(connection_lost_cb_, Run()).Times(0);
base::RunLoop wait_for_done_cb;
EXPECT_CALL(done_cb_, Run())
@@ -224,7 +224,7 @@ void ServiceVideoCaptureDeviceLauncherTest::RunLaunchingDeviceIsAbortedTest(
}));
EXPECT_CALL(mock_callbacks_, DoOnDeviceLaunched(_)).Times(0);
EXPECT_CALL(mock_callbacks_, OnDeviceLaunchAborted()).Times(1);
- EXPECT_CALL(mock_callbacks_, OnDeviceLaunchFailed()).Times(0);
+ EXPECT_CALL(mock_callbacks_, OnDeviceLaunchFailed(_)).Times(0);
EXPECT_CALL(connection_lost_cb_, Run()).Times(0);
EXPECT_CALL(done_cb_, Run()).WillOnce(InvokeWithoutArgs([&step_2_run_loop]() {
step_2_run_loop.Quit();
@@ -272,7 +272,11 @@ TEST_F(ServiceVideoCaptureDeviceLauncherTest,
}));
EXPECT_CALL(mock_callbacks_, DoOnDeviceLaunched(_)).Times(0);
EXPECT_CALL(mock_callbacks_, OnDeviceLaunchAborted()).Times(0);
- EXPECT_CALL(mock_callbacks_, OnDeviceLaunchFailed()).Times(1);
+ EXPECT_CALL(mock_callbacks_,
+ OnDeviceLaunchFailed(
+ media::VideoCaptureError::
+ kServiceDeviceLauncherServiceRespondedWithDeviceNotFound))
+ .Times(1);
EXPECT_CALL(connection_lost_cb_, Run()).Times(0);
EXPECT_CALL(done_cb_, Run()).WillOnce(InvokeWithoutArgs([&run_loop]() {
run_loop.Quit();
@@ -292,7 +296,7 @@ TEST_F(ServiceVideoCaptureDeviceLauncherTest,
EXPECT_CALL(mock_callbacks_, DoOnDeviceLaunched(_)).Times(0);
EXPECT_CALL(mock_callbacks_, OnDeviceLaunchAborted()).Times(0);
- EXPECT_CALL(mock_callbacks_, OnDeviceLaunchFailed()).Times(1);
+ EXPECT_CALL(mock_callbacks_, OnDeviceLaunchFailed(_)).Times(1);
EXPECT_CALL(connection_lost_cb_, Run()).Times(0);
EXPECT_CALL(done_cb_, Run()).WillOnce(InvokeWithoutArgs([&run_loop]() {
run_loop.Quit();
@@ -327,7 +331,7 @@ TEST_F(ServiceVideoCaptureDeviceLauncherTest,
}));
EXPECT_CALL(mock_callbacks_, DoOnDeviceLaunched(_)).Times(0);
EXPECT_CALL(mock_callbacks_, OnDeviceLaunchAborted()).Times(0);
- EXPECT_CALL(mock_callbacks_, OnDeviceLaunchFailed()).Times(1);
+ EXPECT_CALL(mock_callbacks_, OnDeviceLaunchFailed(_)).Times(1);
// Note: |connection_lost_cb_| is only meant to be called when the connection
// to a successfully-launched device is lost, which is not the case here.
EXPECT_CALL(connection_lost_cb_, Run()).Times(0);
diff --git a/chromium/content/browser/renderer_host/media/service_video_capture_provider.cc b/chromium/content/browser/renderer_host/media/service_video_capture_provider.cc
index 52ae899701f..34445f23d22 100644
--- a/chromium/content/browser/renderer_host/media/service_video_capture_provider.cc
+++ b/chromium/content/browser/renderer_host/media/service_video_capture_provider.cc
@@ -4,7 +4,6 @@
#include "content/browser/renderer_host/media/service_video_capture_provider.h"
-#include "content/browser/gpu/gpu_client_impl.h"
#include "content/browser/renderer_host/media/service_video_capture_device_launcher.h"
#include "content/browser/renderer_host/media/video_capture_dependencies.h"
#include "content/browser/renderer_host/media/video_capture_factory_delegate.h"
diff --git a/chromium/content/browser/renderer_host/media/service_video_capture_provider.h b/chromium/content/browser/renderer_host/media/service_video_capture_provider.h
index 7cc051d35af..c1b58b70dc3 100644
--- a/chromium/content/browser/renderer_host/media/service_video_capture_provider.h
+++ b/chromium/content/browser/renderer_host/media/service_video_capture_provider.h
@@ -33,11 +33,11 @@ class CONTENT_EXPORT ServiceVideoCaptureProvider : public VideoCaptureProvider {
// This constructor creates a default ServiceConnector which
// uses the ServiceManager associated with the current process to connect
// to the video capture service. It uses a default factory for instances of
- // ui::mojom::Gpu which produces instances of class content::GpuClient.
+ // ws::mojom::Gpu which produces instances of class content::GpuClient.
explicit ServiceVideoCaptureProvider(
base::RepeatingCallback<void(const std::string&)> emit_log_message_cb);
// Lets clients provide a custom ServiceConnector and factory method for
- // creating instances of ui::mojom::Gpu.
+ // creating instances of ws::mojom::Gpu.
ServiceVideoCaptureProvider(
std::unique_ptr<ServiceConnector> service_connector,
CreateAcceleratorFactoryCallback create_accelerator_factory_cb,
diff --git a/chromium/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc b/chromium/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc
index b080b096ec5..0b5aecf53b7 100644
--- a/chromium/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc
@@ -103,7 +103,7 @@ class MockVideoCaptureDeviceLauncherCallbacks
MOCK_METHOD1(DoOnDeviceLaunched,
void(std::unique_ptr<LaunchedVideoCaptureDevice>* device));
- MOCK_METHOD0(OnDeviceLaunchFailed, void());
+ MOCK_METHOD1(OnDeviceLaunchFailed, void(media::VideoCaptureError error));
MOCK_METHOD0(OnDeviceLaunchAborted, void());
};
diff --git a/chromium/content/browser/renderer_host/media/video_capture_browsertest.cc b/chromium/content/browser/renderer_host/media/video_capture_browsertest.cc
index ee5dd193529..7306b1ee393 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_browsertest.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_browsertest.cc
@@ -48,7 +48,8 @@ class MockVideoCaptureControllerEventHandler
const media::mojom::VideoFrameInfoPtr& frame_info));
MOCK_METHOD1(OnStarted, void(VideoCaptureControllerID));
MOCK_METHOD1(OnEnded, void(VideoCaptureControllerID));
- MOCK_METHOD1(OnError, void(VideoCaptureControllerID));
+ MOCK_METHOD2(OnError,
+ void(VideoCaptureControllerID, media::VideoCaptureError));
MOCK_METHOD1(OnStartedUsingGpuDecode, void(VideoCaptureControllerID));
MOCK_METHOD1(OnStoppedUsingGpuDecode, void(VideoCaptureControllerID));
@@ -148,7 +149,7 @@ class VideoCaptureBrowserTest : public ContentBrowserTest,
video_capture_manager_->DisconnectClient(controller_.get(), stub_client_id_,
&mock_controller_event_handler_,
- false);
+ media::VideoCaptureError::kNone);
EXPECT_CALL(mock_stream_provider_listener_, Closed(_, _))
.WillOnce(InvokeWithoutArgs([continuation]() { continuation.Run(); }));
diff --git a/chromium/content/browser/renderer_host/media/video_capture_controller.cc b/chromium/content/browser/renderer_host/media/video_capture_controller.cc
index 4a948b2c47f..b964d0e82f9 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_controller.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_controller.cc
@@ -15,7 +15,6 @@
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "build/build_config.h"
-#include "components/viz/common/gl_helper.h"
#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/browser/renderer_host/media/video_capture_manager.h"
#include "content/public/browser/browser_thread.h"
@@ -48,9 +47,23 @@ static const int kInfiniteRatio = 99999;
base::UmaHistogramSparse( \
name, (height) ? ((width)*100) / (height) : kInfiniteRatio);
-void CallOnError(VideoCaptureControllerEventHandler* client,
+void LogVideoFrameDrop(media::VideoCaptureFrameDropReason reason) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Media.VideoCapture.FrameDrop", reason,
+ static_cast<int>(media::VideoCaptureFrameDropReason::kMaxValue) + 1);
+}
+
+void LogMaxConsecutiveVideoFrameDropCountExceeded(
+ media::VideoCaptureFrameDropReason reason) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Media.VideoCapture.MaxFrameDropExceeded", reason,
+ static_cast<int>(media::VideoCaptureFrameDropReason::kMaxValue) + 1);
+}
+
+void CallOnError(media::VideoCaptureError error,
+ VideoCaptureControllerEventHandler* client,
VideoCaptureControllerID id) {
- client->OnError(id);
+ client->OnError(id, error);
}
void CallOnStarted(VideoCaptureControllerEventHandler* client,
@@ -174,6 +187,9 @@ VideoCaptureController::BufferContext::CloneBufferHandle() {
result->set_shared_buffer_handle(
buffer_handle_->get_shared_buffer_handle()->Clone(
mojo::SharedBufferHandle::AccessMode::READ_WRITE));
+ } else if (buffer_handle_->is_read_only_shmem_region()) {
+ result->set_read_only_shmem_region(
+ buffer_handle_->get_read_only_shmem_region().Duplicate());
} else if (buffer_handle_->is_mailbox_handles()) {
result->set_mailbox_handles(buffer_handle_->get_mailbox_handles()->Clone());
} else {
@@ -182,6 +198,12 @@ VideoCaptureController::BufferContext::CloneBufferHandle() {
return result;
}
+VideoCaptureController::FrameDropLogState::FrameDropLogState(
+ media::VideoCaptureFrameDropReason reason)
+ : drop_count((reason == media::VideoCaptureFrameDropReason::kNone) ? 0 : 1),
+ drop_reason(reason),
+ max_log_count_exceeded(false) {}
+
VideoCaptureController::VideoCaptureController(
const std::string& device_id,
MediaStreamType stream_type,
@@ -231,7 +253,10 @@ void VideoCaptureController::AddClient(
// invalid or unsupported parameters.
LOG(DFATAL) << "Invalid or unsupported video capture parameters requested: "
<< media::VideoCaptureFormat::ToString(params.requested_format);
- event_handler->OnError(id);
+ event_handler->OnError(
+ id,
+ media::VideoCaptureError::
+ kVideoCaptureControllerInvalidOrUnsupportedVideoCaptureParametersRequested);
return;
}
@@ -241,7 +266,9 @@ void VideoCaptureController::AddClient(
// Signal error in case device is already in error state.
if (state_ == VIDEO_CAPTURE_STATE_ERROR) {
- event_handler->OnError(id);
+ event_handler->OnError(
+ id,
+ media::VideoCaptureError::kVideoCaptureControllerIsAlreadyInErrorState);
return;
}
@@ -417,6 +444,8 @@ void VideoCaptureController::OnFrameReadyInBuffer(
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_NE(buffer_id, media::VideoCaptureBufferPool::kInvalidId);
+ frame_drop_log_state_ = FrameDropLogState();
+
auto buffer_context_iter = FindUnretiredBufferContextFromBufferId(buffer_id);
DCHECK(buffer_context_iter != buffer_contexts_.end());
buffer_context_iter->set_frame_feedback_id(frame_feedback_id);
@@ -496,10 +525,39 @@ void VideoCaptureController::OnBufferRetired(int buffer_id) {
buffer_context_iter->set_is_retired();
}
-void VideoCaptureController::OnError() {
+void VideoCaptureController::OnError(media::VideoCaptureError error) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
state_ = VIDEO_CAPTURE_STATE_ERROR;
- PerformForClientsWithOpenSession(base::Bind(&CallOnError));
+ PerformForClientsWithOpenSession(base::BindRepeating(&CallOnError, error));
+}
+
+void VideoCaptureController::OnFrameDropped(
+ media::VideoCaptureFrameDropReason reason) {
+ if (reason == frame_drop_log_state_.drop_reason) {
+ if (frame_drop_log_state_.max_log_count_exceeded)
+ return;
+
+ if (++frame_drop_log_state_.drop_count >
+ kMaxConsecutiveFrameDropForSameReasonCount) {
+ frame_drop_log_state_.max_log_count_exceeded = true;
+ LogMaxConsecutiveVideoFrameDropCountExceeded(reason);
+ std::ostringstream string_stream;
+ string_stream << "Too many consecutive frames dropped with reason code "
+ << static_cast<int>(reason)
+ << ". Stopping to log dropped frames for this reason in "
+ "order to avoid log spam.";
+ EmitLogMessage(string_stream.str(), 1);
+ return;
+ }
+ } else {
+ frame_drop_log_state_ = FrameDropLogState(reason);
+ }
+
+ LogVideoFrameDrop(reason);
+ std::ostringstream string_stream;
+ string_stream << "Frame dropped with reason code "
+ << static_cast<int>(reason);
+ EmitLogMessage(string_stream.str(), 1);
}
void VideoCaptureController::OnLog(const std::string& message) {
@@ -510,13 +568,14 @@ void VideoCaptureController::OnLog(const std::string& message) {
void VideoCaptureController::OnStarted() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
state_ = VIDEO_CAPTURE_STATE_STARTED;
- PerformForClientsWithOpenSession(base::Bind(&CallOnStarted));
+ PerformForClientsWithOpenSession(base::BindRepeating(&CallOnStarted));
}
void VideoCaptureController::OnStartedUsingGpuDecode() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
OnLog("StartedUsingGpuDecode");
- PerformForClientsWithOpenSession(base::Bind(&CallOnStartedUsingGpuDecode));
+ PerformForClientsWithOpenSession(
+ base::BindRepeating(&CallOnStartedUsingGpuDecode));
}
void VideoCaptureController::OnDeviceLaunched(
@@ -530,10 +589,11 @@ void VideoCaptureController::OnDeviceLaunched(
}
}
-void VideoCaptureController::OnDeviceLaunchFailed() {
+void VideoCaptureController::OnDeviceLaunchFailed(
+ media::VideoCaptureError error) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (device_launch_observer_) {
- device_launch_observer_->OnDeviceLaunchFailed(this);
+ device_launch_observer_->OnDeviceLaunchFailed(this, error);
device_launch_observer_ = nullptr;
}
}
diff --git a/chromium/content/browser/renderer_host/media/video_capture_controller.h b/chromium/content/browser/renderer_host/media/video_capture_controller.h
index 62c39fa7901..9179ecde427 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_controller.h
+++ b/chromium/content/browser/renderer_host/media/video_capture_controller.h
@@ -48,6 +48,11 @@ class CONTENT_EXPORT VideoCaptureController
std::unique_ptr<VideoCaptureDeviceLauncher> device_launcher,
base::RepeatingCallback<void(const std::string&)> emit_log_message_cb);
+ // Warning: This value should not be changed, because doing so would change
+ // the meaning of logged UMA events for histograms Media.VideoCapture.Error
+ // and Media.VideoCapture.MaxFrameDropExceeded.
+ static constexpr int kMaxConsecutiveFrameDropForSameReasonCount = 10;
+
base::WeakPtr<VideoCaptureController> GetWeakPtrForIOThread();
// Start video capturing and try to use the resolution specified in |params|.
@@ -109,7 +114,8 @@ class CONTENT_EXPORT VideoCaptureController
buffer_read_permission,
media::mojom::VideoFrameInfoPtr frame_info) override;
void OnBufferRetired(int buffer_id) override;
- void OnError() override;
+ void OnError(media::VideoCaptureError error) override;
+ void OnFrameDropped(media::VideoCaptureFrameDropReason reason) override;
void OnLog(const std::string& message) override;
void OnStarted() override;
void OnStartedUsingGpuDecode() override;
@@ -117,7 +123,7 @@ class CONTENT_EXPORT VideoCaptureController
// Implementation of VideoCaptureDeviceLauncher::Callbacks interface:
void OnDeviceLaunched(
std::unique_ptr<LaunchedVideoCaptureDevice> device) override;
- void OnDeviceLaunchFailed() override;
+ void OnDeviceLaunchFailed(media::VideoCaptureError error) override;
void OnDeviceLaunchAborted() override;
void OnDeviceConnectionLost();
@@ -196,6 +202,16 @@ class CONTENT_EXPORT VideoCaptureController
buffer_read_permission_;
};
+ struct FrameDropLogState {
+ FrameDropLogState(media::VideoCaptureFrameDropReason reason =
+ media::VideoCaptureFrameDropReason::kNone);
+
+ int drop_count = 0;
+ media::VideoCaptureFrameDropReason drop_reason =
+ media::VideoCaptureFrameDropReason::kNone;
+ bool max_log_count_exceeded = false;
+ };
+
~VideoCaptureController() override;
// Find a client of |id| and |handler| in |clients|.
@@ -219,8 +235,8 @@ class CONTENT_EXPORT VideoCaptureController
const std::vector<BufferContext>::iterator& buffer_state_iter);
using EventHandlerAction =
- base::Callback<void(VideoCaptureControllerEventHandler* client,
- VideoCaptureControllerID id)>;
+ base::RepeatingCallback<void(VideoCaptureControllerEventHandler* client,
+ VideoCaptureControllerID id)>;
void PerformForClientsWithOpenSession(EventHandlerAction action);
void EmitLogMessage(const std::string& message, int verbose_log_level);
@@ -243,6 +259,8 @@ class CONTENT_EXPORT VideoCaptureController
// absorbing state which stops the flow of data to clients.
VideoCaptureState state_;
+ FrameDropLogState frame_drop_log_state_;
+
int next_buffer_context_id_ = 0;
// True if the controller has received a video frame from the device.
diff --git a/chromium/content/browser/renderer_host/media/video_capture_controller_event_handler.h b/chromium/content/browser/renderer_host/media/video_capture_controller_event_handler.h
index 4cac4888331..a2564afb998 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_controller_event_handler.h
+++ b/chromium/content/browser/renderer_host/media/video_capture_controller_event_handler.h
@@ -33,7 +33,8 @@ typedef int VideoCaptureControllerID;
class CONTENT_EXPORT VideoCaptureControllerEventHandler {
public:
// An Error has occurred in the VideoCaptureDevice.
- virtual void OnError(VideoCaptureControllerID id) = 0;
+ virtual void OnError(VideoCaptureControllerID id,
+ media::VideoCaptureError error) = 0;
virtual void OnNewBuffer(VideoCaptureControllerID id,
media::mojom::VideoBufferHandlePtr buffer_handle,
diff --git a/chromium/content/browser/renderer_host/media/video_capture_controller_unittest.cc b/chromium/content/browser/renderer_host/media/video_capture_controller_unittest.cc
index a9ae13311f3..a5af5ca6252 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_controller_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_controller_unittest.cc
@@ -10,6 +10,7 @@
#include <memory>
#include <string>
#include <utility>
+#include "base/metrics/histogram_macros.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
@@ -18,6 +19,7 @@
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
+#include "base/test/metrics/histogram_tester.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/browser/renderer_host/media/media_stream_provider.h"
#include "content/browser/renderer_host/media/mock_video_capture_provider.h"
@@ -62,11 +64,15 @@ class MockVideoCaptureControllerEventHandler
void(VideoCaptureControllerID, int buffer_id));
MOCK_METHOD2(DoBufferReady, void(VideoCaptureControllerID, const gfx::Size&));
MOCK_METHOD1(DoEnded, void(VideoCaptureControllerID));
- MOCK_METHOD1(DoError, void(VideoCaptureControllerID));
+ MOCK_METHOD2(DoError,
+ void(VideoCaptureControllerID, media::VideoCaptureError));
MOCK_METHOD1(OnStarted, void(VideoCaptureControllerID));
MOCK_METHOD1(OnStartedUsingGpuDecode, void(VideoCaptureControllerID));
- void OnError(VideoCaptureControllerID id) override { DoError(id); }
+ void OnError(VideoCaptureControllerID id,
+ media::VideoCaptureError error) override {
+ DoError(id, error);
+ }
void OnNewBuffer(VideoCaptureControllerID id,
media::mojom::VideoBufferHandlePtr buffer_handle,
int length,
@@ -513,14 +519,24 @@ TEST_F(VideoCaptureControllerTest, ErrorBeforeDeviceCreation) {
// Start with one client.
controller_->AddClient(route_id, client_a_.get(), 100, session_100);
- device_client_->OnError(FROM_HERE, "Test Error");
- EXPECT_CALL(*client_a_, DoError(route_id)).Times(1);
+ device_client_->OnError(
+ media::VideoCaptureError::kIntentionalErrorRaisedByUnitTest, FROM_HERE,
+ "Test Error");
+ EXPECT_CALL(
+ *client_a_,
+ DoError(route_id,
+ media::VideoCaptureError::kIntentionalErrorRaisedByUnitTest))
+ .Times(1);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(client_a_.get());
// Second client connects after the error state. It also should get told of
// the error.
- EXPECT_CALL(*client_b_, DoError(route_id)).Times(1);
+ EXPECT_CALL(
+ *client_b_,
+ DoError(route_id, media::VideoCaptureError::
+ kVideoCaptureControllerIsAlreadyInErrorState))
+ .Times(1);
controller_->AddClient(route_id, client_b_.get(), 200, session_200);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(client_b_.get());
@@ -568,18 +584,28 @@ TEST_F(VideoCaptureControllerTest, ErrorAfterDeviceCreation) {
arbitrary_frame_feedback_id);
ASSERT_TRUE(buffer.is_valid());
- device_client_->OnError(FROM_HERE, "Test Error");
+ device_client_->OnError(
+ media::VideoCaptureError::kIntentionalErrorRaisedByUnitTest, FROM_HERE,
+ "Test Error");
device_client_->OnIncomingCapturedBuffer(std::move(buffer), device_format,
arbitrary_reference_time_,
arbitrary_timestamp_);
- EXPECT_CALL(*client_a_, DoError(route_id)).Times(1);
+ EXPECT_CALL(
+ *client_a_,
+ DoError(route_id,
+ media::VideoCaptureError::kIntentionalErrorRaisedByUnitTest))
+ .Times(1);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(client_a_.get());
// Second client connects after the error state. It also should get told of
// the error.
- EXPECT_CALL(*client_b_, DoError(route_id)).Times(1);
+ EXPECT_CALL(
+ *client_b_,
+ DoError(route_id, media::VideoCaptureError::
+ kVideoCaptureControllerIsAlreadyInErrorState))
+ .Times(1);
controller_->AddClient(route_id, client_b_.get(), 200, session_200);
Mock::VerifyAndClearExpectations(client_b_.get());
}
@@ -828,4 +854,140 @@ TEST_F(VideoCaptureControllerTest, OnStartedForMultipleClients) {
controller_->AddClient(client_a_route_2, client_a_.get(), 200, session_200);
}
}
+
+TEST_F(VideoCaptureControllerTest, DroppedFramesGetLoggedInUMA) {
+ base::HistogramTester histogram_tester;
+
+ controller_->OnFrameDropped(
+ media::VideoCaptureFrameDropReason::kDeviceClientFrameHasInvalidFormat);
+ controller_->OnFrameDropped(
+ media::VideoCaptureFrameDropReason::
+ kDeviceClientFailedToReserveBufferFromBufferPool);
+ controller_->OnFrameDropped(
+ media::VideoCaptureFrameDropReason::kDeviceClientFrameHasInvalidFormat);
+
+ histogram_tester.ExpectBucketCount(
+ "Media.VideoCapture.FrameDrop",
+ media::VideoCaptureFrameDropReason::kDeviceClientFrameHasInvalidFormat,
+ 2);
+ histogram_tester.ExpectBucketCount(
+ "Media.VideoCapture.FrameDrop",
+ media::VideoCaptureFrameDropReason::
+ kDeviceClientFailedToReserveBufferFromBufferPool,
+ 1);
+}
+
+// Tests that too many frames dropped for the same reason emits a special UMA
+// log and disables further logging
+TEST_F(VideoCaptureControllerTest,
+ DroppedFrameLoggingGetsDisabledIfTooManyConsecutiveDropsForSameReason) {
+ base::HistogramTester histogram_tester;
+
+ for (int i = 0;
+ i < VideoCaptureController::kMaxConsecutiveFrameDropForSameReasonCount;
+ i++) {
+ controller_->OnFrameDropped(
+ media::VideoCaptureFrameDropReason::kDeviceClientFrameHasInvalidFormat);
+ }
+ histogram_tester.ExpectBucketCount(
+ "Media.VideoCapture.FrameDrop",
+ media::VideoCaptureFrameDropReason::kDeviceClientFrameHasInvalidFormat,
+ VideoCaptureController::kMaxConsecutiveFrameDropForSameReasonCount);
+
+ // Add one more count after already having reached the max allowed.
+ // This should not get counted.
+ controller_->OnFrameDropped(
+ media::VideoCaptureFrameDropReason::kDeviceClientFrameHasInvalidFormat);
+ histogram_tester.ExpectBucketCount(
+ "Media.VideoCapture.FrameDrop",
+ media::VideoCaptureFrameDropReason::kDeviceClientFrameHasInvalidFormat,
+ VideoCaptureController::kMaxConsecutiveFrameDropForSameReasonCount);
+
+ histogram_tester.ExpectBucketCount(
+ "Media.VideoCapture.MaxFrameDropExceeded",
+ media::VideoCaptureFrameDropReason::kDeviceClientFrameHasInvalidFormat,
+ 1);
+}
+
+TEST_F(VideoCaptureControllerTest,
+ DeliveredFrameInBetweenDroppedFramesResetsCounter) {
+ base::HistogramTester histogram_tester;
+ for (int i = 0;
+ i <
+ VideoCaptureController::kMaxConsecutiveFrameDropForSameReasonCount - 1;
+ i++) {
+ controller_->OnFrameDropped(
+ media::VideoCaptureFrameDropReason::kDeviceClientFrameHasInvalidFormat);
+ }
+
+ SendStubFrameToDeviceClient(arbitrary_format_);
+ base::RunLoop().RunUntilIdle();
+
+ for (int i = 0;
+ i < VideoCaptureController::kMaxConsecutiveFrameDropForSameReasonCount;
+ i++) {
+ controller_->OnFrameDropped(
+ media::VideoCaptureFrameDropReason::kDeviceClientFrameHasInvalidFormat);
+ }
+ histogram_tester.ExpectBucketCount(
+ "Media.VideoCapture.FrameDrop",
+ media::VideoCaptureFrameDropReason::kDeviceClientFrameHasInvalidFormat,
+ 2 * VideoCaptureController::kMaxConsecutiveFrameDropForSameReasonCount -
+ 1);
+}
+
+TEST_F(VideoCaptureControllerTest, DeliveredFrameReenablesDroppedFrameLogging) {
+ base::HistogramTester histogram_tester;
+
+ // Drop enough frames to disable logging
+ for (int i = 0;
+ i <
+ VideoCaptureController::kMaxConsecutiveFrameDropForSameReasonCount + 1;
+ i++) {
+ controller_->OnFrameDropped(
+ media::VideoCaptureFrameDropReason::kDeviceClientFrameHasInvalidFormat);
+ }
+
+ SendStubFrameToDeviceClient(arbitrary_format_);
+ base::RunLoop().RunUntilIdle();
+
+ controller_->OnFrameDropped(
+ media::VideoCaptureFrameDropReason::kDeviceClientFrameHasInvalidFormat);
+ histogram_tester.ExpectBucketCount(
+ "Media.VideoCapture.FrameDrop",
+ media::VideoCaptureFrameDropReason::kDeviceClientFrameHasInvalidFormat,
+ VideoCaptureController::kMaxConsecutiveFrameDropForSameReasonCount + 1);
+}
+
+TEST_F(VideoCaptureControllerTest,
+ ChangeInDropReasonReenablesDroppedFrameLogging) {
+ base::HistogramTester histogram_tester;
+
+ // Drop enough frames to disable logging
+ for (int i = 0;
+ i <
+ VideoCaptureController::kMaxConsecutiveFrameDropForSameReasonCount + 1;
+ i++) {
+ controller_->OnFrameDropped(
+ media::VideoCaptureFrameDropReason::kDeviceClientFrameHasInvalidFormat);
+ }
+
+ // Drop for a different reason
+ controller_->OnFrameDropped(
+ media::VideoCaptureFrameDropReason::
+ kDeviceClientFailedToReserveBufferFromBufferPool);
+
+ controller_->OnFrameDropped(
+ media::VideoCaptureFrameDropReason::kDeviceClientFrameHasInvalidFormat);
+ histogram_tester.ExpectBucketCount(
+ "Media.VideoCapture.FrameDrop",
+ media::VideoCaptureFrameDropReason::kDeviceClientFrameHasInvalidFormat,
+ VideoCaptureController::kMaxConsecutiveFrameDropForSameReasonCount + 1);
+ histogram_tester.ExpectBucketCount(
+ "Media.VideoCapture.FrameDrop",
+ media::VideoCaptureFrameDropReason::
+ kDeviceClientFailedToReserveBufferFromBufferPool,
+ 1);
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/media/video_capture_device_launch_observer.h b/chromium/content/browser/renderer_host/media/video_capture_device_launch_observer.h
index 33e4b1bfea8..a0f492972b5 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_device_launch_observer.h
+++ b/chromium/content/browser/renderer_host/media/video_capture_device_launch_observer.h
@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_DEVICE_LAUNCH_OBSERVER_H_
#include "content/common/content_export.h"
+#include "media/capture/video_capture_types.h"
namespace content {
@@ -15,7 +16,8 @@ class CONTENT_EXPORT VideoCaptureDeviceLaunchObserver {
public:
virtual ~VideoCaptureDeviceLaunchObserver() {}
virtual void OnDeviceLaunched(VideoCaptureController* controller) = 0;
- virtual void OnDeviceLaunchFailed(VideoCaptureController* controller) = 0;
+ virtual void OnDeviceLaunchFailed(VideoCaptureController* controller,
+ media::VideoCaptureError error) = 0;
virtual void OnDeviceLaunchAborted() = 0;
virtual void OnDeviceConnectionLost(VideoCaptureController* controller) = 0;
};
diff --git a/chromium/content/browser/renderer_host/media/video_capture_host.cc b/chromium/content/browser/renderer_host/media/video_capture_host.cc
index 209d64c83db..d35e6a28544 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_host.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_host.cc
@@ -89,7 +89,8 @@ VideoCaptureHost::~VideoCaptureHost() {
if (controller) {
const VideoCaptureControllerID controller_id(it->first);
media_stream_manager_->video_capture_manager()->DisconnectClient(
- controller.get(), controller_id, this, false);
+ controller.get(), controller_id, this,
+ media::VideoCaptureError::kNone);
++it;
} else {
// Remove the entry for this controller_id so that when the controller
@@ -104,13 +105,14 @@ VideoCaptureHost::~VideoCaptureHost() {
render_process_host_delegate_.release());
}
-void VideoCaptureHost::OnError(VideoCaptureControllerID controller_id) {
+void VideoCaptureHost::OnError(VideoCaptureControllerID controller_id,
+ media::VideoCaptureError error) {
DVLOG(1) << __func__;
DCHECK_CURRENTLY_ON(BrowserThread::IO);
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::BindOnce(&VideoCaptureHost::DoError, weak_factory_.GetWeakPtr(),
- controller_id));
+ controller_id, error));
}
void VideoCaptureHost::OnNewBuffer(
@@ -216,7 +218,7 @@ void VideoCaptureHost::Stop(int32_t device_id) {
}
device_id_to_observer_map_.erase(controller_id);
- DeleteVideoCaptureController(controller_id, false);
+ DeleteVideoCaptureController(controller_id, media::VideoCaptureError::kNone);
NotifyStreamRemoved();
}
@@ -316,7 +318,8 @@ void VideoCaptureHost::GetDeviceFormatsInUse(
std::move(callback).Run(formats_in_use);
}
-void VideoCaptureHost::DoError(VideoCaptureControllerID controller_id) {
+void VideoCaptureHost::DoError(VideoCaptureControllerID controller_id,
+ media::VideoCaptureError error) {
DVLOG(1) << __func__;
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (controllers_.find(controller_id) == controllers_.end())
@@ -327,7 +330,7 @@ void VideoCaptureHost::DoError(VideoCaptureControllerID controller_id) {
media::mojom::VideoCaptureState::FAILED);
}
- DeleteVideoCaptureController(controller_id, true);
+ DeleteVideoCaptureController(controller_id, error);
NotifyStreamRemoved();
}
@@ -342,7 +345,7 @@ void VideoCaptureHost::DoEnded(VideoCaptureControllerID controller_id) {
media::mojom::VideoCaptureState::ENDED);
}
- DeleteVideoCaptureController(controller_id, false);
+ DeleteVideoCaptureController(controller_id, media::VideoCaptureError::kNone);
NotifyStreamRemoved();
}
@@ -355,7 +358,8 @@ void VideoCaptureHost::OnControllerAdded(
if (it == controllers_.end()) {
if (controller) {
media_stream_manager_->video_capture_manager()->DisconnectClient(
- controller.get(), controller_id, this, false);
+ controller.get(), controller_id, this,
+ media::VideoCaptureError::kNone);
}
return;
}
@@ -374,7 +378,8 @@ void VideoCaptureHost::OnControllerAdded(
}
void VideoCaptureHost::DeleteVideoCaptureController(
- VideoCaptureControllerID controller_id, bool on_error) {
+ VideoCaptureControllerID controller_id,
+ media::VideoCaptureError error) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
auto it = controllers_.find(controller_id);
@@ -387,7 +392,7 @@ void VideoCaptureHost::DeleteVideoCaptureController(
return;
media_stream_manager_->video_capture_manager()->DisconnectClient(
- controller.get(), controller_id, this, on_error);
+ controller.get(), controller_id, this, error);
}
void VideoCaptureHost::NotifyStreamAdded() {
diff --git a/chromium/content/browser/renderer_host/media/video_capture_host.h b/chromium/content/browser/renderer_host/media/video_capture_host.h
index d19c4ad5b20..5fdecfe6c63 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_host.h
+++ b/chromium/content/browser/renderer_host/media/video_capture_host.h
@@ -53,7 +53,8 @@ class CONTENT_EXPORT VideoCaptureHost
FRIEND_TEST_ALL_PREFIXES(VideoCaptureTest, IncrementMatchesDecrementCalls);
// VideoCaptureControllerEventHandler implementation.
- void OnError(VideoCaptureControllerID id) override;
+ void OnError(VideoCaptureControllerID id,
+ media::VideoCaptureError error) override;
void OnNewBuffer(VideoCaptureControllerID id,
media::mojom::VideoBufferHandlePtr buffer_handle,
int length,
@@ -90,7 +91,7 @@ class CONTENT_EXPORT VideoCaptureHost
int32_t session_id,
GetDeviceFormatsInUseCallback callback) override;
- void DoError(VideoCaptureControllerID id);
+ void DoError(VideoCaptureControllerID id, media::VideoCaptureError error);
void DoEnded(VideoCaptureControllerID id);
// Bound as callback for VideoCaptureManager::StartCaptureForClient().
@@ -102,7 +103,7 @@ class CONTENT_EXPORT VideoCaptureHost
// to StopCaptureForClient(). |on_error| is true if this is triggered by
// VideoCaptureControllerEventHandler::OnError.
void DeleteVideoCaptureController(VideoCaptureControllerID controller_id,
- bool on_error);
+ media::VideoCaptureError error);
void NotifyStreamAdded();
void NotifyStreamRemoved();
diff --git a/chromium/content/browser/renderer_host/media/video_capture_manager.cc b/chromium/content/browser/renderer_host/media/video_capture_manager.cc
index 3cdff16e6ef..12e9dc70f33 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_manager.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_manager.cc
@@ -49,6 +49,12 @@ void LogVideoCaptureEvent(VideoCaptureEvent event) {
NUM_VIDEO_CAPTURE_EVENT);
}
+void LogVideoCaptureError(media::VideoCaptureError error) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Media.VideoCapture.Error", error,
+ static_cast<int>(media::VideoCaptureError::kMaxValue) + 1);
+}
+
const media::VideoCaptureSessionId kFakeSessionId = -1;
} // namespace
@@ -263,7 +269,10 @@ void VideoCaptureManager::ProcessDeviceStartRequestQueue() {
const media::VideoCaptureDeviceInfo* device_info =
GetDeviceInfoById(controller->device_id());
if (!device_info) {
- OnDeviceLaunchFailed(controller);
+ OnDeviceLaunchFailed(
+ controller,
+ media::VideoCaptureError::
+ kVideoCaptureManagerProcessDeviceStartQueueDeviceInfoNotFound);
return;
}
for (auto& observer : capture_observers_)
@@ -295,7 +304,7 @@ void VideoCaptureManager::OnDeviceLaunched(VideoCaptureController* controller) {
DCHECK_EQ(controller, device_start_request_queue_.begin()->controller());
DCHECK(controller);
- if (controller->stream_type() == MEDIA_DESKTOP_VIDEO_CAPTURE) {
+ if (controller->stream_type() == MEDIA_GUM_DESKTOP_VIDEO_CAPTURE) {
const media::VideoCaptureSessionId session_id =
device_start_request_queue_.front().session_id();
DCHECK(session_id != kFakeSessionId);
@@ -318,12 +327,13 @@ void VideoCaptureManager::OnDeviceLaunched(VideoCaptureController* controller) {
}
void VideoCaptureManager::OnDeviceLaunchFailed(
- VideoCaptureController* controller) {
+ VideoCaptureController* controller,
+ media::VideoCaptureError error) {
std::ostringstream string_stream;
string_stream << "Launching device has failed. device_id = "
<< controller->device_id();
EmitLogMessage(string_stream.str(), 1);
- controller->OnError();
+ controller->OnError(error);
device_start_request_queue_.pop_front();
ProcessDeviceStartRequestQueue();
@@ -341,7 +351,8 @@ void VideoCaptureManager::OnDeviceConnectionLost(
string_stream << "Lost connection to device. device_id = "
<< controller->device_id();
EmitLogMessage(string_stream.str(), 1);
- controller->OnError();
+ controller->OnError(
+ media::VideoCaptureError::kVideoCaptureManagerDeviceConnectionLost);
}
void VideoCaptureManager::ConnectClient(
@@ -387,7 +398,7 @@ void VideoCaptureManager::DisconnectClient(
VideoCaptureController* controller,
VideoCaptureControllerID client_id,
VideoCaptureControllerEventHandler* client_handler,
- bool aborted_due_to_error) {
+ media::VideoCaptureError error) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(controller);
DCHECK(client_handler);
@@ -396,7 +407,7 @@ void VideoCaptureManager::DisconnectClient(
NOTREACHED();
return;
}
- if (!aborted_due_to_error) {
+ if (error == media::VideoCaptureError::kNone) {
if (controller->has_received_frames()) {
LogVideoCaptureEvent(VIDEO_CAPTURE_STOP_CAPTURE_OK);
} else if (controller->stream_type() == MEDIA_DEVICE_VIDEO_CAPTURE) {
@@ -408,6 +419,11 @@ void VideoCaptureManager::DisconnectClient(
}
} else {
LogVideoCaptureEvent(VIDEO_CAPTURE_STOP_CAPTURE_DUE_TO_ERROR);
+ LogVideoCaptureError(error);
+ std::ostringstream string_stream;
+ string_stream << "Video capture session stopped with error code "
+ << static_cast<int>(error);
+ EmitLogMessage(string_stream.str(), 1);
for (auto it : sessions_) {
if (it.second.type == controller->stream_type() &&
it.second.id == controller->device_id()) {
@@ -573,7 +589,7 @@ void VideoCaptureManager::MaybePostDesktopCaptureWindowId(
return;
}
- DCHECK_EQ(MEDIA_DESKTOP_VIDEO_CAPTURE, existing_device->stream_type());
+ DCHECK_EQ(MEDIA_GUM_DESKTOP_VIDEO_CAPTURE, existing_device->stream_type());
DesktopMediaID id = DesktopMediaID::Parse(existing_device->device_id());
if (id.is_null())
return;
diff --git a/chromium/content/browser/renderer_host/media/video_capture_manager.h b/chromium/content/browser/renderer_host/media/video_capture_manager.h
index 0604c90425d..a32d287958c 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_manager.h
+++ b/chromium/content/browser/renderer_host/media/video_capture_manager.h
@@ -97,7 +97,7 @@ class CONTENT_EXPORT VideoCaptureManager
void DisconnectClient(VideoCaptureController* controller,
VideoCaptureControllerID client_id,
VideoCaptureControllerEventHandler* client_handler,
- bool aborted_due_to_error);
+ media::VideoCaptureError error);
// Called by VideoCaptureHost to pause to update video buffer specified by
// |client_id| and |client_handler|. If all clients of |controller| are
@@ -179,7 +179,8 @@ class CONTENT_EXPORT VideoCaptureManager
// VideoCaptureDeviceLaunchObserver implementation:
void OnDeviceLaunched(VideoCaptureController* controller) override;
- void OnDeviceLaunchFailed(VideoCaptureController* controller) override;
+ void OnDeviceLaunchFailed(VideoCaptureController* controller,
+ media::VideoCaptureError error) override;
void OnDeviceLaunchAborted() override;
void OnDeviceConnectionLost(VideoCaptureController* controller) override;
@@ -264,7 +265,7 @@ class CONTENT_EXPORT VideoCaptureManager
void EmitLogMessage(const std::string& message, int verbose_log_level);
// Only accessed on Browser::IO thread.
- base::ObserverList<MediaStreamProviderListener> listeners_;
+ base::ObserverList<MediaStreamProviderListener>::Unchecked listeners_;
media::VideoCaptureSessionId new_capture_session_id_;
// An entry is kept in this map for every session that has been created via
@@ -288,7 +289,7 @@ class CONTENT_EXPORT VideoCaptureManager
const std::unique_ptr<VideoCaptureProvider> video_capture_provider_;
base::RepeatingCallback<void(const std::string&)> emit_log_message_cb_;
- base::ObserverList<media::VideoCaptureObserver> capture_observers_;
+ base::ObserverList<media::VideoCaptureObserver>::Unchecked capture_observers_;
// Local cache of the enumerated DeviceInfos. GetDeviceSupportedFormats() will
// use this list if the device is not started, otherwise it will retrieve the
diff --git a/chromium/content/browser/renderer_host/media/video_capture_manager_unittest.cc b/chromium/content/browser/renderer_host/media/video_capture_manager_unittest.cc
index 5816d1b3803..ce592438e1d 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_manager_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_manager_unittest.cc
@@ -152,7 +152,9 @@ class MockMediaStreamProviderListener : public MediaStreamProviderListener {
// Needed as an input argument to ConnectClient().
class MockFrameObserver : public VideoCaptureControllerEventHandler {
public:
- MOCK_METHOD1(OnError, void(VideoCaptureControllerID id));
+ MOCK_METHOD2(OnError,
+ void(VideoCaptureControllerID id,
+ media::VideoCaptureError error));
MOCK_METHOD1(OnStarted, void(VideoCaptureControllerID id));
MOCK_METHOD1(OnStartedUsingGpuDecode, void(VideoCaptureControllerID id));
@@ -258,7 +260,8 @@ class VideoCaptureManagerTest : public testing::Test {
void StopClient(VideoCaptureControllerID client_id) {
ASSERT_TRUE(1 == controllers_.count(client_id));
vcm_->DisconnectClient(controllers_[client_id], client_id,
- frame_observer_.get(), false);
+ frame_observer_.get(),
+ media::VideoCaptureError::kNone);
controllers_.erase(client_id);
}
@@ -355,8 +358,9 @@ TEST_F(VideoCaptureManagerTest, CreateAndAbort) {
// Wait for device opened.
base::RunLoop().RunUntilIdle();
- vcm_->DisconnectClient(controllers_[client_id], client_id,
- frame_observer_.get(), true);
+ vcm_->DisconnectClient(
+ controllers_[client_id], client_id, frame_observer_.get(),
+ media::VideoCaptureError::kIntentionalErrorRaisedByUnitTest);
// Wait to check callbacks before removing the listener.
base::RunLoop().RunUntilIdle();
@@ -666,7 +670,7 @@ TEST_F(VideoCaptureManagerTest, OpenTwo) {
// Try open a non-existing device.
TEST_F(VideoCaptureManagerTest, OpenNotExisting) {
InSequence s;
- EXPECT_CALL(*frame_observer_, OnError(_));
+ EXPECT_CALL(*frame_observer_, OnError(_, _));
EXPECT_CALL(*listener_, Opened(MEDIA_DEVICE_VIDEO_CAPTURE, _));
EXPECT_CALL(*listener_, Closed(MEDIA_DEVICE_VIDEO_CAPTURE, _));
diff --git a/chromium/content/browser/renderer_host/media/video_capture_unittest.cc b/chromium/content/browser/renderer_host/media/video_capture_unittest.cc
index 6cebba5ed0f..13c722627ea 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_unittest.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_unittest.cc
@@ -142,9 +142,9 @@ class VideoCaptureTest : public testing::Test,
devices_to_enumerate[MEDIA_DEVICE_TYPE_VIDEO_INPUT] = true;
media_stream_manager_->media_devices_manager()->EnumerateDevices(
devices_to_enumerate,
- base::Bind(&VideoInputDevicesEnumerated, run_loop.QuitClosure(),
- browser_context_.GetMediaDeviceIDSalt(), security_origin,
- &video_devices));
+ base::BindOnce(&VideoInputDevicesEnumerated, run_loop.QuitClosure(),
+ browser_context_.GetMediaDeviceIDSalt(),
+ security_origin, &video_devices));
run_loop.Run();
}
ASSERT_FALSE(video_devices.empty());
@@ -277,7 +277,8 @@ class VideoCaptureTest : public testing::Test,
void SimulateError() {
EXPECT_CALL(*this, OnStateChanged(media::mojom::VideoCaptureState::FAILED));
VideoCaptureControllerID id(kDeviceId);
- host_->OnError(id);
+ host_->OnError(id,
+ media::VideoCaptureError::kIntentionalErrorRaisedByUnitTest);
base::RunLoop().RunUntilIdle();
}
diff --git a/chromium/content/browser/renderer_host/p2p/DEPS b/chromium/content/browser/renderer_host/p2p/DEPS
deleted file mode 100644
index 93e27aa264f..00000000000
--- a/chromium/content/browser/renderer_host/p2p/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
- "+jingle/glue",
-]
diff --git a/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.cc b/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.cc
index 270b2aaee40..ce859120f2e 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.cc
+++ b/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.cc
@@ -9,181 +9,29 @@
#include <algorithm>
#include "base/bind.h"
-#include "base/task_scheduler/post_task.h"
#include "content/browser/bad_message.h"
-#include "content/browser/renderer_host/p2p/socket_host.h"
-#include "content/common/p2p_messages.h"
-#include "content/public/browser/browser_thread.h"
-#include "net/base/address_list.h"
-#include "net/base/completion_callback.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/browser/storage_partition_impl.h"
#include "net/base/net_errors.h"
-#include "net/base/network_interfaces.h"
-#include "net/base/sys_addrinfo.h"
-#include "net/dns/host_resolver.h"
-#include "net/log/net_log_source.h"
-#include "net/log/net_log_with_source.h"
-#include "net/socket/client_socket_factory.h"
-#include "net/socket/datagram_client_socket.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "services/network/proxy_resolving_client_socket_factory.h"
+#include "services/network/public/cpp/p2p_param_traits.h"
using content::BrowserMessageFilter;
using content::BrowserThread;
namespace content {
-namespace {
+P2PSocketDispatcherHost::P2PSocketDispatcherHost(int render_process_id)
+ : render_process_id_(render_process_id),
+ binding_(this),
+ weak_factory_(this) {}
-// Used by GetDefaultLocalAddress as the target to connect to for getting the
-// default local address. They are public DNS servers on the internet.
-const uint8_t kPublicIPv4Host[] = {8, 8, 8, 8};
-const uint8_t kPublicIPv6Host[] = {
- 0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0, 0, 0, 0, 0, 0, 0, 0, 0x88, 0x88};
-const int kPublicPort = 53; // DNS port.
-
-// Experimentation shows that creating too many sockets creates odd problems
-// because of resource exhaustion in the Unix sockets domain.
-// Trouble has been seen on Linux at 3479 sockets in test, so leave a margin.
-const int kMaxSimultaneousSockets = 3000;
-
-} // namespace
-
-const size_t kMaximumPacketSize = 32768;
-
-class P2PSocketDispatcherHost::DnsRequest {
- public:
- typedef base::Callback<void(const net::IPAddressList&)> DoneCallback;
-
- DnsRequest(int32_t request_id, net::HostResolver* host_resolver)
- : request_id_(request_id), resolver_(host_resolver) {}
-
- void Resolve(const std::string& host_name,
- const DoneCallback& done_callback) {
- DCHECK(!done_callback.is_null());
-
- host_name_ = host_name;
- done_callback_ = done_callback;
-
- // Return an error if it's an empty string.
- if (host_name_.empty()) {
- net::IPAddressList address_list;
- done_callback_.Run(address_list);
- return;
- }
-
- // Add period at the end to make sure that we only resolve
- // fully-qualified names.
- if (host_name_.back() != '.')
- host_name_ += '.';
-
- net::HostResolver::RequestInfo info(net::HostPortPair(host_name_, 0));
- int result = resolver_->Resolve(
- info, net::DEFAULT_PRIORITY, &addresses_,
- base::Bind(&P2PSocketDispatcherHost::DnsRequest::OnDone,
- base::Unretained(this)),
- &request_, net::NetLogWithSource());
- if (result != net::ERR_IO_PENDING)
- OnDone(result);
- }
-
- int32_t request_id() { return request_id_; }
-
- private:
- void OnDone(int result) {
- net::IPAddressList list;
- if (result != net::OK) {
- LOG(ERROR) << "Failed to resolve address for " << host_name_
- << ", errorcode: " << result;
- done_callback_.Run(list);
- return;
- }
-
- DCHECK(!addresses_.empty());
- for (net::AddressList::iterator iter = addresses_.begin();
- iter != addresses_.end(); ++iter) {
- list.push_back(iter->address());
- }
- done_callback_.Run(list);
- }
-
- int32_t request_id_;
- net::AddressList addresses_;
-
- std::string host_name_;
- net::HostResolver* resolver_;
- std::unique_ptr<net::HostResolver::Request> request_;
-
- DoneCallback done_callback_;
-};
-
-P2PSocketDispatcherHost::P2PSocketDispatcherHost(
- net::URLRequestContextGetter* url_context)
- : BrowserMessageFilter(P2PMsgStart),
- url_context_(url_context),
- monitoring_networks_(false),
- dump_incoming_rtp_packet_(false),
- dump_outgoing_rtp_packet_(false),
- network_list_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::USER_VISIBLE})) {}
-
-void P2PSocketDispatcherHost::OnChannelClosing() {
- // Since the IPC sender is gone, close pending connections.
- sockets_.clear();
-
- dns_requests_.clear();
-
- if (monitoring_networks_) {
- net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
- monitoring_networks_ = false;
- }
-
- proxy_resolving_socket_factory_.reset();
-}
-
-void P2PSocketDispatcherHost::OnDestruct() const {
- BrowserThread::DeleteOnIOThread::Destruct(this);
-}
-
-bool P2PSocketDispatcherHost::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(P2PSocketDispatcherHost, message)
- IPC_MESSAGE_HANDLER(P2PHostMsg_StartNetworkNotifications,
- OnStartNetworkNotifications)
- IPC_MESSAGE_HANDLER(P2PHostMsg_StopNetworkNotifications,
- OnStopNetworkNotifications)
- IPC_MESSAGE_HANDLER(P2PHostMsg_GetHostAddress, OnGetHostAddress)
- IPC_MESSAGE_HANDLER(P2PHostMsg_CreateSocket, OnCreateSocket)
- IPC_MESSAGE_HANDLER(P2PHostMsg_AcceptIncomingTcpConnection,
- OnAcceptIncomingTcpConnection)
- IPC_MESSAGE_HANDLER(P2PHostMsg_Send, OnSend)
- IPC_MESSAGE_HANDLER(P2PHostMsg_SetOption, OnSetOption)
- IPC_MESSAGE_HANDLER(P2PHostMsg_DestroySocket, OnDestroySocket)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void P2PSocketDispatcherHost::OnNetworkChanged(
- net::NetworkChangeNotifier::ConnectionType type) {
- // NetworkChangeNotifier always emits CONNECTION_NONE notification whenever
- // network configuration changes. All other notifications can be ignored.
- if (type != net::NetworkChangeNotifier::CONNECTION_NONE)
- return;
-
- // Notify the renderer about changes to list of network interfaces.
- network_list_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&P2PSocketDispatcherHost::DoGetNetworkList, this));
-}
+P2PSocketDispatcherHost::~P2PSocketDispatcherHost() {}
void P2PSocketDispatcherHost::StartRtpDump(
bool incoming,
bool outgoing,
const RenderProcessHost::WebRtcRtpPacketCallback& packet_callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if ((!dump_incoming_rtp_packet_ && incoming) ||
(!dump_outgoing_rtp_packet_ && outgoing)) {
if (incoming)
@@ -193,256 +41,70 @@ void P2PSocketDispatcherHost::StartRtpDump(
dump_outgoing_rtp_packet_ = true;
packet_callback_ = packet_callback;
- for (SocketsMap::iterator it = sockets_.begin(); it != sockets_.end(); ++it)
- it->second->StartRtpDump(incoming, outgoing, packet_callback);
+ if (trusted_socket_manager_)
+ trusted_socket_manager_->StartRtpDump(incoming, outgoing);
}
}
-void P2PSocketDispatcherHost::StopRtpDumpOnUIThread(bool incoming,
- bool outgoing) {
+void P2PSocketDispatcherHost::StopRtpDump(bool incoming, bool outgoing) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(&P2PSocketDispatcherHost::StopRtpDumpOnIOThread, this,
- incoming, outgoing));
-}
-
-P2PSocketDispatcherHost::~P2PSocketDispatcherHost() {
- DCHECK(sockets_.empty());
- DCHECK(dns_requests_.empty());
-
- if (monitoring_networks_)
- net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
-}
-
-P2PSocketHost* P2PSocketDispatcherHost::LookupSocket(int socket_id) {
- SocketsMap::iterator it = sockets_.find(socket_id);
- return (it == sockets_.end()) ? nullptr : it->second.get();
-}
-
-void P2PSocketDispatcherHost::OnStartNetworkNotifications() {
- if (!monitoring_networks_) {
- net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
- monitoring_networks_ = true;
- }
-
- network_list_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&P2PSocketDispatcherHost::DoGetNetworkList, this));
-}
-
-void P2PSocketDispatcherHost::OnStopNetworkNotifications() {
- if (monitoring_networks_) {
- net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
- monitoring_networks_ = false;
- }
-}
-
-void P2PSocketDispatcherHost::OnGetHostAddress(const std::string& host_name,
- int32_t request_id) {
- std::unique_ptr<DnsRequest> request = std::make_unique<DnsRequest>(
- request_id, url_context_->GetURLRequestContext()->host_resolver());
- DnsRequest* request_ptr = request.get();
- dns_requests_.insert(std::move(request));
- request_ptr->Resolve(host_name,
- base::Bind(&P2PSocketDispatcherHost::OnAddressResolved,
- base::Unretained(this), request_ptr));
-}
-
-void P2PSocketDispatcherHost::OnCreateSocket(
- P2PSocketType type,
- int socket_id,
- const net::IPEndPoint& local_address,
- const P2PPortRange& port_range,
- const P2PHostAndIPEndPoint& remote_address) {
- if (port_range.min_port > port_range.max_port ||
- (port_range.min_port == 0 && port_range.max_port != 0)) {
- bad_message::ReceivedBadMessage(this, bad_message::SDH_INVALID_PORT_RANGE);
- return;
- }
-
- if (LookupSocket(socket_id)) {
- LOG(ERROR) << "Received P2PHostMsg_CreateSocket for socket "
- "that already exists.";
- return;
- }
-
- if (!proxy_resolving_socket_factory_) {
- proxy_resolving_socket_factory_ =
- std::make_unique<network::ProxyResolvingClientSocketFactory>(
- url_context_->GetURLRequestContext());
- }
- if (sockets_.size() > kMaxSimultaneousSockets) {
- LOG(ERROR) << "Too many sockets created";
- Send(new P2PMsg_OnError(socket_id));
- return;
- }
- std::unique_ptr<P2PSocketHost> socket(P2PSocketHost::Create(
- this, socket_id, type, url_context_.get(),
- proxy_resolving_socket_factory_.get(), &throttler_));
+ if ((dump_incoming_rtp_packet_ && incoming) ||
+ (dump_outgoing_rtp_packet_ && outgoing)) {
+ if (incoming)
+ dump_incoming_rtp_packet_ = false;
- if (!socket) {
- Send(new P2PMsg_OnError(socket_id));
- return;
- }
+ if (outgoing)
+ dump_outgoing_rtp_packet_ = false;
- if (socket->Init(local_address, port_range.min_port, port_range.max_port,
- remote_address)) {
- sockets_[socket_id] = std::move(socket);
+ if (!dump_incoming_rtp_packet_ && !dump_outgoing_rtp_packet_)
+ packet_callback_.Reset();
- if (dump_incoming_rtp_packet_ || dump_outgoing_rtp_packet_) {
- sockets_[socket_id]->StartRtpDump(dump_incoming_rtp_packet_,
- dump_outgoing_rtp_packet_,
- packet_callback_);
- }
+ if (trusted_socket_manager_)
+ trusted_socket_manager_->StopRtpDump(incoming, outgoing);
}
}
-void P2PSocketDispatcherHost::OnAcceptIncomingTcpConnection(
- int listen_socket_id, const net::IPEndPoint& remote_address,
- int connected_socket_id) {
- P2PSocketHost* socket = LookupSocket(listen_socket_id);
- if (!socket) {
- LOG(ERROR) << "Received P2PHostMsg_AcceptIncomingTcpConnection "
- "for invalid listen_socket_id.";
+void P2PSocketDispatcherHost::BindRequest(
+ network::mojom::P2PSocketManagerRequest request) {
+ auto* rph = RenderProcessHostImpl::FromID(render_process_id_);
+ if (!rph)
return;
- }
- if (LookupSocket(connected_socket_id) != nullptr) {
- LOG(ERROR) << "Received P2PHostMsg_AcceptIncomingTcpConnection "
- "for duplicated connected_socket_id.";
- return;
- }
- std::unique_ptr<P2PSocketHost> accepted_connection(
- socket->AcceptIncomingTcpConnection(remote_address, connected_socket_id));
- if (accepted_connection) {
- sockets_[connected_socket_id] = std::move(accepted_connection);
- }
-}
-
-void P2PSocketDispatcherHost::OnSend(
- int socket_id,
- const std::vector<char>& data,
- const P2PPacketInfo& packet_info,
- const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
- P2PSocketHost* socket = LookupSocket(socket_id);
- if (!socket) {
- LOG(ERROR) << "Received P2PHostMsg_Send for invalid socket_id.";
- return;
- }
+ network::mojom::P2PTrustedSocketManagerClientPtr
+ trusted_socket_manager_client;
+ binding_.Bind(mojo::MakeRequest(&trusted_socket_manager_client));
- if (data.size() > kMaximumPacketSize) {
- LOG(ERROR) << "Received P2PHostMsg_Send with a packet that is too big: "
- << data.size();
- Send(new P2PMsg_OnError(socket_id));
- sockets_.erase(socket_id); // deletes the socket
- return;
+ rph->GetStoragePartition()->GetNetworkContext()->CreateP2PSocketManager(
+ std::move(trusted_socket_manager_client),
+ mojo::MakeRequest(&trusted_socket_manager_), std::move(request));
+ if (dump_incoming_rtp_packet_ || dump_outgoing_rtp_packet_) {
+ trusted_socket_manager_->StartRtpDump(dump_incoming_rtp_packet_,
+ dump_outgoing_rtp_packet_);
}
-
- socket->Send(packet_info.destination, data, packet_info.packet_options,
- packet_info.packet_id,
- net::NetworkTrafficAnnotationTag(traffic_annotation));
}
-void P2PSocketDispatcherHost::OnSetOption(int socket_id,
- P2PSocketOption option,
- int value) {
- P2PSocketHost* socket = LookupSocket(socket_id);
- if (!socket) {
- LOG(ERROR) << "Received P2PHostMsg_SetOption for invalid socket_id.";
- return;
- }
-
- socket->SetOption(option, value);
+base::WeakPtr<P2PSocketDispatcherHost> P2PSocketDispatcherHost::GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
}
-void P2PSocketDispatcherHost::OnDestroySocket(int socket_id) {
- SocketsMap::iterator it = sockets_.find(socket_id);
- if (it != sockets_.end()) {
- sockets_.erase(it); // deletes the socket
- } else {
- LOG(ERROR) << "Received P2PHostMsg_DestroySocket for invalid socket_id.";
- }
+void P2PSocketDispatcherHost::InvalidSocketPortRangeRequested() {
+ bad_message::ReceivedBadMessage(render_process_id_,
+ bad_message::SDH_INVALID_PORT_RANGE);
}
-void P2PSocketDispatcherHost::DoGetNetworkList() {
- net::NetworkInterfaceList list;
- if (!net::GetNetworkList(&list, net::EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES)) {
- LOG(ERROR) << "GetNetworkList failed.";
+void P2PSocketDispatcherHost::DumpPacket(
+ const std::vector<uint8_t>& packet_header,
+ uint64_t packet_length,
+ bool incoming) {
+ if (!packet_callback_)
return;
- }
- default_ipv4_local_address_ = GetDefaultLocalAddress(AF_INET);
- default_ipv6_local_address_ = GetDefaultLocalAddress(AF_INET6);
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(&P2PSocketDispatcherHost::SendNetworkList, this, list,
- default_ipv4_local_address_, default_ipv6_local_address_));
-}
-
-void P2PSocketDispatcherHost::SendNetworkList(
- const net::NetworkInterfaceList& list,
- const net::IPAddress& default_ipv4_local_address,
- const net::IPAddress& default_ipv6_local_address) {
- Send(new P2PMsg_NetworkListChanged(list, default_ipv4_local_address,
- default_ipv6_local_address));
-}
-
-net::IPAddress P2PSocketDispatcherHost::GetDefaultLocalAddress(int family) {
- DCHECK(family == AF_INET || family == AF_INET6);
-
- // Creation and connection of a UDP socket might be janky.
- DCHECK(network_list_task_runner_->RunsTasksInCurrentSequence());
-
- auto socket =
- net::ClientSocketFactory::GetDefaultFactory()->CreateDatagramClientSocket(
- net::DatagramSocket::DEFAULT_BIND, nullptr, net::NetLogSource());
-
- net::IPAddress ip_address;
- if (family == AF_INET) {
- ip_address = net::IPAddress(kPublicIPv4Host);
- } else {
- ip_address = net::IPAddress(kPublicIPv6Host);
- }
-
- if (socket->Connect(net::IPEndPoint(ip_address, kPublicPort)) != net::OK) {
- return net::IPAddress();
- }
-
- net::IPEndPoint local_address;
- if (socket->GetLocalAddress(&local_address) != net::OK)
- return net::IPAddress();
-
- return local_address.address();
-}
-void P2PSocketDispatcherHost::OnAddressResolved(
- DnsRequest* request,
- const net::IPAddressList& addresses) {
- Send(new P2PMsg_GetHostAddressResult(request->request_id(), addresses));
+ std::unique_ptr<uint8_t[]> header_buffer(new uint8_t[packet_header.size()]);
+ memcpy(header_buffer.get(), &packet_header[0], packet_header.size());
- dns_requests_.erase(
- std::find_if(dns_requests_.begin(), dns_requests_.end(),
- [request](const std::unique_ptr<DnsRequest>& ptr) {
- return ptr.get() == request;
- }));
-}
-
-void P2PSocketDispatcherHost::StopRtpDumpOnIOThread(bool incoming,
- bool outgoing) {
- if ((dump_incoming_rtp_packet_ && incoming) ||
- (dump_outgoing_rtp_packet_ && outgoing)) {
- if (incoming)
- dump_incoming_rtp_packet_ = false;
-
- if (outgoing)
- dump_outgoing_rtp_packet_ = false;
-
- if (!dump_incoming_rtp_packet_ && !dump_outgoing_rtp_packet_)
- packet_callback_.Reset();
-
- for (SocketsMap::iterator it = sockets_.begin(); it != sockets_.end(); ++it)
- it->second->StopRtpDump(incoming, outgoing);
- }
+ packet_callback_.Run(std::move(header_buffer),
+ static_cast<size_t>(packet_header.size()),
+ static_cast<size_t>(packet_length), incoming);
}
} // namespace content
diff --git a/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.h b/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.h
index 288c834e422..3802f73ec6b 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.h
+++ b/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.h
@@ -7,130 +7,60 @@
#include <stdint.h>
-#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner.h"
-#include "content/browser/renderer_host/p2p/socket_host_throttler.h"
-#include "content/common/p2p_socket_type.h"
-#include "content/public/browser/browser_message_filter.h"
-#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
-#include "net/base/ip_address.h"
-#include "net/base/ip_endpoint.h"
-#include "net/base/network_change_notifier.h"
-
-namespace net {
-struct MutableNetworkTrafficAnnotationTag;
-class URLRequestContextGetter;
-}
-
-namespace network {
-class ProxyResolvingClientSocketFactory;
-}
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/network/public/mojom/p2p.mojom.h"
+#include "services/network/public/mojom/p2p_trusted.mojom.h"
namespace content {
-class P2PSocketHost;
-
+// Responsible for P2P sockets. Lives on the UI thread.
class P2PSocketDispatcherHost
- : public content::BrowserMessageFilter,
- public net::NetworkChangeNotifier::NetworkChangeObserver {
+ : public network::mojom::P2PTrustedSocketManagerClient {
public:
- explicit P2PSocketDispatcherHost(net::URLRequestContextGetter* url_context);
-
- // content::BrowserMessageFilter overrides.
- void OnChannelClosing() override;
- void OnDestruct() const override;
- bool OnMessageReceived(const IPC::Message& message) override;
+ explicit P2PSocketDispatcherHost(int render_process_id);
+ ~P2PSocketDispatcherHost() override;
- // net::NetworkChangeNotifier::NetworkChangeObserver interface.
- void OnNetworkChanged(
- net::NetworkChangeNotifier::ConnectionType type) override;
- // Starts the RTP packet header dumping. Must be called on the IO thread.
+ // Starts the RTP packet header dumping.
void StartRtpDump(
bool incoming,
bool outgoing,
const RenderProcessHost::WebRtcRtpPacketCallback& packet_callback);
- // Stops the RTP packet header dumping. Must be Called on the UI thread.
- void StopRtpDumpOnUIThread(bool incoming, bool outgoing);
-
- protected:
- ~P2PSocketDispatcherHost() override;
-
- private:
- friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
- friend class base::DeleteHelper<P2PSocketDispatcherHost>;
-
- typedef std::map<int, std::unique_ptr<P2PSocketHost>> SocketsMap;
+ // Stops the RTP packet header dumping.
+ void StopRtpDump(bool incoming, bool outgoing);
- class DnsRequest;
+ void BindRequest(network::mojom::P2PSocketManagerRequest request);
- P2PSocketHost* LookupSocket(int socket_id);
+ base::WeakPtr<P2PSocketDispatcherHost> GetWeakPtr();
- // Handlers for the messages coming from the renderer.
- void OnStartNetworkNotifications();
- void OnStopNetworkNotifications();
- void OnGetHostAddress(const std::string& host_name, int32_t request_id);
-
- void OnCreateSocket(P2PSocketType type,
- int socket_id,
- const net::IPEndPoint& local_address,
- const P2PPortRange& port_range,
- const P2PHostAndIPEndPoint& remote_address);
- void OnAcceptIncomingTcpConnection(int listen_socket_id,
- const net::IPEndPoint& remote_address,
- int connected_socket_id);
- void OnSend(
- int socket_id,
- const std::vector<char>& data,
- const P2PPacketInfo& packet_info,
- const net::MutableNetworkTrafficAnnotationTag& traffic_annotation);
- void OnSetOption(int socket_id, P2PSocketOption option, int value);
- void OnDestroySocket(int socket_id);
-
- void DoGetNetworkList();
- void SendNetworkList(const net::NetworkInterfaceList& list,
- const net::IPAddress& default_ipv4_local_address,
- const net::IPAddress& default_ipv6_local_address);
-
- // This connects a UDP socket to a public IP address and gets local
- // address. Since it binds to the "any" address (0.0.0.0 or ::) internally, it
- // retrieves the default local address.
- net::IPAddress GetDefaultLocalAddress(int family);
-
- void OnAddressResolved(DnsRequest* request,
- const net::IPAddressList& addresses);
-
- void StopRtpDumpOnIOThread(bool incoming, bool outgoing);
-
- scoped_refptr<net::URLRequestContextGetter> url_context_;
- // Initialized on browser IO thread.
- std::unique_ptr<network::ProxyResolvingClientSocketFactory>
- proxy_resolving_socket_factory_;
-
- SocketsMap sockets_;
+ private:
+ // network::mojom::P2PTrustedSocketManagerClient overrides:
+ void InvalidSocketPortRangeRequested() override;
+ void DumpPacket(const std::vector<uint8_t>& packet_header,
+ uint64_t packet_length,
+ bool incoming) override;
- bool monitoring_networks_;
+ int render_process_id_;
- std::set<std::unique_ptr<DnsRequest>> dns_requests_;
- P2PMessageThrottler throttler_;
+ bool dump_incoming_rtp_packet_ = false;
+ bool dump_outgoing_rtp_packet_ = false;
+ RenderProcessHost::WebRtcRtpPacketCallback packet_callback_;
- net::IPAddress default_ipv4_local_address_;
- net::IPAddress default_ipv6_local_address_;
+ mojo::Binding<network::mojom::P2PTrustedSocketManagerClient> binding_;
+ network::mojom::P2PTrustedSocketManagerPtr trusted_socket_manager_;
- bool dump_incoming_rtp_packet_;
- bool dump_outgoing_rtp_packet_;
- RenderProcessHost::WebRtcRtpPacketCallback packet_callback_;
+ network::mojom::P2PNetworkNotificationClientPtr network_notification_client_;
- // Used to call DoGetNetworkList, which may briefly block since getting the
- // default local address involves creating a dummy socket.
- const scoped_refptr<base::SequencedTaskRunner> network_list_task_runner_;
+ base::WeakPtrFactory<P2PSocketDispatcherHost> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(P2PSocketDispatcherHost);
};
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host.cc b/chromium/content/browser/renderer_host/p2p/socket_host.cc
deleted file mode 100644
index 8173bcfddd3..00000000000
--- a/chromium/content/browser/renderer_host/p2p/socket_host.cc
+++ /dev/null
@@ -1,332 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/renderer_host/p2p/socket_host.h"
-
-#include "base/metrics/histogram_macros.h"
-#include "base/sys_byteorder.h"
-#include "content/browser/renderer_host/p2p/socket_host_tcp.h"
-#include "content/browser/renderer_host/p2p/socket_host_tcp_server.h"
-#include "content/browser/renderer_host/p2p/socket_host_udp.h"
-#include "content/browser/renderer_host/render_process_host_impl.h"
-#include "content/public/browser/browser_thread.h"
-#include "net/base/net_errors.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "services/network/proxy_resolving_client_socket_factory.h"
-#include "third_party/webrtc/media/base/rtputils.h"
-#include "third_party/webrtc/media/base/turnutils.h"
-
-namespace {
-
-// Used to back histogram value of "WebRTC.ICE.TcpSocketErrorCode" and
-// "WebRTC.ICE.UdpSocketErrorCode".
-enum class SocketErrorCode {
- ERR_MSG_TOO_BIG,
- ERR_ADDRESS_UNREACHABLE,
- ERR_ADDRESS_INVALID,
- ERR_INTERNET_DISCONNECTED,
- ERR_TIMED_OUT,
- ERR_INSUFFICIENT_RESOURCES,
- ERR_OUT_OF_MEMORY,
- ERR_OTHER // For all the others
-};
-
-const uint32_t kStunMagicCookie = 0x2112A442;
-const size_t kMinRtcpHeaderLength = 8;
-const size_t kDtlsRecordHeaderLength = 13;
-
-bool IsDtlsPacket(const char* data, size_t length) {
- const uint8_t* u = reinterpret_cast<const uint8_t*>(data);
- return (length >= kDtlsRecordHeaderLength && (u[0] > 19 && u[0] < 64));
-}
-
-bool IsRtcpPacket(const char* data, size_t length) {
- if (length < kMinRtcpHeaderLength) {
- return false;
- }
-
- int type = (static_cast<uint8_t>(data[1]) & 0x7F);
- return (type >= 64 && type < 96);
-}
-
-// Map the network error to SocketErrorCode for the UMA histogram.
-// static
-static SocketErrorCode MapNetErrorToSocketErrorCode(int net_err) {
- switch (net_err) {
- case net::OK:
- NOTREACHED();
- return SocketErrorCode::ERR_OTHER;
- case net::ERR_MSG_TOO_BIG:
- return SocketErrorCode::ERR_MSG_TOO_BIG;
- case net::ERR_ADDRESS_UNREACHABLE:
- return SocketErrorCode::ERR_ADDRESS_UNREACHABLE;
- case net::ERR_ADDRESS_INVALID:
- return SocketErrorCode::ERR_ADDRESS_INVALID;
- case net::ERR_INTERNET_DISCONNECTED:
- return SocketErrorCode::ERR_INTERNET_DISCONNECTED;
- case net::ERR_TIMED_OUT:
- return SocketErrorCode::ERR_TIMED_OUT;
- case net::ERR_INSUFFICIENT_RESOURCES:
- return SocketErrorCode::ERR_INSUFFICIENT_RESOURCES;
- case net::ERR_OUT_OF_MEMORY:
- return SocketErrorCode::ERR_OUT_OF_MEMORY;
- default:
- return SocketErrorCode::ERR_OTHER;
- }
-}
-} // namespace
-
-namespace content {
-
-P2PSocketHost::P2PSocketHost(IPC::Sender* message_sender,
- int socket_id,
- ProtocolType protocol_type)
- : message_sender_(message_sender),
- id_(socket_id),
- state_(STATE_UNINITIALIZED),
- dump_incoming_rtp_packet_(false),
- dump_outgoing_rtp_packet_(false),
- protocol_type_(protocol_type),
- send_packets_delayed_total_(0),
- send_packets_total_(0),
- send_bytes_delayed_max_(0),
- send_bytes_delayed_cur_(0),
- weak_ptr_factory_(this) {
-}
-
-P2PSocketHost::~P2PSocketHost() {
- if (protocol_type_ == P2PSocketHost::UDP) {
- UMA_HISTOGRAM_COUNTS_10000("WebRTC.SystemMaxConsecutiveBytesDelayed_UDP",
- send_bytes_delayed_max_);
- } else {
- UMA_HISTOGRAM_COUNTS_10000("WebRTC.SystemMaxConsecutiveBytesDelayed_TCP",
- send_bytes_delayed_max_);
- }
-
- if (send_packets_total_ > 0) {
- int delay_rate = (send_packets_delayed_total_ * 100) / send_packets_total_;
- if (protocol_type_ == P2PSocketHost::UDP) {
- UMA_HISTOGRAM_PERCENTAGE("WebRTC.SystemPercentPacketsDelayed_UDP",
- delay_rate);
- } else {
- UMA_HISTOGRAM_PERCENTAGE("WebRTC.SystemPercentPacketsDelayed_TCP",
- delay_rate);
- }
- }
-}
-
-// Verifies that the packet |data| has a valid STUN header.
-// static
-bool P2PSocketHost::GetStunPacketType(
- const char* data, int data_size, StunMessageType* type) {
-
- if (data_size < kStunHeaderSize) {
- return false;
- }
-
- uint32_t cookie =
- base::NetToHost32(*reinterpret_cast<const uint32_t*>(data + 4));
- if (cookie != kStunMagicCookie) {
- return false;
- }
-
- uint16_t length =
- base::NetToHost16(*reinterpret_cast<const uint16_t*>(data + 2));
- if (length != data_size - kStunHeaderSize) {
- return false;
- }
-
- int message_type =
- base::NetToHost16(*reinterpret_cast<const uint16_t*>(data));
-
- // Verify that the type is known:
- switch (message_type) {
- case STUN_BINDING_REQUEST:
- case STUN_BINDING_RESPONSE:
- case STUN_BINDING_ERROR_RESPONSE:
- case STUN_SHARED_SECRET_REQUEST:
- case STUN_SHARED_SECRET_RESPONSE:
- case STUN_SHARED_SECRET_ERROR_RESPONSE:
- case STUN_ALLOCATE_REQUEST:
- case STUN_ALLOCATE_RESPONSE:
- case STUN_ALLOCATE_ERROR_RESPONSE:
- case STUN_SEND_REQUEST:
- case STUN_SEND_RESPONSE:
- case STUN_SEND_ERROR_RESPONSE:
- case STUN_DATA_INDICATION:
- *type = static_cast<StunMessageType>(message_type);
- return true;
-
- default:
- return false;
- }
-}
-
-// static
-bool P2PSocketHost::IsRequestOrResponse(StunMessageType type) {
- return type == STUN_BINDING_REQUEST || type == STUN_BINDING_RESPONSE ||
- type == STUN_ALLOCATE_REQUEST || type == STUN_ALLOCATE_RESPONSE;
-}
-
-// static
-void P2PSocketHost::ReportSocketError(int result, const char* histogram_name) {
- SocketErrorCode error_code = MapNetErrorToSocketErrorCode(result);
- UMA_HISTOGRAM_ENUMERATION(histogram_name, static_cast<int>(error_code),
- static_cast<int>(SocketErrorCode::ERR_OTHER) + 1);
-}
-
-// static
-P2PSocketHost* P2PSocketHost::Create(
- IPC::Sender* message_sender,
- int socket_id,
- P2PSocketType type,
- net::URLRequestContextGetter* url_context,
- network::ProxyResolvingClientSocketFactory* proxy_resolving_socket_factory,
- P2PMessageThrottler* throttler) {
- switch (type) {
- case P2P_SOCKET_UDP:
- return new P2PSocketHostUdp(
- message_sender, socket_id, throttler,
- url_context->GetURLRequestContext()->net_log());
- case P2P_SOCKET_TCP_SERVER:
- return new P2PSocketHostTcpServer(
- message_sender, socket_id, P2P_SOCKET_TCP_CLIENT);
-
- case P2P_SOCKET_STUN_TCP_SERVER:
- return new P2PSocketHostTcpServer(
- message_sender, socket_id, P2P_SOCKET_STUN_TCP_CLIENT);
-
- case P2P_SOCKET_TCP_CLIENT:
- case P2P_SOCKET_SSLTCP_CLIENT:
- case P2P_SOCKET_TLS_CLIENT:
- return new P2PSocketHostTcp(message_sender, socket_id, type, url_context,
- proxy_resolving_socket_factory);
-
- case P2P_SOCKET_STUN_TCP_CLIENT:
- case P2P_SOCKET_STUN_SSLTCP_CLIENT:
- case P2P_SOCKET_STUN_TLS_CLIENT:
- return new P2PSocketHostStunTcp(message_sender, socket_id, type,
- url_context,
- proxy_resolving_socket_factory);
- }
-
- NOTREACHED();
- return nullptr;
-}
-
-void P2PSocketHost::StartRtpDump(
- bool incoming,
- bool outgoing,
- const RenderProcessHost::WebRtcRtpPacketCallback& packet_callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(!packet_callback.is_null());
- DCHECK(incoming || outgoing);
-
- if (incoming) {
- dump_incoming_rtp_packet_ = true;
- }
-
- if (outgoing) {
- dump_outgoing_rtp_packet_ = true;
- }
-
- packet_dump_callback_ = packet_callback;
-}
-
-void P2PSocketHost::StopRtpDump(bool incoming, bool outgoing) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(incoming || outgoing);
-
- if (incoming) {
- dump_incoming_rtp_packet_ = false;
- }
-
- if (outgoing) {
- dump_outgoing_rtp_packet_ = false;
- }
-
- if (!dump_incoming_rtp_packet_ && !dump_outgoing_rtp_packet_) {
- packet_dump_callback_.Reset();
- }
-}
-
-void P2PSocketHost::DumpRtpPacket(const char* packet,
- size_t length,
- bool incoming) {
- if (IsDtlsPacket(packet, length) || IsRtcpPacket(packet, length)) {
- return;
- }
-
- size_t rtp_packet_pos = 0;
- size_t rtp_packet_length = length;
- if (!cricket::UnwrapTurnPacket(reinterpret_cast<const uint8_t*>(packet),
- length, &rtp_packet_pos, &rtp_packet_length)) {
- return;
- }
-
- packet += rtp_packet_pos;
-
- size_t header_length = 0;
- bool valid =
- cricket::ValidateRtpHeader(reinterpret_cast<const uint8_t*>(packet),
- rtp_packet_length, &header_length);
- if (!valid) {
- NOTREACHED();
- return;
- }
-
- std::unique_ptr<uint8_t[]> header_buffer(new uint8_t[header_length]);
- memcpy(header_buffer.get(), packet, header_length);
-
- // Posts to the IO thread as the data members should be accessed on the IO
- // thread only.
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(&P2PSocketHost::DumpRtpPacketOnIOThread,
- weak_ptr_factory_.GetWeakPtr(), std::move(header_buffer),
- header_length, rtp_packet_length, incoming));
-}
-
-void P2PSocketHost::DumpRtpPacketOnIOThread(
- std::unique_ptr<uint8_t[]> packet_header,
- size_t header_length,
- size_t packet_length,
- bool incoming) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- if ((incoming && !dump_incoming_rtp_packet_) ||
- (!incoming && !dump_outgoing_rtp_packet_) ||
- packet_dump_callback_.is_null()) {
- return;
- }
-
- // |packet_dump_callback_| must be called on the UI thread.
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::BindOnce(packet_dump_callback_, std::move(packet_header),
- header_length, packet_length, incoming));
-}
-
-void P2PSocketHost::IncrementDelayedPackets() {
- send_packets_delayed_total_++;
-}
-
-void P2PSocketHost::IncrementTotalSentPackets() {
- send_packets_total_++;
-}
-
-void P2PSocketHost::IncrementDelayedBytes(uint32_t size) {
- send_bytes_delayed_cur_ += size;
- if (send_bytes_delayed_cur_ > send_bytes_delayed_max_) {
- send_bytes_delayed_max_ = send_bytes_delayed_cur_;
- }
-}
-
-void P2PSocketHost::DecrementDelayedBytes(uint32_t size) {
- send_bytes_delayed_cur_ -= size;
- DCHECK_GE(send_bytes_delayed_cur_, 0);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host.h b/chromium/content/browser/renderer_host/p2p/socket_host.h
deleted file mode 100644
index f330cdd3f55..00000000000
--- a/chromium/content/browser/renderer_host/p2p/socket_host.h
+++ /dev/null
@@ -1,183 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_H_
-#define CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "content/common/content_export.h"
-#include "content/common/p2p_socket_type.h"
-#include "content/public/browser/render_process_host.h"
-#include "net/base/ip_endpoint.h"
-#include "net/socket/datagram_socket.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
-
-namespace IPC {
-class Sender;
-}
-
-namespace net {
-class URLRequestContextGetter;
-}
-
-namespace network {
-class ProxyResolvingClientSocketFactory;
-}
-
-namespace rtc {
-struct PacketOptions;
-}
-
-namespace content {
-class P2PMessageThrottler;
-
-// Base class for P2P sockets.
-class CONTENT_EXPORT P2PSocketHost {
- public:
- static const int kStunHeaderSize = 20;
- // Creates P2PSocketHost of the specific type.
- static P2PSocketHost* Create(IPC::Sender* message_sender,
- int socket_id,
- P2PSocketType type,
- net::URLRequestContextGetter* url_context,
- network::ProxyResolvingClientSocketFactory*
- proxy_resolving_socket_factory,
- P2PMessageThrottler* throttler);
-
- virtual ~P2PSocketHost();
-
- // Initalizes the socket. Returns false when initialization fails.
- // |min_port| and |max_port| specify the valid range of allowed ports.
- // |min_port| must be less than or equal to |max_port|.
- // If |min_port| is zero, |max_port| must also be zero and it means all ports
- // are valid.
- // If |local_address.port()| is zero, the socket will be initialized to a port
- // in the valid range.
- // If |local_address.port()| is nonzero and not in the valid range,
- // initialization will fail.
- virtual bool Init(const net::IPEndPoint& local_address,
- uint16_t min_port,
- uint16_t max_port,
- const P2PHostAndIPEndPoint& remote_address) = 0;
-
- // Sends |data| on the socket to |to|.
- virtual void Send(
- const net::IPEndPoint& to,
- const std::vector<char>& data,
- const rtc::PacketOptions& options,
- uint64_t packet_id,
- const net::NetworkTrafficAnnotationTag traffic_annotation) = 0;
-
- virtual std::unique_ptr<P2PSocketHost> AcceptIncomingTcpConnection(
- const net::IPEndPoint& remote_address,
- int id) = 0;
-
- virtual bool SetOption(P2PSocketOption option, int value) = 0;
-
- void StartRtpDump(
- bool incoming,
- bool outgoing,
- const RenderProcessHost::WebRtcRtpPacketCallback& packet_callback);
- void StopRtpDump(bool incoming, bool outgoing);
-
- protected:
- friend class P2PSocketHostTcpTestBase;
-
- // This should match suffix IPProtocolType defined in histograms.xml.
- enum ProtocolType { UDP = 0x1, TCP = 0x2 };
-
- // TODO(mallinath) - Remove this below enum and use one defined in
- // libjingle/souce/talk/p2p/base/stun.h
- enum StunMessageType {
- STUN_BINDING_REQUEST = 0x0001,
- STUN_BINDING_RESPONSE = 0x0101,
- STUN_BINDING_ERROR_RESPONSE = 0x0111,
- STUN_SHARED_SECRET_REQUEST = 0x0002,
- STUN_SHARED_SECRET_RESPONSE = 0x0102,
- STUN_SHARED_SECRET_ERROR_RESPONSE = 0x0112,
- STUN_ALLOCATE_REQUEST = 0x0003,
- STUN_ALLOCATE_RESPONSE = 0x0103,
- STUN_ALLOCATE_ERROR_RESPONSE = 0x0113,
- STUN_SEND_REQUEST = 0x0004,
- STUN_SEND_RESPONSE = 0x0104,
- STUN_SEND_ERROR_RESPONSE = 0x0114,
- STUN_DATA_INDICATION = 0x0115,
- TURN_SEND_INDICATION = 0x0016,
- TURN_DATA_INDICATION = 0x0017,
- TURN_CREATE_PERMISSION_REQUEST = 0x0008,
- TURN_CREATE_PERMISSION_RESPONSE = 0x0108,
- TURN_CREATE_PERMISSION_ERROR_RESPONSE = 0x0118,
- TURN_CHANNEL_BIND_REQUEST = 0x0009,
- TURN_CHANNEL_BIND_RESPONSE = 0x0109,
- TURN_CHANNEL_BIND_ERROR_RESPONSE = 0x0119,
- };
-
- enum State {
- STATE_UNINITIALIZED,
- STATE_CONNECTING,
- STATE_OPEN,
- STATE_ERROR,
- };
-
- P2PSocketHost(IPC::Sender* message_sender,
- int socket_id,
- ProtocolType protocol_type);
-
- // Verifies that the packet |data| has a valid STUN header. In case
- // of success stores type of the message in |type|.
- static bool GetStunPacketType(const char* data, int data_size,
- StunMessageType* type);
- static bool IsRequestOrResponse(StunMessageType type);
-
- static void ReportSocketError(int result, const char* histogram_name);
-
- // Calls |packet_dump_callback_| to record the RTP header.
- void DumpRtpPacket(const char* packet, size_t length, bool incoming);
-
- // A helper to dump the packet on the IO thread.
- void DumpRtpPacketOnIOThread(std::unique_ptr<uint8_t[]> packet_header,
- size_t header_length,
- size_t packet_length,
- bool incoming);
-
- // Used by subclasses to track the metrics of delayed bytes and packets.
- void IncrementDelayedPackets();
- void IncrementTotalSentPackets();
- void IncrementDelayedBytes(uint32_t size);
- void DecrementDelayedBytes(uint32_t size);
-
- IPC::Sender* message_sender_;
- int id_;
- State state_;
- bool dump_incoming_rtp_packet_;
- bool dump_outgoing_rtp_packet_;
- RenderProcessHost::WebRtcRtpPacketCallback packet_dump_callback_;
-
- ProtocolType protocol_type_;
-
- private:
- // Track total delayed packets for calculating how many packets are
- // delayed by system at the end of call.
- uint32_t send_packets_delayed_total_;
- uint32_t send_packets_total_;
-
- // Track the maximum of consecutive delayed bytes caused by system's
- // EWOULDBLOCK.
- int32_t send_bytes_delayed_max_;
- int32_t send_bytes_delayed_cur_;
-
- base::WeakPtrFactory<P2PSocketHost> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(P2PSocketHost);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_H_
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_tcp.cc b/chromium/content/browser/renderer_host/p2p/socket_host_tcp.cc
deleted file mode 100644
index efc6c63a375..00000000000
--- a/chromium/content/browser/renderer_host/p2p/socket_host_tcp.cc
+++ /dev/null
@@ -1,620 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/renderer_host/p2p/socket_host_tcp.h"
-
-#include <stddef.h>
-#include <utility>
-
-#include "base/location.h"
-#include "base/single_thread_task_runner.h"
-#include "base/sys_byteorder.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "content/common/p2p_messages.h"
-#include "ipc/ipc_sender.h"
-#include "jingle/glue/fake_ssl_client_socket.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/socket/client_socket_factory.h"
-#include "net/socket/client_socket_handle.h"
-#include "net/socket/ssl_client_socket.h"
-#include "net/socket/tcp_client_socket.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "services/network/proxy_resolving_client_socket.h"
-#include "services/network/proxy_resolving_client_socket_factory.h"
-#include "third_party/webrtc/media/base/rtputils.h"
-#include "url/gurl.h"
-
-namespace {
-
-typedef uint16_t PacketLength;
-const int kPacketHeaderSize = sizeof(PacketLength);
-const int kTcpReadBufferSize = 4096;
-const int kPacketLengthOffset = 2;
-const int kTurnChannelDataHeaderSize = 4;
-const int kTcpRecvSocketBufferSize = 128 * 1024;
-const int kTcpSendSocketBufferSize = 128 * 1024;
-
-bool IsTlsClientSocket(content::P2PSocketType type) {
- return (type == content::P2P_SOCKET_STUN_TLS_CLIENT ||
- type == content::P2P_SOCKET_TLS_CLIENT);
-}
-
-bool IsPseudoTlsClientSocket(content::P2PSocketType type) {
- return (type == content::P2P_SOCKET_SSLTCP_CLIENT ||
- type == content::P2P_SOCKET_STUN_SSLTCP_CLIENT);
-}
-
-} // namespace
-
-namespace content {
-
-P2PSocketHostTcp::SendBuffer::SendBuffer() : rtc_packet_id(-1) {}
-P2PSocketHostTcp::SendBuffer::SendBuffer(
- int32_t rtc_packet_id,
- scoped_refptr<net::DrainableIOBuffer> buffer,
- const net::NetworkTrafficAnnotationTag traffic_annotation)
- : rtc_packet_id(rtc_packet_id),
- buffer(buffer),
- traffic_annotation(traffic_annotation) {}
-P2PSocketHostTcp::SendBuffer::SendBuffer(const SendBuffer& rhs) = default;
-P2PSocketHostTcp::SendBuffer::~SendBuffer() {}
-
-P2PSocketHostTcpBase::P2PSocketHostTcpBase(
- IPC::Sender* message_sender,
- int socket_id,
- P2PSocketType type,
- net::URLRequestContextGetter* url_context,
- network::ProxyResolvingClientSocketFactory* proxy_resolving_socket_factory)
- : P2PSocketHost(message_sender, socket_id, P2PSocketHost::TCP),
- write_pending_(false),
- connected_(false),
- type_(type),
- url_context_(url_context),
- proxy_resolving_socket_factory_(proxy_resolving_socket_factory) {}
-
-P2PSocketHostTcpBase::~P2PSocketHostTcpBase() {
- if (state_ == STATE_OPEN) {
- DCHECK(socket_.get());
- socket_.reset();
- }
-}
-
-bool P2PSocketHostTcpBase::InitAccepted(
- const net::IPEndPoint& remote_address,
- std::unique_ptr<net::StreamSocket> socket) {
- DCHECK(socket);
- DCHECK_EQ(state_, STATE_UNINITIALIZED);
-
- remote_address_.ip_address = remote_address;
- // TODO(ronghuawu): Add FakeSSLServerSocket.
- socket_ = std::move(socket);
- state_ = STATE_OPEN;
- DoRead();
- return state_ != STATE_ERROR;
-}
-
-bool P2PSocketHostTcpBase::Init(const net::IPEndPoint& local_address,
- uint16_t min_port,
- uint16_t max_port,
- const P2PHostAndIPEndPoint& remote_address) {
- DCHECK_EQ(state_, STATE_UNINITIALIZED);
-
- remote_address_ = remote_address;
- state_ = STATE_CONNECTING;
-
- net::HostPortPair dest_host_port_pair;
- // If there is a domain name, let's try it first, it's required by some proxy
- // to only take hostname for CONNECT. If it has been DNS resolved, the result
- // is likely cached and shouldn't cause 2nd DNS resolution in the case of
- // direct connect (i.e. no proxy).
- if (!remote_address.hostname.empty()) {
- dest_host_port_pair = net::HostPortPair(remote_address.hostname,
- remote_address.ip_address.port());
- } else {
- DCHECK(!remote_address.ip_address.address().empty());
- dest_host_port_pair = net::HostPortPair::FromIPEndPoint(
- remote_address.ip_address);
- }
-
- // TODO(mallinath) - We are ignoring local_address altogether. We should
- // find a way to inject this into ProxyResolvingClientSocket. This could be
- // a problem on multi-homed host.
-
- socket_ = proxy_resolving_socket_factory_->CreateSocket(
- GURL("https://" + dest_host_port_pair.ToString()),
- IsTlsClientSocket(type_));
-
- if (IsPseudoTlsClientSocket(type_)) {
- socket_ =
- std::make_unique<jingle_glue::FakeSSLClientSocket>(std::move(socket_));
- }
-
- int status = socket_->Connect(base::BindOnce(
- &P2PSocketHostTcpBase::OnConnected, base::Unretained(this)));
- if (status != net::ERR_IO_PENDING) {
- // We defer execution of ProcessConnectDone instead of calling it
- // directly here as the caller may not expect an error/close to
- // happen here. This is okay, as from the caller's point of view,
- // the connect always happens asynchronously.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&P2PSocketHostTcpBase::OnConnected,
- base::Unretained(this), status));
- }
-
- return state_ != STATE_ERROR;
-}
-
-void P2PSocketHostTcpBase::OnError() {
- socket_.reset();
-
- if (state_ == STATE_UNINITIALIZED || state_ == STATE_CONNECTING ||
- state_ == STATE_OPEN) {
- message_sender_->Send(new P2PMsg_OnError(id_));
- }
-
- state_ = STATE_ERROR;
-}
-
-void P2PSocketHostTcpBase::OnConnected(int result) {
- DCHECK_EQ(state_, STATE_CONNECTING);
- DCHECK_NE(result, net::ERR_IO_PENDING);
-
- if (result != net::OK) {
- LOG(WARNING) << "Error from connecting socket, result=" << result;
- OnError();
- return;
- }
-
- OnOpen();
-}
-
-void P2PSocketHostTcpBase::OnOpen() {
- state_ = STATE_OPEN;
- // Setting socket send and receive buffer size.
- if (net::OK != socket_->SetReceiveBufferSize(kTcpRecvSocketBufferSize)) {
- LOG(WARNING) << "Failed to set socket receive buffer size to "
- << kTcpRecvSocketBufferSize;
- }
-
- if (net::OK != socket_->SetSendBufferSize(kTcpSendSocketBufferSize)) {
- LOG(WARNING) << "Failed to set socket send buffer size to "
- << kTcpSendSocketBufferSize;
- }
-
- if (!DoSendSocketCreateMsg())
- return;
-
- DCHECK_EQ(state_, STATE_OPEN);
- DoRead();
-}
-
-bool P2PSocketHostTcpBase::DoSendSocketCreateMsg() {
- DCHECK(socket_.get());
-
- net::IPEndPoint local_address;
- int result = socket_->GetLocalAddress(&local_address);
- if (result < 0) {
- LOG(ERROR) << "P2PSocketHostTcpBase::OnConnected: unable to get local"
- << " address: " << result;
- OnError();
- return false;
- }
-
- VLOG(1) << "Local address: " << local_address.ToString();
-
- net::IPEndPoint remote_address;
-
- // GetPeerAddress returns ERR_NAME_NOT_RESOLVED if the socket is connected
- // through a proxy.
- result = socket_->GetPeerAddress(&remote_address);
- if (result < 0 && result != net::ERR_NAME_NOT_RESOLVED) {
- LOG(ERROR) << "P2PSocketHostTcpBase::OnConnected: unable to get peer"
- << " address: " << result;
- OnError();
- return false;
- }
-
- if (!remote_address.address().empty()) {
- VLOG(1) << "Remote address: " << remote_address.ToString();
- if (remote_address_.ip_address.address().empty()) {
- // Save |remote_address| if address is empty.
- remote_address_.ip_address = remote_address;
- }
- } else {
- VLOG(1) << "Remote address is unknown since connection is proxied";
- }
-
- // If we are not doing TLS, we are ready to send data now.
- // In case of TLS SignalConnect will be sent only after TLS handshake is
- // successful. So no buffering will be done at socket handlers if any
- // packets sent before that by the application.
- message_sender_->Send(new P2PMsg_OnSocketCreated(
- id_, local_address, remote_address));
- return true;
-}
-
-void P2PSocketHostTcpBase::DoRead() {
- int result;
- do {
- if (!read_buffer_.get()) {
- read_buffer_ = new net::GrowableIOBuffer();
- read_buffer_->SetCapacity(kTcpReadBufferSize);
- } else if (read_buffer_->RemainingCapacity() < kTcpReadBufferSize) {
- // Make sure that we always have at least kTcpReadBufferSize of
- // remaining capacity in the read buffer. Normally all packets
- // are smaller than kTcpReadBufferSize, so this is not really
- // required.
- read_buffer_->SetCapacity(read_buffer_->capacity() + kTcpReadBufferSize -
- read_buffer_->RemainingCapacity());
- }
- result = socket_->Read(
- read_buffer_.get(),
- read_buffer_->RemainingCapacity(),
- base::Bind(&P2PSocketHostTcp::OnRead, base::Unretained(this)));
- DidCompleteRead(result);
- } while (result > 0);
-}
-
-void P2PSocketHostTcpBase::OnRead(int result) {
- DidCompleteRead(result);
- if (state_ == STATE_OPEN) {
- DoRead();
- }
-}
-
-void P2PSocketHostTcpBase::OnPacket(const std::vector<char>& data) {
- if (!connected_) {
- P2PSocketHost::StunMessageType type;
- bool stun = GetStunPacketType(&*data.begin(), data.size(), &type);
- if (stun && IsRequestOrResponse(type)) {
- connected_ = true;
- } else if (!stun || type == STUN_DATA_INDICATION) {
- LOG(ERROR) << "Received unexpected data packet from "
- << remote_address_.ip_address.ToString()
- << " before STUN binding is finished. "
- << "Terminating connection.";
- OnError();
- return;
- }
- }
-
- message_sender_->Send(new P2PMsg_OnDataReceived(
- id_, remote_address_.ip_address, data, base::TimeTicks::Now()));
-
- if (dump_incoming_rtp_packet_)
- DumpRtpPacket(&data[0], data.size(), true);
-}
-
-// Note: dscp is not actually used on TCP sockets as this point,
-// but may be honored in the future.
-void P2PSocketHostTcpBase::Send(
- const net::IPEndPoint& to,
- const std::vector<char>& data,
- const rtc::PacketOptions& options,
- uint64_t packet_id,
- const net::NetworkTrafficAnnotationTag traffic_annotation) {
- if (!socket_) {
- // The Send message may be sent after the an OnError message was
- // sent by hasn't been processed the renderer.
- return;
- }
-
- if (!(to == remote_address_.ip_address)) {
- // Renderer should use this socket only to send data to |remote_address_|.
- NOTREACHED();
- OnError();
- return;
- }
-
- if (!connected_) {
- P2PSocketHost::StunMessageType type = P2PSocketHost::StunMessageType();
- bool stun = GetStunPacketType(&*data.begin(), data.size(), &type);
- if (!stun || type == STUN_DATA_INDICATION) {
- LOG(ERROR) << "Page tried to send a data packet to " << to.ToString()
- << " before STUN binding is finished.";
- OnError();
- return;
- }
- }
-
- DoSend(to, data, options, traffic_annotation);
-}
-
-void P2PSocketHostTcpBase::WriteOrQueue(SendBuffer& send_buffer) {
- IncrementTotalSentPackets();
- if (write_buffer_.buffer.get()) {
- write_queue_.push(send_buffer);
- IncrementDelayedPackets();
- IncrementDelayedBytes(send_buffer.buffer->size());
- return;
- }
-
- write_buffer_ = send_buffer;
- DoWrite();
-}
-
-void P2PSocketHostTcpBase::DoWrite() {
- while (write_buffer_.buffer.get() && state_ == STATE_OPEN &&
- !write_pending_) {
- int result = socket_->Write(
- write_buffer_.buffer.get(), write_buffer_.buffer->BytesRemaining(),
- base::Bind(&P2PSocketHostTcp::OnWritten, base::Unretained(this)),
- net::NetworkTrafficAnnotationTag(write_buffer_.traffic_annotation));
- HandleWriteResult(result);
- }
-}
-
-void P2PSocketHostTcpBase::OnWritten(int result) {
- DCHECK(write_pending_);
- DCHECK_NE(result, net::ERR_IO_PENDING);
-
- write_pending_ = false;
- HandleWriteResult(result);
- DoWrite();
-}
-
-void P2PSocketHostTcpBase::HandleWriteResult(int result) {
- DCHECK(write_buffer_.buffer.get());
- if (result >= 0) {
- write_buffer_.buffer->DidConsume(result);
- if (write_buffer_.buffer->BytesRemaining() == 0) {
- base::TimeTicks send_time = base::TimeTicks::Now();
- message_sender_->Send(new P2PMsg_OnSendComplete(
- id_,
- P2PSendPacketMetrics(0, write_buffer_.rtc_packet_id, send_time)));
- if (write_queue_.empty()) {
- write_buffer_.buffer = nullptr;
- write_buffer_.rtc_packet_id = -1;
- } else {
- write_buffer_ = write_queue_.front();
- write_queue_.pop();
- // Update how many bytes are still waiting to be sent.
- DecrementDelayedBytes(write_buffer_.buffer->size());
- }
- }
- } else if (result == net::ERR_IO_PENDING) {
- write_pending_ = true;
- } else {
- ReportSocketError(result, "WebRTC.ICE.TcpSocketWriteErrorCode");
-
- LOG(ERROR) << "Error when sending data in TCP socket: " << result;
- OnError();
- }
-}
-
-std::unique_ptr<P2PSocketHost>
-P2PSocketHostTcpBase::AcceptIncomingTcpConnection(
- const net::IPEndPoint& remote_address,
- int id) {
- NOTREACHED();
- OnError();
- return nullptr;
-}
-
-void P2PSocketHostTcpBase::DidCompleteRead(int result) {
- DCHECK_EQ(state_, STATE_OPEN);
-
- if (result == net::ERR_IO_PENDING) {
- return;
- } else if (result < 0) {
- LOG(ERROR) << "Error when reading from TCP socket: " << result;
- OnError();
- return;
- } else if (result == 0) {
- LOG(WARNING) << "Remote peer has shutdown TCP socket.";
- OnError();
- return;
- }
-
- read_buffer_->set_offset(read_buffer_->offset() + result);
- char* head = read_buffer_->StartOfBuffer(); // Purely a convenience.
- int pos = 0;
- while (pos <= read_buffer_->offset() && state_ == STATE_OPEN) {
- int consumed = ProcessInput(head + pos, read_buffer_->offset() - pos);
- if (!consumed)
- break;
- pos += consumed;
- }
- // We've consumed all complete packets from the buffer; now move any remaining
- // bytes to the head of the buffer and set offset to reflect this.
- if (pos && pos <= read_buffer_->offset()) {
- memmove(head, head + pos, read_buffer_->offset() - pos);
- read_buffer_->set_offset(read_buffer_->offset() - pos);
- }
-}
-
-bool P2PSocketHostTcpBase::SetOption(P2PSocketOption option, int value) {
- if (state_ != STATE_OPEN) {
- DCHECK_EQ(state_, STATE_ERROR);
- return false;
- }
-
- switch (option) {
- case P2P_SOCKET_OPT_RCVBUF:
- return socket_->SetReceiveBufferSize(value) == net::OK;
- case P2P_SOCKET_OPT_SNDBUF:
- return socket_->SetSendBufferSize(value) == net::OK;
- case P2P_SOCKET_OPT_DSCP:
- return false; // For TCP sockets DSCP setting is not available.
- default:
- NOTREACHED();
- return false;
- }
-}
-
-P2PSocketHostTcp::P2PSocketHostTcp(
- IPC::Sender* message_sender,
- int socket_id,
- P2PSocketType type,
- net::URLRequestContextGetter* url_context,
- network::ProxyResolvingClientSocketFactory* proxy_resolving_socket_factory)
- : P2PSocketHostTcpBase(message_sender,
- socket_id,
- type,
- url_context,
- proxy_resolving_socket_factory) {
- DCHECK(type == P2P_SOCKET_TCP_CLIENT ||
- type == P2P_SOCKET_SSLTCP_CLIENT ||
- type == P2P_SOCKET_TLS_CLIENT);
-}
-
-P2PSocketHostTcp::~P2PSocketHostTcp() {
-}
-
-int P2PSocketHostTcp::ProcessInput(char* input, int input_len) {
- if (input_len < kPacketHeaderSize)
- return 0;
- int packet_size = base::NetToHost16(*reinterpret_cast<uint16_t*>(input));
- if (input_len < packet_size + kPacketHeaderSize)
- return 0;
-
- int consumed = kPacketHeaderSize;
- char* cur = input + consumed;
- std::vector<char> data(cur, cur + packet_size);
- OnPacket(data);
- consumed += packet_size;
- return consumed;
-}
-
-void P2PSocketHostTcp::DoSend(
- const net::IPEndPoint& to,
- const std::vector<char>& data,
- const rtc::PacketOptions& options,
- const net::NetworkTrafficAnnotationTag traffic_annotation) {
- int size = kPacketHeaderSize + data.size();
- SendBuffer send_buffer(
- options.packet_id,
- new net::DrainableIOBuffer(new net::IOBuffer(size), size),
- traffic_annotation);
- *reinterpret_cast<uint16_t*>(send_buffer.buffer->data()) =
- base::HostToNet16(data.size());
- memcpy(send_buffer.buffer->data() + kPacketHeaderSize, &data[0], data.size());
-
- cricket::ApplyPacketOptions(
- reinterpret_cast<uint8_t*>(send_buffer.buffer->data()) +
- kPacketHeaderSize,
- send_buffer.buffer->BytesRemaining() - kPacketHeaderSize,
- options.packet_time_params,
- (base::TimeTicks::Now() - base::TimeTicks()).InMicroseconds());
-
- WriteOrQueue(send_buffer);
-}
-
-// P2PSocketHostStunTcp
-P2PSocketHostStunTcp::P2PSocketHostStunTcp(
- IPC::Sender* message_sender,
- int socket_id,
- P2PSocketType type,
- net::URLRequestContextGetter* url_context,
- network::ProxyResolvingClientSocketFactory* proxy_resolving_socket_factory)
- : P2PSocketHostTcpBase(message_sender,
- socket_id,
- type,
- url_context,
- proxy_resolving_socket_factory) {
- DCHECK(type == P2P_SOCKET_STUN_TCP_CLIENT ||
- type == P2P_SOCKET_STUN_SSLTCP_CLIENT ||
- type == P2P_SOCKET_STUN_TLS_CLIENT);
-}
-
-P2PSocketHostStunTcp::~P2PSocketHostStunTcp() {
-}
-
-int P2PSocketHostStunTcp::ProcessInput(char* input, int input_len) {
- if (input_len < kPacketHeaderSize + kPacketLengthOffset)
- return 0;
-
- int pad_bytes;
- int packet_size = GetExpectedPacketSize(
- input, input_len, &pad_bytes);
-
- if (input_len < packet_size + pad_bytes)
- return 0;
-
- // We have a complete packet. Read through it.
- int consumed = 0;
- char* cur = input;
- std::vector<char> data(cur, cur + packet_size);
- OnPacket(data);
- consumed += packet_size;
- consumed += pad_bytes;
- return consumed;
-}
-
-void P2PSocketHostStunTcp::DoSend(
- const net::IPEndPoint& to,
- const std::vector<char>& data,
- const rtc::PacketOptions& options,
- const net::NetworkTrafficAnnotationTag traffic_annotation) {
- // Each packet is expected to have header (STUN/TURN ChannelData), where
- // header contains message type and and length of message.
- if (data.size() < kPacketHeaderSize + kPacketLengthOffset) {
- NOTREACHED();
- OnError();
- return;
- }
-
- int pad_bytes;
- size_t expected_len = GetExpectedPacketSize(
- &data[0], data.size(), &pad_bytes);
-
- // Accepts only complete STUN/TURN packets.
- if (data.size() != expected_len) {
- NOTREACHED();
- OnError();
- return;
- }
-
- // Add any pad bytes to the total size.
- int size = data.size() + pad_bytes;
-
- SendBuffer send_buffer(
- options.packet_id,
- new net::DrainableIOBuffer(new net::IOBuffer(size), size),
- traffic_annotation);
- memcpy(send_buffer.buffer->data(), &data[0], data.size());
-
- cricket::ApplyPacketOptions(
- reinterpret_cast<uint8_t*>(send_buffer.buffer->data()), data.size(),
- options.packet_time_params,
- (base::TimeTicks::Now() - base::TimeTicks()).InMicroseconds());
-
- if (pad_bytes) {
- char padding[4] = {0};
- DCHECK_LE(pad_bytes, 4);
- memcpy(send_buffer.buffer->data() + data.size(), padding, pad_bytes);
- }
- WriteOrQueue(send_buffer);
-
- if (dump_outgoing_rtp_packet_)
- DumpRtpPacket(send_buffer.buffer->data(), data.size(), false);
-}
-
-int P2PSocketHostStunTcp::GetExpectedPacketSize(
- const char* data, int len, int* pad_bytes) {
- DCHECK_LE(kTurnChannelDataHeaderSize, len);
- // Both stun and turn had length at offset 2.
- int packet_size = base::NetToHost16(
- *reinterpret_cast<const uint16_t*>(data + kPacketLengthOffset));
-
- // Get packet type (STUN or TURN).
- uint16_t msg_type =
- base::NetToHost16(*reinterpret_cast<const uint16_t*>(data));
-
- *pad_bytes = 0;
- // Add heder length to packet length.
- if ((msg_type & 0xC000) == 0) {
- packet_size += kStunHeaderSize;
- } else {
- packet_size += kTurnChannelDataHeaderSize;
- // Calculate any padding if present.
- if (packet_size % 4)
- *pad_bytes = 4 - packet_size % 4;
- }
- return packet_size;
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_tcp.h b/chromium/content/browser/renderer_host/p2p/socket_host_tcp.h
deleted file mode 100644
index 6031e5d70a6..00000000000
--- a/chromium/content/browser/renderer_host/p2p/socket_host_tcp.h
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_TCP_H_
-#define CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_TCP_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/containers/queue.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "content/browser/renderer_host/p2p/socket_host.h"
-#include "content/common/p2p_socket_type.h"
-#include "net/base/completion_callback.h"
-#include "net/base/ip_endpoint.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
-
-namespace network {
-class ProxyResolvingClientSocketFactory;
-} // namespace network
-
-namespace net {
-class DrainableIOBuffer;
-class GrowableIOBuffer;
-class StreamSocket;
-class URLRequestContextGetter;
-} // namespace net
-
-namespace content {
-
-class CONTENT_EXPORT P2PSocketHostTcpBase : public P2PSocketHost {
- public:
- P2PSocketHostTcpBase(IPC::Sender* message_sender,
- int socket_id,
- P2PSocketType type,
- net::URLRequestContextGetter* url_context,
- network::ProxyResolvingClientSocketFactory*
- proxy_resolving_socket_factory);
- ~P2PSocketHostTcpBase() override;
-
- bool InitAccepted(const net::IPEndPoint& remote_address,
- std::unique_ptr<net::StreamSocket> socket);
-
- // P2PSocketHost overrides.
- bool Init(const net::IPEndPoint& local_address,
- uint16_t min_port,
- uint16_t max_port,
- const P2PHostAndIPEndPoint& remote_address) override;
- void Send(const net::IPEndPoint& to,
- const std::vector<char>& data,
- const rtc::PacketOptions& options,
- uint64_t packet_id,
- const net::NetworkTrafficAnnotationTag traffic_annotation) override;
- std::unique_ptr<P2PSocketHost> AcceptIncomingTcpConnection(
- const net::IPEndPoint& remote_address,
- int id) override;
- bool SetOption(P2PSocketOption option, int value) override;
-
- protected:
- struct SendBuffer {
- SendBuffer();
- SendBuffer(int32_t packet_id,
- scoped_refptr<net::DrainableIOBuffer> buffer,
- const net::NetworkTrafficAnnotationTag traffic_annotation);
- SendBuffer(const SendBuffer& rhs);
- ~SendBuffer();
-
- int32_t rtc_packet_id;
- scoped_refptr<net::DrainableIOBuffer> buffer;
- net::MutableNetworkTrafficAnnotationTag traffic_annotation;
- };
-
- // Derived classes will provide the implementation.
- virtual int ProcessInput(char* input, int input_len) = 0;
- virtual void DoSend(
- const net::IPEndPoint& to,
- const std::vector<char>& data,
- const rtc::PacketOptions& options,
- const net::NetworkTrafficAnnotationTag traffic_annotation) = 0;
-
- void WriteOrQueue(SendBuffer& send_buffer);
- void OnPacket(const std::vector<char>& data);
- void OnError();
-
- private:
- friend class P2PSocketHostTcpTestBase;
- friend class P2PSocketHostTcpServerTest;
-
- void DidCompleteRead(int result);
- void DoRead();
-
- void DoWrite();
- void HandleWriteResult(int result);
-
- // Callbacks for Connect(), Read() and Write().
- void OnConnected(int result);
- void OnRead(int result);
- void OnWritten(int result);
-
- // Helper method to send socket create message and start read.
- void OnOpen();
- bool DoSendSocketCreateMsg();
-
- P2PHostAndIPEndPoint remote_address_;
-
- std::unique_ptr<net::StreamSocket> socket_;
- scoped_refptr<net::GrowableIOBuffer> read_buffer_;
- base::queue<SendBuffer> write_queue_;
- SendBuffer write_buffer_;
-
- bool write_pending_;
-
- bool connected_;
- P2PSocketType type_;
- scoped_refptr<net::URLRequestContextGetter> url_context_;
- network::ProxyResolvingClientSocketFactory* proxy_resolving_socket_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(P2PSocketHostTcpBase);
-};
-
-class CONTENT_EXPORT P2PSocketHostTcp : public P2PSocketHostTcpBase {
- public:
- P2PSocketHostTcp(IPC::Sender* message_sender,
- int socket_id,
- P2PSocketType type,
- net::URLRequestContextGetter* url_context,
- network::ProxyResolvingClientSocketFactory*
- proxy_resolving_socket_factory);
-
- ~P2PSocketHostTcp() override;
-
- protected:
- int ProcessInput(char* input, int input_len) override;
- void DoSend(
- const net::IPEndPoint& to,
- const std::vector<char>& data,
- const rtc::PacketOptions& options,
- const net::NetworkTrafficAnnotationTag traffic_annotation) override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(P2PSocketHostTcp);
-};
-
-// P2PSocketHostStunTcp class provides the framing of STUN messages when used
-// with TURN. These messages will not have length at front of the packet and
-// are padded to multiple of 4 bytes.
-// Formatting of messages is defined in RFC5766.
-class CONTENT_EXPORT P2PSocketHostStunTcp : public P2PSocketHostTcpBase {
- public:
- P2PSocketHostStunTcp(IPC::Sender* message_sender,
- int socket_id,
- P2PSocketType type,
- net::URLRequestContextGetter* url_context,
- network::ProxyResolvingClientSocketFactory*
- proxy_resolving_socket_factory);
-
- ~P2PSocketHostStunTcp() override;
-
- protected:
- int ProcessInput(char* input, int input_len) override;
- void DoSend(
- const net::IPEndPoint& to,
- const std::vector<char>& data,
- const rtc::PacketOptions& options,
- const net::NetworkTrafficAnnotationTag traffic_annotation) override;
-
- private:
- int GetExpectedPacketSize(const char* data, int len, int* pad_bytes);
-
- DISALLOW_COPY_AND_ASSIGN(P2PSocketHostStunTcp);
-};
-
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_TCP_H_
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_tcp_server.cc b/chromium/content/browser/renderer_host/p2p/socket_host_tcp_server.cc
deleted file mode 100644
index 628b90de501..00000000000
--- a/chromium/content/browser/renderer_host/p2p/socket_host_tcp_server.cc
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/renderer_host/p2p/socket_host_tcp_server.h"
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "content/browser/renderer_host/p2p/socket_host_tcp.h"
-#include "content/common/p2p_messages.h"
-#include "net/base/address_list.h"
-#include "net/base/net_errors.h"
-#include "net/log/net_log_source.h"
-#include "net/socket/stream_socket.h"
-
-namespace {
-const int kListenBacklog = 5;
-} // namespace
-
-namespace content {
-
-P2PSocketHostTcpServer::P2PSocketHostTcpServer(IPC::Sender* message_sender,
- int socket_id,
- P2PSocketType client_type)
- : P2PSocketHost(message_sender, socket_id, P2PSocketHost::TCP),
- client_type_(client_type),
- socket_(new net::TCPServerSocket(nullptr, net::NetLogSource())),
- accept_callback_(base::Bind(&P2PSocketHostTcpServer::OnAccepted,
- base::Unretained(this))) {
-}
-
-P2PSocketHostTcpServer::~P2PSocketHostTcpServer() {
- if (state_ == STATE_OPEN) {
- DCHECK(socket_.get());
- socket_.reset();
- }
-}
-
-// TODO(guidou): Add support for port range.
-bool P2PSocketHostTcpServer::Init(const net::IPEndPoint& local_address,
- uint16_t min_port,
- uint16_t max_port,
- const P2PHostAndIPEndPoint& remote_address) {
- DCHECK_EQ(state_, STATE_UNINITIALIZED);
-
- int result = socket_->Listen(local_address, kListenBacklog);
- if (result < 0) {
- LOG(ERROR) << "Listen() failed: " << result;
- OnError();
- return false;
- }
-
- result = socket_->GetLocalAddress(&local_address_);
- if (result < 0) {
- LOG(ERROR) << "P2PSocketHostTcpServer::Init(): can't to get local address: "
- << result;
- OnError();
- return false;
- }
- VLOG(1) << "Local address: " << local_address_.ToString();
-
- state_ = STATE_OPEN;
- // NOTE: Remote address can be empty as socket is just listening
- // in this state.
- message_sender_->Send(new P2PMsg_OnSocketCreated(
- id_, local_address_, remote_address.ip_address));
- DoAccept();
- return true;
-}
-
-void P2PSocketHostTcpServer::OnError() {
- socket_.reset();
-
- if (state_ == STATE_UNINITIALIZED || state_ == STATE_OPEN)
- message_sender_->Send(new P2PMsg_OnError(id_));
-
- state_ = STATE_ERROR;
-}
-
-void P2PSocketHostTcpServer::DoAccept() {
- while (true) {
- int result = socket_->Accept(&accept_socket_, accept_callback_);
- if (result == net::ERR_IO_PENDING) {
- break;
- } else {
- HandleAcceptResult(result);
- }
- }
-}
-
-void P2PSocketHostTcpServer::HandleAcceptResult(int result) {
- if (result < 0) {
- if (result != net::ERR_IO_PENDING)
- OnError();
- return;
- }
-
- net::IPEndPoint address;
- if (accept_socket_->GetPeerAddress(&address) != net::OK) {
- LOG(ERROR) << "Failed to get address of an accepted socket.";
- accept_socket_.reset();
- return;
- }
- accepted_sockets_[address] = std::move(accept_socket_);
- message_sender_->Send(
- new P2PMsg_OnIncomingTcpConnection(id_, address));
-}
-
-void P2PSocketHostTcpServer::OnAccepted(int result) {
- HandleAcceptResult(result);
- if (result == net::OK)
- DoAccept();
-}
-
-void P2PSocketHostTcpServer::Send(
- const net::IPEndPoint& to,
- const std::vector<char>& data,
- const rtc::PacketOptions& options,
- uint64_t packet_id,
- const net::NetworkTrafficAnnotationTag traffic_annotation) {
- NOTREACHED();
- OnError();
-}
-
-std::unique_ptr<P2PSocketHost>
-P2PSocketHostTcpServer::AcceptIncomingTcpConnection(
- const net::IPEndPoint& remote_address,
- int id) {
- auto it = accepted_sockets_.find(remote_address);
- if (it == accepted_sockets_.end())
- return nullptr;
-
- std::unique_ptr<net::StreamSocket> socket = std::move(it->second);
- accepted_sockets_.erase(it);
-
- std::unique_ptr<P2PSocketHostTcpBase> result;
- if (client_type_ == P2P_SOCKET_TCP_CLIENT) {
- result.reset(new P2PSocketHostTcp(message_sender_, id, client_type_,
- nullptr, nullptr));
- } else {
- result.reset(new P2PSocketHostStunTcp(message_sender_, id, client_type_,
- nullptr, nullptr));
- }
- if (!result->InitAccepted(remote_address, std::move(socket)))
- return nullptr;
- return std::move(result);
-}
-
-bool P2PSocketHostTcpServer::SetOption(P2PSocketOption option,
- int value) {
- // Currently we don't have use case tcp server sockets are used for p2p.
- return false;
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_tcp_server.h b/chromium/content/browser/renderer_host/p2p/socket_host_tcp_server.h
deleted file mode 100644
index 9b249463ff4..00000000000
--- a/chromium/content/browser/renderer_host/p2p/socket_host_tcp_server.h
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_TCP_SERVER_H_
-#define CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_TCP_SERVER_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "content/browser/renderer_host/p2p/socket_host.h"
-#include "content/common/content_export.h"
-#include "content/common/p2p_socket_type.h"
-#include "ipc/ipc_sender.h"
-#include "net/base/completion_callback.h"
-#include "net/socket/tcp_server_socket.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
-
-namespace net {
-class StreamSocket;
-} // namespace net
-
-namespace content {
-
-class CONTENT_EXPORT P2PSocketHostTcpServer : public P2PSocketHost {
- public:
- P2PSocketHostTcpServer(IPC::Sender* message_sender,
- int socket_id,
- P2PSocketType client_type);
- ~P2PSocketHostTcpServer() override;
-
- // P2PSocketHost overrides.
- bool Init(const net::IPEndPoint& local_address,
- uint16_t min_port,
- uint16_t max_port,
- const P2PHostAndIPEndPoint& remote_address) override;
- void Send(const net::IPEndPoint& to,
- const std::vector<char>& data,
- const rtc::PacketOptions& options,
- uint64_t packet_id,
- const net::NetworkTrafficAnnotationTag traffic_annotation) override;
- std::unique_ptr<P2PSocketHost> AcceptIncomingTcpConnection(
- const net::IPEndPoint& remote_address,
- int id) override;
- bool SetOption(P2PSocketOption option, int value) override;
-
- private:
- friend class P2PSocketHostTcpServerTest;
-
- void OnError();
-
- void DoAccept();
- void HandleAcceptResult(int result);
-
- // Callback for Accept().
- void OnAccepted(int result);
-
- const P2PSocketType client_type_;
- std::unique_ptr<net::ServerSocket> socket_;
- net::IPEndPoint local_address_;
-
- std::unique_ptr<net::StreamSocket> accept_socket_;
- std::map<net::IPEndPoint, std::unique_ptr<net::StreamSocket>>
- accepted_sockets_;
-
- net::CompletionCallback accept_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(P2PSocketHostTcpServer);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_TCP_SERVER_H_
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc b/chromium/content/browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc
deleted file mode 100644
index ca1ea46195c..00000000000
--- a/chromium/content/browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/renderer_host/p2p/socket_host_tcp_server.h"
-
-#include <stdint.h>
-
-#include <list>
-
-#include "content/browser/renderer_host/p2p/socket_host_tcp.h"
-#include "content/browser/renderer_host/p2p/socket_host_test_utils.h"
-#include "net/base/completion_callback.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using ::testing::_;
-using ::testing::DeleteArg;
-using ::testing::DoAll;
-using ::testing::Return;
-
-namespace {
-
-class FakeServerSocket : public net::ServerSocket {
- public:
- FakeServerSocket() : listening_(false), accept_socket_(nullptr) {}
-
- ~FakeServerSocket() override {}
-
- bool listening() { return listening_; }
-
- void AddIncoming(net::StreamSocket* socket) {
- if (!accept_callback_.is_null()) {
- DCHECK(incoming_sockets_.empty());
- accept_socket_->reset(socket);
- accept_socket_ = nullptr;
-
- // This copy is necessary because this implementation of ServerSocket
- // bases logic on the null-ness of |accept_callback_| in the bound
- // callback.
- net::CompletionCallback cb = accept_callback_;
- accept_callback_.Reset();
- std::move(cb).Run(net::OK);
- } else {
- incoming_sockets_.push_back(socket);
- }
- }
-
- int Listen(const net::IPEndPoint& address, int backlog) override {
- local_address_ = address;
- listening_ = true;
- return net::OK;
- }
-
- int GetLocalAddress(net::IPEndPoint* address) const override {
- *address = local_address_;
- return net::OK;
- }
-
- int Accept(std::unique_ptr<net::StreamSocket>* socket,
- const net::CompletionCallback& callback) override {
- DCHECK(socket);
- if (!incoming_sockets_.empty()) {
- socket->reset(incoming_sockets_.front());
- incoming_sockets_.pop_front();
- return net::OK;
- } else {
- accept_socket_ = socket;
- accept_callback_ = callback;
- return net::ERR_IO_PENDING;
- }
- }
-
- private:
- bool listening_;
-
- net::IPEndPoint local_address_;
-
- std::unique_ptr<net::StreamSocket>* accept_socket_;
- net::CompletionCallback accept_callback_;
-
- std::list<net::StreamSocket*> incoming_sockets_;
-};
-
-} // namespace
-
-namespace content {
-
-class P2PSocketHostTcpServerTest : public testing::Test {
- protected:
- void SetUp() override {
- socket_ = new FakeServerSocket();
- socket_host_.reset(
- new P2PSocketHostTcpServer(&sender_, 0, P2P_SOCKET_TCP_CLIENT));
- socket_host_->socket_.reset(socket_);
-
- EXPECT_CALL(
- sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnSocketCreated::ID))))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-
- P2PHostAndIPEndPoint dest;
- dest.ip_address = ParseAddress(kTestIpAddress1, kTestPort1);
-
- socket_host_->Init(ParseAddress(kTestLocalIpAddress, 0), 0, 0, dest);
- EXPECT_TRUE(socket_->listening());
- }
-
- // Needed by the chilt classes because only this class is a friend
- // of P2PSocketHostTcp.
- net::StreamSocket* GetSocketFormTcpSocketHost(P2PSocketHostTcp* host) {
- return host->socket_.get();
- }
-
- MockIPCSender sender_;
- FakeServerSocket* socket_; // Owned by |socket_host_|.
- std::unique_ptr<P2PSocketHostTcpServer> socket_host_;
-};
-
-// Accept incoming connection.
-TEST_F(P2PSocketHostTcpServerTest, Accept) {
- FakeSocket* incoming = new FakeSocket(nullptr);
- incoming->SetLocalAddress(ParseAddress(kTestLocalIpAddress, kTestPort1));
- net::IPEndPoint addr = ParseAddress(kTestIpAddress1, kTestPort1);
- incoming->SetPeerAddress(addr);
-
- EXPECT_CALL(sender_, Send(MatchIncomingSocketMessage(addr)))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- socket_->AddIncoming(incoming);
-
- const int kAcceptedSocketId = 1;
-
- std::unique_ptr<P2PSocketHost> new_host(
- socket_host_->AcceptIncomingTcpConnection(addr, kAcceptedSocketId));
- ASSERT_TRUE(new_host.get() != nullptr);
- EXPECT_EQ(incoming, GetSocketFormTcpSocketHost(
- reinterpret_cast<P2PSocketHostTcp*>(new_host.get())));
-}
-
-// Accept 2 simultaneous connections.
-TEST_F(P2PSocketHostTcpServerTest, Accept2) {
- FakeSocket* incoming1 = new FakeSocket(nullptr);
- incoming1->SetLocalAddress(ParseAddress(kTestLocalIpAddress, kTestPort1));
- net::IPEndPoint addr1 = ParseAddress(kTestIpAddress1, kTestPort1);
- incoming1->SetPeerAddress(addr1);
- FakeSocket* incoming2 = new FakeSocket(nullptr);
- incoming2->SetLocalAddress(ParseAddress(kTestLocalIpAddress, kTestPort1));
- net::IPEndPoint addr2 = ParseAddress(kTestIpAddress2, kTestPort2);
- incoming2->SetPeerAddress(addr2);
-
- EXPECT_CALL(sender_, Send(MatchIncomingSocketMessage(addr1)))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- EXPECT_CALL(sender_, Send(MatchIncomingSocketMessage(addr2)))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- socket_->AddIncoming(incoming1);
- socket_->AddIncoming(incoming2);
-
- const int kAcceptedSocketId1 = 1;
- const int kAcceptedSocketId2 = 2;
-
- std::unique_ptr<P2PSocketHost> new_host1(
- socket_host_->AcceptIncomingTcpConnection(addr1, kAcceptedSocketId1));
- ASSERT_TRUE(new_host1.get() != nullptr);
- EXPECT_EQ(incoming1, GetSocketFormTcpSocketHost(
- reinterpret_cast<P2PSocketHostTcp*>(new_host1.get())));
- std::unique_ptr<P2PSocketHost> new_host2(
- socket_host_->AcceptIncomingTcpConnection(addr2, kAcceptedSocketId2));
- ASSERT_TRUE(new_host2.get() != nullptr);
- EXPECT_EQ(incoming2, GetSocketFormTcpSocketHost(
- reinterpret_cast<P2PSocketHostTcp*>(new_host2.get())));
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_tcp_unittest.cc b/chromium/content/browser/renderer_host/p2p/socket_host_tcp_unittest.cc
deleted file mode 100644
index 1017d6bb1d9..00000000000
--- a/chromium/content/browser/renderer_host/p2p/socket_host_tcp_unittest.cc
+++ /dev/null
@@ -1,581 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/renderer_host/p2p/socket_host_tcp.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/sys_byteorder.h"
-#include "base/test/scoped_task_environment.h"
-#include "content/browser/renderer_host/p2p/socket_host_test_utils.h"
-#include "jingle/glue/fake_ssl_client_socket.h"
-#include "net/socket/socket_test_util.h"
-#include "net/socket/stream_socket.h"
-#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "net/url_request/url_request_test_util.h"
-#include "services/network/proxy_resolving_client_socket_factory.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using ::testing::_;
-using ::testing::DeleteArg;
-using ::testing::DoAll;
-using ::testing::Return;
-
-namespace content {
-
-class P2PSocketHostTcpTestBase : public testing::Test {
- protected:
- explicit P2PSocketHostTcpTestBase(P2PSocketType type)
- : socket_type_(type) {
- }
-
- void SetUp() override {
- EXPECT_CALL(
- sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnSocketCreated::ID))))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-
- if (socket_type_ == P2P_SOCKET_TCP_CLIENT) {
- socket_host_.reset(new P2PSocketHostTcp(
- &sender_, 0, P2P_SOCKET_TCP_CLIENT, nullptr, nullptr));
- } else {
- socket_host_.reset(new P2PSocketHostStunTcp(
- &sender_, 0, P2P_SOCKET_STUN_TCP_CLIENT, nullptr, nullptr));
- }
-
- socket_ = new FakeSocket(&sent_data_);
- socket_->SetLocalAddress(ParseAddress(kTestLocalIpAddress, kTestPort1));
- socket_host_->socket_.reset(socket_);
-
- dest_.ip_address = ParseAddress(kTestIpAddress1, kTestPort1);
-
- local_address_ = ParseAddress(kTestLocalIpAddress, kTestPort1);
-
- socket_host_->remote_address_ = dest_;
- socket_host_->state_ = P2PSocketHost::STATE_CONNECTING;
- socket_host_->OnConnected(net::OK);
- }
-
- std::string IntToSize(int size) {
- std::string result;
- uint16_t size16 = base::HostToNet16(size);
- result.resize(sizeof(size16));
- memcpy(&result[0], &size16, sizeof(size16));
- return result;
- }
-
- std::string sent_data_;
- FakeSocket* socket_; // Owned by |socket_host_|.
- std::unique_ptr<P2PSocketHostTcpBase> socket_host_;
- MockIPCSender sender_;
-
- net::IPEndPoint local_address_;
- P2PHostAndIPEndPoint dest_;
- P2PSocketType socket_type_;
-};
-
-class P2PSocketHostTcpTest : public P2PSocketHostTcpTestBase {
- protected:
- P2PSocketHostTcpTest() : P2PSocketHostTcpTestBase(P2P_SOCKET_TCP_CLIENT) { }
-};
-
-class P2PSocketHostStunTcpTest : public P2PSocketHostTcpTestBase {
- protected:
- P2PSocketHostStunTcpTest()
- : P2PSocketHostTcpTestBase(P2P_SOCKET_STUN_TCP_CLIENT) {
- }
-};
-
-// Verify that we can send STUN message and that they are formatted
-// properly.
-TEST_F(P2PSocketHostTcpTest, SendStunNoAuth) {
- EXPECT_CALL(
- sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnSendComplete::ID))))
- .Times(3)
- .WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
-
- rtc::PacketOptions options;
- std::vector<char> packet1;
- CreateStunRequest(&packet1);
- socket_host_->Send(dest_.ip_address, packet1, options, 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- std::vector<char> packet2;
- CreateStunResponse(&packet2);
- socket_host_->Send(dest_.ip_address, packet2, options, 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- std::vector<char> packet3;
- CreateStunError(&packet3);
- socket_host_->Send(dest_.ip_address, packet3, options, 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- std::string expected_data;
- expected_data.append(IntToSize(packet1.size()));
- expected_data.append(packet1.begin(), packet1.end());
- expected_data.append(IntToSize(packet2.size()));
- expected_data.append(packet2.begin(), packet2.end());
- expected_data.append(IntToSize(packet3.size()));
- expected_data.append(packet3.begin(), packet3.end());
-
- EXPECT_EQ(expected_data, sent_data_);
-}
-
-// Verify that we can receive STUN messages from the socket, and that
-// the messages are parsed properly.
-TEST_F(P2PSocketHostTcpTest, ReceiveStun) {
- EXPECT_CALL(
- sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnSendComplete::ID))))
- .Times(3)
- .WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
-
- rtc::PacketOptions options;
- std::vector<char> packet1;
- CreateStunRequest(&packet1);
- socket_host_->Send(dest_.ip_address, packet1, options, 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- std::vector<char> packet2;
- CreateStunResponse(&packet2);
- socket_host_->Send(dest_.ip_address, packet2, options, 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- std::vector<char> packet3;
- CreateStunError(&packet3);
- socket_host_->Send(dest_.ip_address, packet3, options, 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- std::string received_data;
- received_data.append(IntToSize(packet1.size()));
- received_data.append(packet1.begin(), packet1.end());
- received_data.append(IntToSize(packet2.size()));
- received_data.append(packet2.begin(), packet2.end());
- received_data.append(IntToSize(packet3.size()));
- received_data.append(packet3.begin(), packet3.end());
-
- EXPECT_CALL(sender_, Send(MatchPacketMessage(packet1)))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- EXPECT_CALL(sender_, Send(MatchPacketMessage(packet2)))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- EXPECT_CALL(sender_, Send(MatchPacketMessage(packet3)))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-
- size_t pos = 0;
- size_t step_sizes[] = {3, 2, 1};
- size_t step = 0;
- while (pos < received_data.size()) {
- size_t step_size = std::min(step_sizes[step], received_data.size() - pos);
- socket_->AppendInputData(&received_data[pos], step_size);
- pos += step_size;
- if (++step >= arraysize(step_sizes))
- step = 0;
- }
-}
-
-// Verify that we can't send data before we've received STUN response
-// from the other side.
-TEST_F(P2PSocketHostTcpTest, SendDataNoAuth) {
- EXPECT_CALL(sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnError::ID))))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-
- rtc::PacketOptions options;
- std::vector<char> packet;
- CreateRandomPacket(&packet);
- socket_host_->Send(dest_.ip_address, packet, options, 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- EXPECT_EQ(0U, sent_data_.size());
-}
-
-// Verify that SetOption() doesn't crash after an error.
-TEST_F(P2PSocketHostTcpTest, SetOptionAfterError) {
- // Get the sender into the error state.
- EXPECT_CALL(sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnError::ID))))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- socket_host_->Send(dest_.ip_address, {1, 2, 3, 4}, rtc::PacketOptions(), 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
- testing::Mock::VerifyAndClearExpectations(&sender_);
-
- // Verify that SetOptions() fails, but doesn't crash.
- EXPECT_FALSE(socket_host_->SetOption(P2P_SOCKET_OPT_RCVBUF, 2048));
-}
-
-// Verify that we can send data after we've received STUN response
-// from the other side.
-TEST_F(P2PSocketHostTcpTest, SendAfterStunRequest) {
- // Receive packet from |dest_|.
- std::vector<char> request_packet;
- CreateStunRequest(&request_packet);
-
- std::string received_data;
- received_data.append(IntToSize(request_packet.size()));
- received_data.append(request_packet.begin(), request_packet.end());
-
- EXPECT_CALL(
- sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnSendComplete::ID))))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- EXPECT_CALL(sender_, Send(MatchPacketMessage(request_packet)))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- socket_->AppendInputData(&received_data[0], received_data.size());
-
- rtc::PacketOptions options;
- // Now we should be able to send any data to |dest_|.
- std::vector<char> packet;
- CreateRandomPacket(&packet);
- socket_host_->Send(dest_.ip_address, packet, options, 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- std::string expected_data;
- expected_data.append(IntToSize(packet.size()));
- expected_data.append(packet.begin(), packet.end());
-
- EXPECT_EQ(expected_data, sent_data_);
-}
-
-// Verify that asynchronous writes are handled correctly.
-TEST_F(P2PSocketHostTcpTest, AsyncWrites) {
- base::MessageLoop message_loop;
-
- socket_->set_async_write(true);
-
- EXPECT_CALL(
- sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnSendComplete::ID))))
- .Times(2)
- .WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
-
- rtc::PacketOptions options;
- std::vector<char> packet1;
- CreateStunRequest(&packet1);
-
- socket_host_->Send(dest_.ip_address, packet1, options, 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- std::vector<char> packet2;
- CreateStunResponse(&packet2);
- socket_host_->Send(dest_.ip_address, packet2, options, 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- base::RunLoop().RunUntilIdle();
-
- std::string expected_data;
- expected_data.append(IntToSize(packet1.size()));
- expected_data.append(packet1.begin(), packet1.end());
- expected_data.append(IntToSize(packet2.size()));
- expected_data.append(packet2.begin(), packet2.end());
-
- EXPECT_EQ(expected_data, sent_data_);
-}
-
-TEST_F(P2PSocketHostTcpTest, PacketIdIsPropagated) {
- base::MessageLoop message_loop;
-
- socket_->set_async_write(true);
-
- const int32_t kRtcPacketId = 1234;
-
- base::TimeTicks now = base::TimeTicks::Now();
-
- EXPECT_CALL(sender_, Send(MatchSendPacketMetrics(kRtcPacketId, now)))
- .Times(1)
- .WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
-
- rtc::PacketOptions options;
- options.packet_id = kRtcPacketId;
- std::vector<char> packet1;
- CreateStunRequest(&packet1);
-
- socket_host_->Send(dest_.ip_address, packet1, options, 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- base::RunLoop().RunUntilIdle();
-
- std::string expected_data;
- expected_data.append(IntToSize(packet1.size()));
- expected_data.append(packet1.begin(), packet1.end());
-
- EXPECT_EQ(expected_data, sent_data_);
-}
-
-TEST_F(P2PSocketHostTcpTest, SendDataWithPacketOptions) {
- std::vector<char> request_packet;
- CreateStunRequest(&request_packet);
-
- std::string received_data;
- received_data.append(IntToSize(request_packet.size()));
- received_data.append(request_packet.begin(), request_packet.end());
-
- EXPECT_CALL(
- sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnSendComplete::ID))))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- EXPECT_CALL(sender_, Send(MatchPacketMessage(request_packet)))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- socket_->AppendInputData(&received_data[0], received_data.size());
-
- rtc::PacketOptions options;
- options.packet_time_params.rtp_sendtime_extension_id = 3;
- // Now we should be able to send any data to |dest_|.
- std::vector<char> packet;
- CreateRandomPacket(&packet);
- // Make it a RTP packet.
- *reinterpret_cast<uint16_t*>(&*packet.begin()) = base::HostToNet16(0x8000);
- socket_host_->Send(dest_.ip_address, packet, options, 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- std::string expected_data;
- expected_data.append(IntToSize(packet.size()));
- expected_data.append(packet.begin(), packet.end());
-
- EXPECT_EQ(expected_data, sent_data_);
-}
-
-// Verify that we can send STUN message and that they are formatted
-// properly.
-TEST_F(P2PSocketHostStunTcpTest, SendStunNoAuth) {
- EXPECT_CALL(
- sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnSendComplete::ID))))
- .Times(3)
- .WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
-
- rtc::PacketOptions options;
- std::vector<char> packet1;
- CreateStunRequest(&packet1);
- socket_host_->Send(dest_.ip_address, packet1, options, 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- std::vector<char> packet2;
- CreateStunResponse(&packet2);
- socket_host_->Send(dest_.ip_address, packet2, options, 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- std::vector<char> packet3;
- CreateStunError(&packet3);
- socket_host_->Send(dest_.ip_address, packet3, options, 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- std::string expected_data;
- expected_data.append(packet1.begin(), packet1.end());
- expected_data.append(packet2.begin(), packet2.end());
- expected_data.append(packet3.begin(), packet3.end());
-
- EXPECT_EQ(expected_data, sent_data_);
-}
-
-// Verify that we can receive STUN messages from the socket, and that
-// the messages are parsed properly.
-TEST_F(P2PSocketHostStunTcpTest, ReceiveStun) {
- EXPECT_CALL(
- sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnSendComplete::ID))))
- .Times(3)
- .WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
-
- rtc::PacketOptions options;
- std::vector<char> packet1;
- CreateStunRequest(&packet1);
- socket_host_->Send(dest_.ip_address, packet1, options, 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- std::vector<char> packet2;
- CreateStunResponse(&packet2);
- socket_host_->Send(dest_.ip_address, packet2, options, 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- std::vector<char> packet3;
- CreateStunError(&packet3);
- socket_host_->Send(dest_.ip_address, packet3, options, 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- std::string received_data;
- received_data.append(packet1.begin(), packet1.end());
- received_data.append(packet2.begin(), packet2.end());
- received_data.append(packet3.begin(), packet3.end());
-
- EXPECT_CALL(sender_, Send(MatchPacketMessage(packet1)))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- EXPECT_CALL(sender_, Send(MatchPacketMessage(packet2)))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- EXPECT_CALL(sender_, Send(MatchPacketMessage(packet3)))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-
- size_t pos = 0;
- size_t step_sizes[] = {3, 2, 1};
- size_t step = 0;
- while (pos < received_data.size()) {
- size_t step_size = std::min(step_sizes[step], received_data.size() - pos);
- socket_->AppendInputData(&received_data[pos], step_size);
- pos += step_size;
- if (++step >= arraysize(step_sizes))
- step = 0;
- }
-}
-
-// Verify that we can't send data before we've received STUN response
-// from the other side.
-TEST_F(P2PSocketHostStunTcpTest, SendDataNoAuth) {
- EXPECT_CALL(sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnError::ID))))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-
- rtc::PacketOptions options;
- std::vector<char> packet;
- CreateRandomPacket(&packet);
- socket_host_->Send(dest_.ip_address, packet, options, 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- EXPECT_EQ(0U, sent_data_.size());
-}
-
-// Verify that asynchronous writes are handled correctly.
-TEST_F(P2PSocketHostStunTcpTest, AsyncWrites) {
- base::MessageLoop message_loop;
-
- socket_->set_async_write(true);
-
- EXPECT_CALL(
- sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnSendComplete::ID))))
- .Times(2)
- .WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
-
- rtc::PacketOptions options;
- std::vector<char> packet1;
- CreateStunRequest(&packet1);
- socket_host_->Send(dest_.ip_address, packet1, options, 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- std::vector<char> packet2;
- CreateStunResponse(&packet2);
- socket_host_->Send(dest_.ip_address, packet2, options, 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- base::RunLoop().RunUntilIdle();
-
- std::string expected_data;
- expected_data.append(packet1.begin(), packet1.end());
- expected_data.append(packet2.begin(), packet2.end());
-
- EXPECT_EQ(expected_data, sent_data_);
-}
-
-// When pseudo-tls is used (e.g. for P2P_SOCKET_SSLTCP_CLIENT),
-// network::ProxyResolvingClientSocket::Connect() won't be called twice.
-// Regression test for crbug.com/840797.
-TEST(P2PSocketHostTcpWithPseudoTlsTest, Basic) {
- base::test::ScopedTaskEnvironment scoped_task_environment(
- base::test::ScopedTaskEnvironment::MainThreadType::IO);
- MockIPCSender sender;
- EXPECT_CALL(
- sender,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnSocketCreated::ID))))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-
- net::TestURLRequestContext context(true);
- net::MockClientSocketFactory mock_socket_factory;
- context.set_client_socket_factory(&mock_socket_factory);
- context.Init();
- network::ProxyResolvingClientSocketFactory factory(&context);
-
- base::StringPiece ssl_client_hello =
- jingle_glue::FakeSSLClientSocket::GetSslClientHello();
- base::StringPiece ssl_server_hello =
- jingle_glue::FakeSSLClientSocket::GetSslServerHello();
- net::MockRead reads[] = {
- net::MockRead(net::ASYNC, ssl_server_hello.data(),
- ssl_server_hello.size()),
- net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING)};
- net::MockWrite writes[] = {net::MockWrite(
- net::SYNCHRONOUS, ssl_client_hello.data(), ssl_client_hello.size())};
- net::StaticSocketDataProvider data_provider(reads, writes);
- net::IPEndPoint server_addr(net::IPAddress::IPv4Localhost(), 1234);
- data_provider.set_connect_data(
- net::MockConnect(net::SYNCHRONOUS, net::OK, server_addr));
- mock_socket_factory.AddSocketDataProvider(&data_provider);
-
- P2PSocketHostTcp host(&sender, 0 /*socket_id*/, P2P_SOCKET_SSLTCP_CLIENT,
- nullptr, &factory);
- P2PHostAndIPEndPoint dest;
- dest.ip_address = server_addr;
- bool success = host.Init(net::IPEndPoint(net::IPAddress::IPv4Localhost(), 0),
- 0, 0, dest);
- EXPECT_TRUE(success);
-
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(data_provider.AllReadDataConsumed());
- EXPECT_TRUE(data_provider.AllWriteDataConsumed());
-}
-
-class P2PSocketHostTcpWithTlsTest
- : public testing::TestWithParam<std::tuple<net::IoMode, P2PSocketType>> {};
-
-INSTANTIATE_TEST_CASE_P(
- /* no prefix */,
- P2PSocketHostTcpWithTlsTest,
- ::testing::Combine(::testing::Values(net::SYNCHRONOUS, net::ASYNC),
- ::testing::Values(P2P_SOCKET_TLS_CLIENT,
- P2P_SOCKET_STUN_TLS_CLIENT)));
-
-// Tests that if a socket type satisfies IsTlsClientSocket(), TLS connection is
-// established.
-TEST_P(P2PSocketHostTcpWithTlsTest, Basic) {
- base::test::ScopedTaskEnvironment scoped_task_environment(
- base::test::ScopedTaskEnvironment::MainThreadType::IO);
- MockIPCSender sender;
- EXPECT_CALL(
- sender,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnSocketCreated::ID))))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-
- net::TestURLRequestContext context(true);
- net::MockClientSocketFactory mock_socket_factory;
- context.set_client_socket_factory(&mock_socket_factory);
- context.Init();
- network::ProxyResolvingClientSocketFactory factory(&context);
- const net::IoMode io_mode = std::get<0>(GetParam());
- const P2PSocketType socket_type = std::get<1>(GetParam());
- // OnOpen() calls DoRead(), so populate the mock socket with a pending read.
- net::MockRead reads[] = {
- net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING)};
- net::StaticSocketDataProvider data_provider(
- reads, base::span<const net::MockWrite>());
- net::IPEndPoint server_addr(net::IPAddress::IPv4Localhost(), 1234);
- data_provider.set_connect_data(
- net::MockConnect(io_mode, net::OK, server_addr));
- net::SSLSocketDataProvider ssl_socket_provider(io_mode, net::OK);
- mock_socket_factory.AddSocketDataProvider(&data_provider);
- mock_socket_factory.AddSSLSocketDataProvider(&ssl_socket_provider);
-
- std::unique_ptr<P2PSocketHostTcpBase> host;
- if (socket_type == P2P_SOCKET_STUN_TLS_CLIENT) {
- host = std::make_unique<P2PSocketHostStunTcp>(
- &sender, 0 /*socket_id*/, socket_type, nullptr, &factory);
- } else {
- host = std::make_unique<P2PSocketHostTcp>(&sender, 0 /*socket_id*/,
- socket_type, nullptr, &factory);
- }
- P2PHostAndIPEndPoint dest;
- dest.ip_address = server_addr;
- bool success = host->Init(net::IPEndPoint(net::IPAddress::IPv4Localhost(), 0),
- 0, 0, dest);
- EXPECT_TRUE(success);
-
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(data_provider.AllReadDataConsumed());
- EXPECT_TRUE(data_provider.AllWriteDataConsumed());
- EXPECT_TRUE(ssl_socket_provider.ConnectDataConsumed());
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_test_utils.cc b/chromium/content/browser/renderer_host/p2p/socket_host_test_utils.cc
deleted file mode 100644
index 6c18bea987b..00000000000
--- a/chromium/content/browser/renderer_host/p2p/socket_host_test_utils.cc
+++ /dev/null
@@ -1,217 +0,0 @@
-// 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 "content/browser/renderer_host/p2p/socket_host_test_utils.h"
-
-#include <stddef.h>
-
-#include "base/logging.h"
-#include "base/sys_byteorder.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "net/base/completion_callback.h"
-#include "net/base/io_buffer.h"
-#include "net/base/ip_address.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
-
-const int kStunHeaderSize = 20;
-const uint16_t kStunBindingRequest = 0x0001;
-const uint16_t kStunBindingResponse = 0x0102;
-const uint16_t kStunBindingError = 0x0111;
-const uint32_t kStunMagicCookie = 0x2112A442;
-
-MockIPCSender::MockIPCSender() { }
-MockIPCSender::~MockIPCSender() { }
-
-FakeSocket::FakeSocket(std::string* written_data)
- : read_pending_(false),
- input_pos_(0),
- written_data_(written_data),
- async_write_(false),
- write_pending_(false) {
-}
-
-FakeSocket::~FakeSocket() { }
-
-void FakeSocket::AppendInputData(const char* data, int data_size) {
- input_data_.insert(input_data_.end(), data, data + data_size);
- // Complete pending read if any.
- if (read_pending_) {
- read_pending_ = false;
- int result = std::min(read_buffer_size_,
- static_cast<int>(input_data_.size() - input_pos_));
- CHECK(result > 0);
- memcpy(read_buffer_->data(), &input_data_[0] + input_pos_, result);
- input_pos_ += result;
- read_buffer_ = nullptr;
- std::move(read_callback_).Run(result);
- }
-}
-
-void FakeSocket::SetPeerAddress(const net::IPEndPoint& peer_address) {
- peer_address_ = peer_address;
-}
-
-void FakeSocket::SetLocalAddress(const net::IPEndPoint& local_address) {
- local_address_ = local_address;
-}
-
-int FakeSocket::Read(net::IOBuffer* buf,
- int buf_len,
- net::CompletionOnceCallback callback) {
- DCHECK(buf);
- if (input_pos_ < static_cast<int>(input_data_.size())){
- int result = std::min(buf_len,
- static_cast<int>(input_data_.size()) - input_pos_);
- memcpy(buf->data(), &(*input_data_.begin()) + input_pos_, result);
- input_pos_ += result;
- return result;
- } else {
- read_pending_ = true;
- read_buffer_ = buf;
- read_buffer_size_ = buf_len;
- read_callback_ = std::move(callback);
- return net::ERR_IO_PENDING;
- }
-}
-
-int FakeSocket::Write(
- net::IOBuffer* buf,
- int buf_len,
- net::CompletionOnceCallback callback,
- const net::NetworkTrafficAnnotationTag& /*traffic_annotation*/) {
- DCHECK(buf);
- DCHECK(!write_pending_);
-
- if (async_write_) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(&FakeSocket::DoAsyncWrite, base::Unretained(this),
- scoped_refptr<net::IOBuffer>(buf), buf_len,
- std::move(callback)));
- write_pending_ = true;
- return net::ERR_IO_PENDING;
- }
-
- if (written_data_) {
- written_data_->insert(written_data_->end(),
- buf->data(), buf->data() + buf_len);
- }
- return buf_len;
-}
-
-void FakeSocket::DoAsyncWrite(scoped_refptr<net::IOBuffer> buf,
- int buf_len,
- net::CompletionOnceCallback callback) {
- write_pending_ = false;
-
- if (written_data_) {
- written_data_->insert(written_data_->end(),
- buf->data(), buf->data() + buf_len);
- }
- std::move(callback).Run(buf_len);
-}
-
-int FakeSocket::SetReceiveBufferSize(int32_t size) {
- NOTIMPLEMENTED();
- return net::ERR_NOT_IMPLEMENTED;
-}
-
-int FakeSocket::SetSendBufferSize(int32_t size) {
- NOTIMPLEMENTED();
- return net::ERR_NOT_IMPLEMENTED;
-}
-
-int FakeSocket::Connect(net::CompletionOnceCallback callback) {
- return 0;
-}
-
-void FakeSocket::Disconnect() {
- NOTREACHED();
-}
-
-bool FakeSocket::IsConnected() const {
- return true;
-}
-
-bool FakeSocket::IsConnectedAndIdle() const {
- return false;
-}
-
-int FakeSocket::GetPeerAddress(net::IPEndPoint* address) const {
- *address = peer_address_;
- return net::OK;
-}
-
-int FakeSocket::GetLocalAddress(net::IPEndPoint* address) const {
- *address = local_address_;
- return net::OK;
-}
-
-const net::NetLogWithSource& FakeSocket::NetLog() const {
- NOTREACHED();
- return net_log_;
-}
-
-bool FakeSocket::WasEverUsed() const {
- return true;
-}
-
-bool FakeSocket::WasAlpnNegotiated() const {
- return false;
-}
-
-net::NextProto FakeSocket::GetNegotiatedProtocol() const {
- return net::kProtoUnknown;
-}
-
-bool FakeSocket::GetSSLInfo(net::SSLInfo* ssl_info) {
- return false;
-}
-
-void FakeSocket::GetConnectionAttempts(net::ConnectionAttempts* out) const {
- out->clear();
-}
-
-int64_t FakeSocket::GetTotalReceivedBytes() const {
- NOTIMPLEMENTED();
- return 0;
-}
-
-void CreateRandomPacket(std::vector<char>* packet) {
- size_t size = kStunHeaderSize + rand() % 1000;
- packet->resize(size);
- for (size_t i = 0; i < size; i++) {
- (*packet)[i] = rand() % 256;
- }
- // Always set the first bit to ensure that generated packet is not
- // valid STUN packet.
- (*packet)[0] = (*packet)[0] | 0x80;
-}
-
-static void CreateStunPacket(std::vector<char>* packet, uint16_t type) {
- CreateRandomPacket(packet);
- *reinterpret_cast<uint16_t*>(&*packet->begin()) = base::HostToNet16(type);
- *reinterpret_cast<uint16_t*>(&*packet->begin() + 2) =
- base::HostToNet16(packet->size() - kStunHeaderSize);
- *reinterpret_cast<uint32_t*>(&*packet->begin() + 4) =
- base::HostToNet32(kStunMagicCookie);
-}
-
-void CreateStunRequest(std::vector<char>* packet) {
- CreateStunPacket(packet, kStunBindingRequest);
-}
-
-void CreateStunResponse(std::vector<char>* packet) {
- CreateStunPacket(packet, kStunBindingResponse);
-}
-
-void CreateStunError(std::vector<char>* packet) {
- CreateStunPacket(packet, kStunBindingError);
-}
-
-net::IPEndPoint ParseAddress(const std::string& ip_str, uint16_t port) {
- net::IPAddress ip;
- EXPECT_TRUE(ip.AssignFromIPLiteral(ip_str));
- return net::IPEndPoint(ip, port);
-}
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_test_utils.h b/chromium/content/browser/renderer_host/p2p/socket_host_test_utils.h
deleted file mode 100644
index 296aab86dc0..00000000000
--- a/chromium/content/browser/renderer_host/p2p/socket_host_test_utils.h
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_TEST_UTILS_H_
-#define CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_TEST_UTILS_H_
-
-#include <stdint.h>
-
-#include <string>
-#include <tuple>
-#include <vector>
-
-#include "content/common/p2p_messages.h"
-#include "ipc/ipc_sender.h"
-#include "net/base/net_errors.h"
-#include "net/log/net_log_with_source.h"
-#include "net/socket/stream_socket.h"
-#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-const char kTestLocalIpAddress[] = "123.44.22.4";
-const char kTestIpAddress1[] = "123.44.22.31";
-const uint16_t kTestPort1 = 234;
-const char kTestIpAddress2[] = "133.11.22.33";
-const uint16_t kTestPort2 = 543;
-
-class MockIPCSender : public IPC::Sender {
- public:
- MockIPCSender();
- ~MockIPCSender() override;
-
- MOCK_METHOD1(Send, bool(IPC::Message* msg));
-};
-
-class FakeSocket : public net::StreamSocket {
- public:
- FakeSocket(std::string* written_data);
- ~FakeSocket() override;
-
- void set_async_write(bool async_write) { async_write_ = async_write; }
- void AppendInputData(const char* data, int data_size);
- int input_pos() const { return input_pos_; }
- bool read_pending() const { return read_pending_; }
- void SetPeerAddress(const net::IPEndPoint& peer_address);
- void SetLocalAddress(const net::IPEndPoint& local_address);
-
- // net::Socket implementation.
- int Read(net::IOBuffer* buf,
- int buf_len,
- net::CompletionOnceCallback callback) override;
- int Write(
- net::IOBuffer* buf,
- int buf_len,
- net::CompletionOnceCallback callback,
- const net::NetworkTrafficAnnotationTag& traffic_annotation) override;
- int SetReceiveBufferSize(int32_t size) override;
- int SetSendBufferSize(int32_t size) override;
- int Connect(net::CompletionOnceCallback callback) override;
- void Disconnect() override;
- bool IsConnected() const override;
- bool IsConnectedAndIdle() const override;
- int GetPeerAddress(net::IPEndPoint* address) const override;
- int GetLocalAddress(net::IPEndPoint* address) const override;
- const net::NetLogWithSource& NetLog() const override;
- bool WasEverUsed() const override;
- bool WasAlpnNegotiated() const override;
- net::NextProto GetNegotiatedProtocol() const override;
- bool GetSSLInfo(net::SSLInfo* ssl_info) override;
- void GetConnectionAttempts(net::ConnectionAttempts* out) const override;
- void ClearConnectionAttempts() override {}
- void AddConnectionAttempts(const net::ConnectionAttempts& attempts) override {
- }
- int64_t GetTotalReceivedBytes() const override;
- void ApplySocketTag(const net::SocketTag& tag) override {}
-
- private:
- void DoAsyncWrite(scoped_refptr<net::IOBuffer> buf,
- int buf_len,
- net::CompletionOnceCallback callback);
-
- bool read_pending_;
- scoped_refptr<net::IOBuffer> read_buffer_;
- int read_buffer_size_;
- net::CompletionOnceCallback read_callback_;
-
- std::string input_data_;
- int input_pos_;
-
- std::string* written_data_;
- bool async_write_;
- bool write_pending_;
-
- net::IPEndPoint peer_address_;
- net::IPEndPoint local_address_;
-
- net::NetLogWithSource net_log_;
-};
-
-void CreateRandomPacket(std::vector<char>* packet);
-void CreateStunRequest(std::vector<char>* packet);
-void CreateStunResponse(std::vector<char>* packet);
-void CreateStunError(std::vector<char>* packet);
-
-net::IPEndPoint ParseAddress(const std::string& ip_str, uint16_t port);
-
-MATCHER_P(MatchMessage, type, "") {
- return arg->type() == type;
-}
-
-MATCHER_P(MatchPacketMessage, packet_content, "") {
- if (arg->type() != P2PMsg_OnDataReceived::ID)
- return false;
- P2PMsg_OnDataReceived::Param params;
- P2PMsg_OnDataReceived::Read(arg, &params);
- return std::get<2>(params) == packet_content;
-}
-
-MATCHER_P(MatchIncomingSocketMessage, address, "") {
- if (arg->type() != P2PMsg_OnIncomingTcpConnection::ID)
- return false;
- P2PMsg_OnIncomingTcpConnection::Param params;
- P2PMsg_OnIncomingTcpConnection::Read(
- arg, &params);
- return std::get<1>(params) == address;
-}
-
-MATCHER_P2(MatchSendPacketMetrics, rtc_packet_id, test_start_time, "") {
- if (arg->type() != P2PMsg_OnSendComplete::ID)
- return false;
-
- P2PMsg_OnSendComplete::Param params;
- P2PMsg_OnSendComplete::Read(arg, &params);
- return std::get<1>(params).rtc_packet_id == rtc_packet_id &&
- std::get<1>(params).send_time >= test_start_time &&
- std::get<1>(params).send_time <= base::TimeTicks::Now();
-}
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_TEST_UTILS_H_
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_throttler.cc b/chromium/content/browser/renderer_host/p2p/socket_host_throttler.cc
deleted file mode 100644
index e54d190eee7..00000000000
--- a/chromium/content/browser/renderer_host/p2p/socket_host_throttler.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// 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 "content/browser/renderer_host/p2p/socket_host_throttler.h"
-
-#include <utility>
-
-#include "third_party/webrtc/rtc_base/data_rate_limiter.h"
-#include "third_party/webrtc/rtc_base/timeutils.h"
-
-namespace content {
-
-namespace {
-
-const int kMaxIceMessageBandwidth = 256 * 1024;
-
-} // namespace
-
-P2PMessageThrottler::P2PMessageThrottler()
- : rate_limiter_(new rtc::DataRateLimiter(kMaxIceMessageBandwidth, 1.0)) {}
-
-P2PMessageThrottler::~P2PMessageThrottler() {
-}
-
-void P2PMessageThrottler::SetSendIceBandwidth(int bandwidth_kbps) {
- rate_limiter_.reset(new rtc::DataRateLimiter(bandwidth_kbps, 1.0));
-}
-
-bool P2PMessageThrottler::DropNextPacket(size_t packet_len) {
- double now =
- rtc::TimeNanos() / static_cast<double>(rtc::kNumNanosecsPerSec);
- if (!rate_limiter_->CanUse(packet_len, now)) {
- // Exceeding the send rate, this packet should be dropped.
- return true;
- }
-
- rate_limiter_->Use(packet_len, now);
- return false;
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_throttler.h b/chromium/content/browser/renderer_host/p2p/socket_host_throttler.h
deleted file mode 100644
index d8ad20c7dd3..00000000000
--- a/chromium/content/browser/renderer_host/p2p/socket_host_throttler.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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 CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_THROTTLER_H_
-#define CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_THROTTLER_H_
-
-#include <stddef.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "content/common/content_export.h"
-
-namespace rtc {
-class DataRateLimiter;
-}
-
-namespace content {
-
-// A very simple message throtller. User of this class must drop the packet if
-// DropNextPacket returns false for that packet. This method verifies the
-// current sendrate against the required sendrate.
-
-class CONTENT_EXPORT P2PMessageThrottler {
- public:
- P2PMessageThrottler();
- virtual ~P2PMessageThrottler();
-
- bool DropNextPacket(size_t packet_len);
- void SetSendIceBandwidth(int bandwith_kbps);
-
- private:
- std::unique_ptr<rtc::DataRateLimiter> rate_limiter_;
-
- DISALLOW_COPY_AND_ASSIGN(P2PMessageThrottler);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_THROTTLER_H_
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_udp.cc b/chromium/content/browser/renderer_host/p2p/socket_host_udp.cc
deleted file mode 100644
index 318ed0bbd5a..00000000000
--- a/chromium/content/browser/renderer_host/p2p/socket_host_udp.cc
+++ /dev/null
@@ -1,462 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/renderer_host/p2p/socket_host_udp.h"
-
-#include "base/bind.h"
-#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/stl_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/trace_event/trace_event.h"
-#include "build/build_config.h"
-#include "content/browser/renderer_host/p2p/socket_host_throttler.h"
-#include "content/common/p2p_messages.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/public/common/content_client.h"
-#include "ipc/ipc_sender.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/log/net_log_source.h"
-#include "third_party/webrtc/media/base/rtputils.h"
-
-namespace {
-
-// UDP packets cannot be bigger than 64k.
-const int kUdpReadBufferSize = 65536;
-// Socket receive buffer size.
-const int kUdpRecvSocketBufferSize = 65536; // 64K
-// Socket send buffer size.
-const int kUdpSendSocketBufferSize = 65536;
-
-// Defines set of transient errors. These errors are ignored when we get them
-// from sendto() or recvfrom() calls.
-//
-// net::ERR_OUT_OF_MEMORY
-//
-// This is caused by ENOBUFS which means the buffer of the network interface
-// is full.
-//
-// net::ERR_CONNECTION_RESET
-//
-// This is caused by WSAENETRESET or WSAECONNRESET which means the
-// last send resulted in an "ICMP Port Unreachable" message.
-struct {
- int code;
- const char* name;
-} static const kTransientErrors[] {
- {net::ERR_ADDRESS_UNREACHABLE, "net::ERR_ADDRESS_UNREACHABLE"},
- {net::ERR_ADDRESS_INVALID, "net::ERR_ADDRESS_INVALID"},
- {net::ERR_ACCESS_DENIED, "net::ERR_ACCESS_DENIED"},
- {net::ERR_CONNECTION_RESET, "net::ERR_CONNECTION_RESET"},
- {net::ERR_OUT_OF_MEMORY, "net::ERR_OUT_OF_MEMORY"},
- {net::ERR_INTERNET_DISCONNECTED, "net::ERR_INTERNET_DISCONNECTED"}
-};
-
-bool IsTransientError(int error) {
- for (const auto& transient_error : kTransientErrors) {
- if (transient_error.code == error)
- return true;
- }
- return false;
-}
-
-const char* GetTransientErrorName(int error) {
- for (const auto& transient_error : kTransientErrors) {
- if (transient_error.code == error)
- return transient_error.name;
- }
- return "";
-}
-
-} // namespace
-
-namespace content {
-
-P2PSocketHostUdp::PendingPacket::PendingPacket(
- const net::IPEndPoint& to,
- const std::vector<char>& content,
- const rtc::PacketOptions& options,
- uint64_t id,
- const net::NetworkTrafficAnnotationTag traffic_annotation)
- : to(to),
- data(new net::IOBuffer(content.size())),
- size(content.size()),
- packet_options(options),
- id(id),
- traffic_annotation(traffic_annotation) {
- memcpy(data->data(), &content[0], size);
-}
-
-P2PSocketHostUdp::PendingPacket::PendingPacket(const PendingPacket& other) =
- default;
-
-P2PSocketHostUdp::PendingPacket::~PendingPacket() {
-}
-
-P2PSocketHostUdp::P2PSocketHostUdp(
- IPC::Sender* message_sender,
- int socket_id,
- P2PMessageThrottler* throttler,
- net::NetLog* net_log,
- const DatagramServerSocketFactory& socket_factory)
- : P2PSocketHost(message_sender, socket_id, P2PSocketHost::UDP),
- socket_(socket_factory.Run(net_log)),
- send_pending_(false),
- last_dscp_(net::DSCP_CS0),
- throttler_(throttler),
- net_log_(net_log),
- socket_factory_(socket_factory) {}
-
-P2PSocketHostUdp::P2PSocketHostUdp(IPC::Sender* message_sender,
- int socket_id,
- P2PMessageThrottler* throttler,
- net::NetLog* net_log)
- : P2PSocketHostUdp(message_sender,
- socket_id,
- throttler,
- net_log,
- base::Bind(&P2PSocketHostUdp::DefaultSocketFactory)) {}
-
-P2PSocketHostUdp::~P2PSocketHostUdp() {
- if (state_ == STATE_OPEN) {
- DCHECK(socket_.get());
- socket_.reset();
- }
-}
-
-bool P2PSocketHostUdp::Init(const net::IPEndPoint& local_address,
- uint16_t min_port,
- uint16_t max_port,
- const P2PHostAndIPEndPoint& remote_address) {
- DCHECK_EQ(state_, STATE_UNINITIALIZED);
- DCHECK((min_port == 0 && max_port == 0) || min_port > 0);
- DCHECK_LE(min_port, max_port);
-
- int result = -1;
- if (min_port == 0) {
- result = socket_->Listen(local_address);
- } else if (local_address.port() == 0) {
- for (unsigned port = min_port; port <= max_port && result < 0; ++port) {
- result = socket_->Listen(net::IPEndPoint(local_address.address(), port));
- if (result < 0 && port != max_port)
- socket_ = socket_factory_.Run(net_log_);
- }
- } else if (local_address.port() >= min_port &&
- local_address.port() <= max_port) {
- result = socket_->Listen(local_address);
- }
- if (result < 0) {
- LOG(ERROR) << "bind() to " << local_address.address().ToString()
- << (min_port == 0
- ? base::StringPrintf(":%d", local_address.port())
- : base::StringPrintf(", port range [%d-%d]", min_port,
- max_port))
- << " failed: " << result;
- OnError();
- return false;
- }
-
- // Setting recv socket buffer size.
- if (socket_->SetReceiveBufferSize(kUdpRecvSocketBufferSize) != net::OK) {
- LOG(WARNING) << "Failed to set socket receive buffer size to "
- << kUdpRecvSocketBufferSize;
- }
-
- // Setting socket send buffer size.
- if (socket_->SetSendBufferSize(kUdpSendSocketBufferSize) != net::OK) {
- LOG(WARNING) << "Failed to set socket send buffer size to "
- << kUdpSendSocketBufferSize;
- }
-
- net::IPEndPoint address;
- result = socket_->GetLocalAddress(&address);
- if (result < 0) {
- LOG(ERROR) << "P2PSocketHostUdp::Init(): unable to get local address: "
- << result;
- OnError();
- return false;
- }
- VLOG(1) << "Local address: " << address.ToString();
-
- state_ = STATE_OPEN;
-
- // NOTE: Remote address will be same as what renderer provided.
- message_sender_->Send(new P2PMsg_OnSocketCreated(
- id_, address, remote_address.ip_address));
-
- recv_buffer_ = new net::IOBuffer(kUdpReadBufferSize);
- DoRead();
-
- return true;
-}
-
-void P2PSocketHostUdp::OnError() {
- socket_.reset();
- send_queue_.clear();
-
- if (state_ == STATE_UNINITIALIZED || state_ == STATE_OPEN)
- message_sender_->Send(new P2PMsg_OnError(id_));
-
- state_ = STATE_ERROR;
-}
-
-void P2PSocketHostUdp::DoRead() {
- int result;
- do {
- result = socket_->RecvFrom(
- recv_buffer_.get(), kUdpReadBufferSize, &recv_address_,
- base::Bind(&P2PSocketHostUdp::OnRecv, base::Unretained(this)));
- if (result == net::ERR_IO_PENDING)
- return;
- HandleReadResult(result);
- } while (state_ == STATE_OPEN);
-}
-
-void P2PSocketHostUdp::OnRecv(int result) {
- HandleReadResult(result);
- if (state_ == STATE_OPEN) {
- DoRead();
- }
-}
-
-void P2PSocketHostUdp::HandleReadResult(int result) {
- DCHECK_EQ(STATE_OPEN, state_);
-
- if (result > 0) {
- std::vector<char> data(recv_buffer_->data(), recv_buffer_->data() + result);
-
- if (!base::ContainsKey(connected_peers_, recv_address_)) {
- P2PSocketHost::StunMessageType type;
- bool stun = GetStunPacketType(&*data.begin(), data.size(), &type);
- if ((stun && IsRequestOrResponse(type))) {
- connected_peers_.insert(recv_address_);
- } else if (!stun || type == STUN_DATA_INDICATION) {
- LOG(ERROR) << "Received unexpected data packet from "
- << recv_address_.ToString()
- << " before STUN binding is finished.";
- return;
- }
- }
-
- message_sender_->Send(new P2PMsg_OnDataReceived(
- id_, recv_address_, data, base::TimeTicks::Now()));
-
- if (dump_incoming_rtp_packet_)
- DumpRtpPacket(&data[0], data.size(), true);
- } else if (result < 0 && !IsTransientError(result)) {
- LOG(ERROR) << "Error when reading from UDP socket: " << result;
- OnError();
- }
-}
-
-void P2PSocketHostUdp::Send(
- const net::IPEndPoint& to,
- const std::vector<char>& data,
- const rtc::PacketOptions& options,
- uint64_t packet_id,
- const net::NetworkTrafficAnnotationTag traffic_annotation) {
- if (!socket_) {
- // The Send message may be sent after the an OnError message was
- // sent by hasn't been processed the renderer.
- return;
- }
-
- IncrementTotalSentPackets();
-
- if (send_pending_) {
- send_queue_.push_back(
- PendingPacket(to, data, options, packet_id, traffic_annotation));
- IncrementDelayedBytes(data.size());
- IncrementDelayedPackets();
- } else {
- PendingPacket packet(to, data, options, packet_id, traffic_annotation);
- DoSend(packet);
- }
-}
-
-void P2PSocketHostUdp::DoSend(const PendingPacket& packet) {
- base::TimeTicks send_time = base::TimeTicks::Now();
-
- // The peer is considered not connected until the first incoming STUN
- // request/response. In that state the renderer is allowed to send only STUN
- // messages to that peer and they are throttled using the |throttler_|. This
- // has to be done here instead of Send() to ensure P2PMsg_OnSendComplete
- // messages are sent in correct order.
- if (!base::ContainsKey(connected_peers_, packet.to)) {
- P2PSocketHost::StunMessageType type = P2PSocketHost::StunMessageType();
- bool stun = GetStunPacketType(packet.data->data(), packet.size, &type);
- if (!stun || type == STUN_DATA_INDICATION) {
- LOG(ERROR) << "Page tried to send a data packet to "
- << packet.to.ToString() << " before STUN binding is finished.";
- OnError();
- return;
- }
-
- if (throttler_->DropNextPacket(packet.size)) {
- VLOG(0) << "Throttling outgoing STUN message.";
- // The renderer expects P2PMsg_OnSendComplete for all packets it generates
- // and in the same order it generates them, so we need to respond even
- // when the packet is dropped.
- message_sender_->Send(new P2PMsg_OnSendComplete(
- id_, P2PSendPacketMetrics(packet.id, packet.packet_options.packet_id,
- send_time)));
- // Do not reset the socket.
- return;
- }
- }
-
- TRACE_EVENT_ASYNC_STEP_INTO1("p2p", "Send", packet.id, "UdpAsyncSendTo",
- "size", packet.size);
- // Don't try to set DSCP in following conditions,
- // 1. If the outgoing packet is set to DSCP_NO_CHANGE
- // 2. If no change in DSCP value from last packet
- // 3. If there is any error in setting DSCP on socket.
- net::DiffServCodePoint dscp =
- static_cast<net::DiffServCodePoint>(packet.packet_options.dscp);
- if (dscp != net::DSCP_NO_CHANGE && last_dscp_ != dscp &&
- last_dscp_ != net::DSCP_NO_CHANGE) {
- int result = SetSocketDiffServCodePointInternal(dscp);
- if (result == net::OK) {
- last_dscp_ = dscp;
- } else if (!IsTransientError(result) && last_dscp_ != net::DSCP_CS0) {
- // We receieved a non-transient error, and it seems we have
- // not changed the DSCP in the past, disable DSCP as it unlikely
- // to work in the future.
- last_dscp_ = net::DSCP_NO_CHANGE;
- }
- }
-
- cricket::ApplyPacketOptions(reinterpret_cast<uint8_t*>(packet.data->data()),
- packet.size,
- packet.packet_options.packet_time_params,
- (send_time - base::TimeTicks()).InMicroseconds());
- auto callback_binding =
- base::Bind(&P2PSocketHostUdp::OnSend, base::Unretained(this), packet.id,
- packet.packet_options.packet_id, send_time);
-
- // TODO(crbug.com/656607): Pass traffic annotation after DatagramSocketServer
- // is updated.
- int result = socket_->SendTo(packet.data.get(), packet.size, packet.to,
- callback_binding);
-
- // sendto() may return an error, e.g. if we've received an ICMP Destination
- // Unreachable message. When this happens try sending the same packet again,
- // and just drop it if it fails again.
- if (IsTransientError(result)) {
- result = socket_->SendTo(packet.data.get(), packet.size, packet.to,
- std::move(callback_binding));
- }
-
- if (result == net::ERR_IO_PENDING) {
- send_pending_ = true;
- } else {
- HandleSendResult(packet.id, packet.packet_options.packet_id, send_time,
- result);
- }
-
- if (dump_outgoing_rtp_packet_)
- DumpRtpPacket(packet.data->data(), packet.size, false);
-}
-
-void P2PSocketHostUdp::OnSend(uint64_t packet_id,
- int32_t transport_sequence_number,
- base::TimeTicks send_time,
- int result) {
- DCHECK(send_pending_);
- DCHECK_NE(result, net::ERR_IO_PENDING);
-
- send_pending_ = false;
-
- HandleSendResult(packet_id, transport_sequence_number, send_time, result);
-
- // Send next packets if we have them waiting in the buffer.
- while (state_ == STATE_OPEN && !send_queue_.empty() && !send_pending_) {
- PendingPacket packet = send_queue_.front();
- send_queue_.pop_front();
- DoSend(packet);
- DecrementDelayedBytes(packet.size);
- }
-}
-
-void P2PSocketHostUdp::HandleSendResult(uint64_t packet_id,
- int32_t transport_sequence_number,
- base::TimeTicks send_time,
- int result) {
- TRACE_EVENT_ASYNC_END1("p2p", "Send", packet_id,
- "result", result);
- if (result < 0) {
- ReportSocketError(result, "WebRTC.ICE.UdpSocketWriteErrorCode");
-
- if (!IsTransientError(result)) {
- LOG(ERROR) << "Error when sending data in UDP socket: " << result;
- OnError();
- return;
- }
- VLOG(0) << "sendto() has failed twice returning a "
- " transient error " << GetTransientErrorName(result)
- << ". Dropping the packet.";
- }
-
- // UMA to track the histograms from 1ms to 1 sec for how long a packet spends
- // in the browser process.
- UMA_HISTOGRAM_TIMES("WebRTC.SystemSendPacketDuration_UDP" /* name */,
- base::TimeTicks::Now() - send_time /* sample */);
-
- message_sender_->Send(new P2PMsg_OnSendComplete(
- id_,
- P2PSendPacketMetrics(packet_id, transport_sequence_number, send_time)));
-}
-
-std::unique_ptr<P2PSocketHost> P2PSocketHostUdp::AcceptIncomingTcpConnection(
- const net::IPEndPoint& remote_address,
- int id) {
- NOTREACHED();
- OnError();
- return nullptr;
-}
-
-bool P2PSocketHostUdp::SetOption(P2PSocketOption option, int value) {
- if (state_ != STATE_OPEN) {
- DCHECK_EQ(state_, STATE_ERROR);
- return false;
- }
- switch (option) {
- case P2P_SOCKET_OPT_RCVBUF:
- return socket_->SetReceiveBufferSize(value) == net::OK;
- case P2P_SOCKET_OPT_SNDBUF:
- return socket_->SetSendBufferSize(value) == net::OK;
- case P2P_SOCKET_OPT_DSCP:
- return net::OK == SetSocketDiffServCodePointInternal(
- static_cast<net::DiffServCodePoint>(value));
- default:
- NOTREACHED();
- return false;
- }
-}
-
-// TODO(crbug.com/812137): We don't call SetDiffServCodePoint for the Windows
-// UDP socket, because this is known to cause a hanging thread.
-int P2PSocketHostUdp::SetSocketDiffServCodePointInternal(
- net::DiffServCodePoint dscp) {
-#if defined(OS_WIN)
- return net::OK;
-#else
- return socket_->SetDiffServCodePoint(dscp);
-#endif
-}
-
-// static
-std::unique_ptr<net::DatagramServerSocket>
-P2PSocketHostUdp::DefaultSocketFactory(net::NetLog* net_log) {
- net::UDPServerSocket* socket =
- new net::UDPServerSocket(net_log, net::NetLogSource());
-#if defined(OS_WIN)
- socket->UseNonBlockingIO();
-#endif
-
- return base::WrapUnique(socket);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_udp.h b/chromium/content/browser/renderer_host/p2p/socket_host_udp.h
deleted file mode 100644
index d4398740213..00000000000
--- a/chromium/content/browser/renderer_host/p2p/socket_host_udp.h
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_UDP_H_
-#define CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_UDP_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-#include <set>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/containers/circular_deque.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "content/browser/renderer_host/p2p/socket_host.h"
-#include "content/common/content_export.h"
-#include "content/common/p2p_socket_type.h"
-#include "net/base/ip_endpoint.h"
-#include "net/socket/diff_serv_code_point.h"
-#include "net/socket/udp_server_socket.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "third_party/webrtc/rtc_base/asyncpacketsocket.h"
-
-namespace net {
-class NetLog;
-} // namespace net
-
-namespace content {
-
-class P2PMessageThrottler;
-
-class CONTENT_EXPORT P2PSocketHostUdp : public P2PSocketHost {
- public:
- typedef base::Callback<std::unique_ptr<net::DatagramServerSocket>(
- net::NetLog* net_log)>
- DatagramServerSocketFactory;
- P2PSocketHostUdp(IPC::Sender* message_sender,
- int socket_id,
- P2PMessageThrottler* throttler,
- net::NetLog* net_log,
- const DatagramServerSocketFactory& socket_factory);
- P2PSocketHostUdp(IPC::Sender* message_sender,
- int socket_id,
- P2PMessageThrottler* throttler,
- net::NetLog* net_log);
- ~P2PSocketHostUdp() override;
-
- // P2PSocketHost overrides.
- bool Init(const net::IPEndPoint& local_address,
- uint16_t min_port,
- uint16_t max_port,
- const P2PHostAndIPEndPoint& remote_address) override;
- void Send(const net::IPEndPoint& to,
- const std::vector<char>& data,
- const rtc::PacketOptions& options,
- uint64_t packet_id,
- const net::NetworkTrafficAnnotationTag traffic_annotation) override;
- std::unique_ptr<P2PSocketHost> AcceptIncomingTcpConnection(
- const net::IPEndPoint& remote_address,
- int id) override;
- bool SetOption(P2PSocketOption option, int value) override;
-
- private:
- friend class P2PSocketHostUdpTest;
-
- typedef std::set<net::IPEndPoint> ConnectedPeerSet;
-
- struct PendingPacket {
- PendingPacket(const net::IPEndPoint& to,
- const std::vector<char>& content,
- const rtc::PacketOptions& options,
- uint64_t id,
- const net::NetworkTrafficAnnotationTag traffic_annotation);
- PendingPacket(const PendingPacket& other);
- ~PendingPacket();
- net::IPEndPoint to;
- scoped_refptr<net::IOBuffer> data;
- int size;
- rtc::PacketOptions packet_options;
- uint64_t id;
- const net::NetworkTrafficAnnotationTag traffic_annotation;
- };
-
- void OnError();
-
- void DoRead();
- void OnRecv(int result);
- void HandleReadResult(int result);
-
- void DoSend(const PendingPacket& packet);
- void OnSend(uint64_t packet_id,
- int32_t transport_sequence_number,
- base::TimeTicks send_time,
- int result);
- void HandleSendResult(uint64_t packet_id,
- int32_t transport_sequence_number,
- base::TimeTicks send_time,
- int result);
- int SetSocketDiffServCodePointInternal(net::DiffServCodePoint dscp);
- static std::unique_ptr<net::DatagramServerSocket> DefaultSocketFactory(
- net::NetLog* net_log);
-
- std::unique_ptr<net::DatagramServerSocket> socket_;
- scoped_refptr<net::IOBuffer> recv_buffer_;
- net::IPEndPoint recv_address_;
-
- base::circular_deque<PendingPacket> send_queue_;
- bool send_pending_;
- net::DiffServCodePoint last_dscp_;
-
- // Set of peer for which we have received STUN binding request or
- // response or relay allocation request or response.
- ConnectedPeerSet connected_peers_;
- P2PMessageThrottler* throttler_;
-
- net::NetLog* net_log_;
-
- // Callback object that returns a new socket when invoked.
- DatagramServerSocketFactory socket_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(P2PSocketHostUdp);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_UDP_H_
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_udp_unittest.cc b/chromium/content/browser/renderer_host/p2p/socket_host_udp_unittest.cc
deleted file mode 100644
index dafc06ba0fa..00000000000
--- a/chromium/content/browser/renderer_host/p2p/socket_host_udp_unittest.cc
+++ /dev/null
@@ -1,595 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/renderer_host/p2p/socket_host_udp.h"
-
-#include <stdint.h>
-#include <utility>
-#include <vector>
-
-#include "base/containers/circular_deque.h"
-#include "base/logging.h"
-#include "base/sys_byteorder.h"
-#include "content/browser/renderer_host/p2p/socket_host_test_utils.h"
-#include "content/browser/renderer_host/p2p/socket_host_throttler.h"
-#include "net/base/completion_once_callback.h"
-#include "net/base/io_buffer.h"
-#include "net/base/ip_endpoint.h"
-#include "net/base/net_errors.h"
-#include "net/log/net_log_with_source.h"
-#include "net/socket/datagram_server_socket.h"
-#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using ::testing::_;
-using ::testing::DeleteArg;
-using ::testing::DoAll;
-using ::testing::Return;
-
-namespace {
-
-// TODO(nisse): We can't currently use rtc::ScopedFakeClock, because
-// we don't link with webrtc rtc_base_tests_utils. So roll our own.
-
-// Creating an object of this class makes rtc::TimeMicros() and
-// related functions return zero unless the clock is advanced.
-class ScopedFakeClock : public rtc::ClockInterface {
- public:
- ScopedFakeClock() { prev_clock_ = rtc::SetClockForTesting(this); }
- ~ScopedFakeClock() override { rtc::SetClockForTesting(prev_clock_); }
- // ClockInterface implementation.
- int64_t TimeNanos() const override { return time_nanos_; }
- void SetTimeNanos(uint64_t time_nanos) { time_nanos_ = time_nanos; }
-
- private:
- ClockInterface* prev_clock_;
- uint64_t time_nanos_ = 0;
-};
-
-class FakeDatagramServerSocket : public net::DatagramServerSocket {
- public:
- typedef std::pair<net::IPEndPoint, std::vector<char> > UDPPacket;
-
- // P2PSocketHostUdp destroys a socket on errors so sent packets
- // need to be stored outside of this object.
- FakeDatagramServerSocket(base::circular_deque<UDPPacket>* sent_packets,
- std::vector<uint16_t>* used_ports)
- : sent_packets_(sent_packets),
- recv_address_(nullptr),
- recv_size_(0),
- used_ports_(used_ports) {}
-
- void Close() override {}
-
- int GetPeerAddress(net::IPEndPoint* address) const override {
- NOTREACHED();
- return net::ERR_SOCKET_NOT_CONNECTED;
- }
-
- int GetLocalAddress(net::IPEndPoint* address) const override {
- *address = address_;
- return 0;
- }
-
- void UseNonBlockingIO() override {}
-
- int Listen(const net::IPEndPoint& address) override {
- if (used_ports_) {
- for (auto used_port : *used_ports_) {
- if (used_port == address.port())
- return -1;
- }
- used_ports_->push_back(address.port());
- }
-
- address_ = address;
- return 0;
- }
-
- int RecvFrom(net::IOBuffer* buf,
- int buf_len,
- net::IPEndPoint* address,
- net::CompletionOnceCallback callback) override {
- CHECK(recv_callback_.is_null());
- if (incoming_packets_.size() > 0) {
- scoped_refptr<net::IOBuffer> buffer(buf);
- int size = std::min(
- static_cast<int>(incoming_packets_.front().second.size()), buf_len);
- memcpy(buffer->data(), &*incoming_packets_.front().second.begin(), size);
- *address = incoming_packets_.front().first;
- incoming_packets_.pop_front();
- return size;
- } else {
- recv_callback_ = std::move(callback);
- recv_buffer_ = buf;
- recv_size_ = buf_len;
- recv_address_ = address;
- return net::ERR_IO_PENDING;
- }
- }
-
- int SendTo(net::IOBuffer* buf,
- int buf_len,
- const net::IPEndPoint& address,
- net::CompletionOnceCallback callback) override {
- scoped_refptr<net::IOBuffer> buffer(buf);
- std::vector<char> data_vector(buffer->data(), buffer->data() + buf_len);
- sent_packets_->push_back(UDPPacket(address, data_vector));
- return buf_len;
- }
-
- int SetReceiveBufferSize(int32_t size) override { return net::OK; }
-
- int SetSendBufferSize(int32_t size) override { return net::OK; }
-
- int SetDoNotFragment() override { return net::OK; }
-
- void SetMsgConfirm(bool confirm) override {}
-
- void ReceivePacket(const net::IPEndPoint& address, std::vector<char> data) {
- if (!recv_callback_.is_null()) {
- int size = std::min(recv_size_, static_cast<int>(data.size()));
- memcpy(recv_buffer_->data(), &*data.begin(), size);
- *recv_address_ = address;
- recv_buffer_ = nullptr;
- std::move(recv_callback_).Run(size);
- } else {
- incoming_packets_.push_back(UDPPacket(address, data));
- }
- }
-
- const net::NetLogWithSource& NetLog() const override { return net_log_; }
-
- void AllowAddressReuse() override { NOTIMPLEMENTED(); }
-
- void AllowBroadcast() override { NOTIMPLEMENTED(); }
-
- int JoinGroup(const net::IPAddress& group_address) const override {
- NOTIMPLEMENTED();
- return net::ERR_NOT_IMPLEMENTED;
- }
-
- int LeaveGroup(const net::IPAddress& group_address) const override {
- NOTIMPLEMENTED();
- return net::ERR_NOT_IMPLEMENTED;
- }
-
- int SetMulticastInterface(uint32_t interface_index) override {
- NOTIMPLEMENTED();
- return net::ERR_NOT_IMPLEMENTED;
- }
-
- int SetMulticastTimeToLive(int time_to_live) override {
- NOTIMPLEMENTED();
- return net::ERR_NOT_IMPLEMENTED;
- }
-
- int SetMulticastLoopbackMode(bool loopback) override {
- NOTIMPLEMENTED();
- return net::ERR_NOT_IMPLEMENTED;
- }
-
- int SetDiffServCodePoint(net::DiffServCodePoint dscp) override {
- NOTIMPLEMENTED();
- return net::ERR_NOT_IMPLEMENTED;
- }
-
- void DetachFromThread() override { NOTIMPLEMENTED(); }
-
- private:
- net::IPEndPoint address_;
- base::circular_deque<UDPPacket>* sent_packets_;
- base::circular_deque<UDPPacket> incoming_packets_;
- net::NetLogWithSource net_log_;
-
- scoped_refptr<net::IOBuffer> recv_buffer_;
- net::IPEndPoint* recv_address_;
- int recv_size_;
- net::CompletionOnceCallback recv_callback_;
- std::vector<uint16_t>* used_ports_;
-};
-
-std::unique_ptr<net::DatagramServerSocket> CreateFakeDatagramServerSocket(
- base::circular_deque<FakeDatagramServerSocket::UDPPacket>* sent_packets,
- std::vector<uint16_t>* used_ports,
- net::NetLog* net_log) {
- return std::make_unique<FakeDatagramServerSocket>(sent_packets, used_ports);
-}
-
-} // namespace
-
-namespace content {
-
-class P2PSocketHostUdpTest : public testing::Test {
- protected:
- void SetUp() override {
- EXPECT_CALL(
- sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnSocketCreated::ID))))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-
- socket_host_.reset(new P2PSocketHostUdp(
- &sender_, 0, &throttler_, /*net_log=*/nullptr,
- base::Bind(&CreateFakeDatagramServerSocket, &sent_packets_, nullptr)));
-
- local_address_ = ParseAddress(kTestLocalIpAddress, kTestPort1);
- socket_host_->Init(local_address_, 0, 0, P2PHostAndIPEndPoint());
- socket_ = GetSocketFromHost(socket_host_.get());
-
- dest1_ = ParseAddress(kTestIpAddress1, kTestPort1);
- dest2_ = ParseAddress(kTestIpAddress2, kTestPort2);
- }
-
- static FakeDatagramServerSocket* GetSocketFromHost(
- P2PSocketHostUdp* socket_host) {
- return static_cast<FakeDatagramServerSocket*>(socket_host->socket_.get());
- }
-
- P2PMessageThrottler throttler_;
- ScopedFakeClock fake_clock_;
- base::circular_deque<FakeDatagramServerSocket::UDPPacket> sent_packets_;
- FakeDatagramServerSocket* socket_; // Owned by |socket_host_|.
- std::unique_ptr<P2PSocketHostUdp> socket_host_;
- MockIPCSender sender_;
-
- net::IPEndPoint local_address_;
-
- net::IPEndPoint dest1_;
- net::IPEndPoint dest2_;
-};
-
-// Verify that we can send STUN messages before we receive anything
-// from the other side.
-TEST_F(P2PSocketHostUdpTest, SendStunNoAuth) {
- EXPECT_CALL(
- sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnSendComplete::ID))))
- .Times(3)
- .WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
-
- rtc::PacketOptions options;
- std::vector<char> packet1;
- CreateStunRequest(&packet1);
- socket_host_->Send(dest1_, packet1, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
-
- std::vector<char> packet2;
- CreateStunResponse(&packet2);
- socket_host_->Send(dest1_, packet2, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
-
- std::vector<char> packet3;
- CreateStunError(&packet3);
- socket_host_->Send(dest1_, packet3, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
-
- ASSERT_EQ(sent_packets_.size(), 3U);
- ASSERT_EQ(sent_packets_[0].second, packet1);
- ASSERT_EQ(sent_packets_[1].second, packet2);
- ASSERT_EQ(sent_packets_[2].second, packet3);
-}
-
-// Verify that no data packets can be sent before STUN binding has
-// finished.
-TEST_F(P2PSocketHostUdpTest, SendDataNoAuth) {
- EXPECT_CALL(sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnError::ID))))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-
- rtc::PacketOptions options;
- std::vector<char> packet;
- CreateRandomPacket(&packet);
- socket_host_->Send(dest1_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
-
- ASSERT_EQ(sent_packets_.size(), 0U);
-}
-
-// Verify that SetOption() doesn't crash after an error.
-TEST_F(P2PSocketHostUdpTest, SetOptionAfterError) {
- // Get the sender into the error state.
- EXPECT_CALL(sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnError::ID))))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- socket_host_->Send(dest1_, {1, 2, 3, 4}, rtc::PacketOptions(), 0,
- TRAFFIC_ANNOTATION_FOR_TESTS);
- testing::Mock::VerifyAndClearExpectations(&sender_);
-
- // Verify that SetOptions() fails, but doesn't crash.
- EXPECT_FALSE(socket_host_->SetOption(P2P_SOCKET_OPT_RCVBUF, 2048));
-}
-
-// Verify that we can send data after we've received STUN request
-// from the other side.
-TEST_F(P2PSocketHostUdpTest, SendAfterStunRequest) {
- // Receive packet from |dest1_|.
- std::vector<char> request_packet;
- CreateStunRequest(&request_packet);
-
- EXPECT_CALL(sender_, Send(MatchPacketMessage(request_packet)))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- socket_->ReceivePacket(dest1_, request_packet);
-
- // Now we should be able to send any data to |dest1_|.
- EXPECT_CALL(
- sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnSendComplete::ID))))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-
- rtc::PacketOptions options;
- std::vector<char> packet;
- CreateRandomPacket(&packet);
- socket_host_->Send(dest1_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
-
- ASSERT_EQ(1U, sent_packets_.size());
- ASSERT_EQ(dest1_, sent_packets_[0].first);
-}
-
-// Verify that we can send data after we've received STUN response
-// from the other side.
-TEST_F(P2PSocketHostUdpTest, SendAfterStunResponse) {
- // Receive packet from |dest1_|.
- std::vector<char> request_packet;
- CreateStunRequest(&request_packet);
-
- EXPECT_CALL(sender_, Send(MatchPacketMessage(request_packet)))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- socket_->ReceivePacket(dest1_, request_packet);
-
- // Now we should be able to send any data to |dest1_|.
- EXPECT_CALL(
- sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnSendComplete::ID))))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-
- rtc::PacketOptions options;
- std::vector<char> packet;
- CreateRandomPacket(&packet);
- socket_host_->Send(dest1_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
-
- ASSERT_EQ(1U, sent_packets_.size());
- ASSERT_EQ(dest1_, sent_packets_[0].first);
-}
-
-// Verify messages still cannot be sent to an unathorized host after
-// successful binding with different host.
-TEST_F(P2PSocketHostUdpTest, SendAfterStunResponseDifferentHost) {
- // Receive packet from |dest1_|.
- std::vector<char> request_packet;
- CreateStunRequest(&request_packet);
-
- EXPECT_CALL(sender_, Send(MatchPacketMessage(request_packet)))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- socket_->ReceivePacket(dest1_, request_packet);
-
- // Should fail when trying to send the same packet to |dest2_|.
- rtc::PacketOptions options;
- std::vector<char> packet;
- CreateRandomPacket(&packet);
- EXPECT_CALL(sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnError::ID))))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- socket_host_->Send(dest2_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
-}
-
-// Verify throttler not allowing unlimited sending of ICE messages to
-// any destination.
-TEST_F(P2PSocketHostUdpTest, ThrottleAfterLimit) {
- EXPECT_CALL(
- sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnSendComplete::ID))))
- .Times(3)
- .WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
-
- rtc::PacketOptions options;
- std::vector<char> packet1;
- CreateStunRequest(&packet1);
- throttler_.SetSendIceBandwidth(packet1.size() * 2);
- socket_host_->Send(dest1_, packet1, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
- socket_host_->Send(dest2_, packet1, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
-
- net::IPEndPoint dest3 = ParseAddress(kTestIpAddress1, 2222);
- // This packet must be dropped by the throttler.
- socket_host_->Send(dest3, packet1, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
- ASSERT_EQ(sent_packets_.size(), 2U);
-}
-
-// Verify we can send packets to a known destination when ICE throttling is
-// active.
-TEST_F(P2PSocketHostUdpTest, ThrottleAfterLimitAfterReceive) {
- // Receive packet from |dest1_|.
- std::vector<char> request_packet;
- CreateStunRequest(&request_packet);
-
- EXPECT_CALL(sender_, Send(MatchPacketMessage(request_packet)))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- socket_->ReceivePacket(dest1_, request_packet);
-
- EXPECT_CALL(
- sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnSendComplete::ID))))
- .Times(6)
- .WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
-
- rtc::PacketOptions options;
- std::vector<char> packet1;
- CreateStunRequest(&packet1);
- throttler_.SetSendIceBandwidth(packet1.size());
- // |dest1_| is known address, throttling will not be applied.
- socket_host_->Send(dest1_, packet1, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
- // Trying to send the packet to dest1_ in the same window. It should go.
- socket_host_->Send(dest1_, packet1, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
-
- // Throttler should allow this packet to go through.
- socket_host_->Send(dest2_, packet1, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
-
- net::IPEndPoint dest3 = ParseAddress(kTestIpAddress1, 2223);
- // This packet will be dropped, as limit only for a single packet.
- socket_host_->Send(dest3, packet1, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
- net::IPEndPoint dest4 = ParseAddress(kTestIpAddress1, 2224);
- // This packet should also be dropped.
- socket_host_->Send(dest4, packet1, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
- // |dest1| is known, we can send as many packets to it.
- socket_host_->Send(dest1_, packet1, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
- ASSERT_EQ(sent_packets_.size(), 4U);
-}
-
-// The fake clock mechanism used for this test doesn't work in component builds.
-// See: https://bugs.chromium.org/p/webrtc/issues/detail?id=6490
-#if defined(COMPONENT_BUILD)
-#define MAYBE_ThrottlingStopsAtExpectedTimes DISABLED_ThrottlingStopsAtExpectedTimes
-#else
-#define MAYBE_ThrottlingStopsAtExpectedTimes ThrottlingStopsAtExpectedTimes
-#endif
-// Test that once the limit is hit, the throttling stops at the expected time,
-// allowing packets to be sent again.
-TEST_F(P2PSocketHostUdpTest, MAYBE_ThrottlingStopsAtExpectedTimes) {
- EXPECT_CALL(
- sender_,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnSendComplete::ID))))
- .Times(12)
- .WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
-
- rtc::PacketOptions options;
- std::vector<char> packet;
- CreateStunRequest(&packet);
- // Limit of 2 packets per second.
- throttler_.SetSendIceBandwidth(packet.size() * 2);
- socket_host_->Send(dest1_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
- socket_host_->Send(dest2_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
- EXPECT_EQ(2U, sent_packets_.size());
-
- // These packets must be dropped by the throttler since the limit was hit and
- // the time hasn't advanced.
- socket_host_->Send(dest1_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
- socket_host_->Send(dest2_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
- EXPECT_EQ(2U, sent_packets_.size());
-
- // Advance the time to 0.999 seconds; throttling should still just barely be
- // active.
- fake_clock_.SetTimeNanos(rtc::kNumNanosecsPerMillisec * 999);
- socket_host_->Send(dest1_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
- socket_host_->Send(dest2_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
- EXPECT_EQ(2U, sent_packets_.size());
-
- // After hitting the second mark, we should be able to send again.
- // Add an extra millisecond to account for rounding errors.
- fake_clock_.SetTimeNanos(rtc::kNumNanosecsPerMillisec * 1001);
- socket_host_->Send(dest1_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
- EXPECT_EQ(3U, sent_packets_.size());
-
- // This time, hit the limit in the middle of the period.
- fake_clock_.SetTimeNanos(rtc::kNumNanosecsPerMillisec * 1500);
- socket_host_->Send(dest2_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
- EXPECT_EQ(4U, sent_packets_.size());
-
- // Again, throttling should be active until the next second mark.
- fake_clock_.SetTimeNanos(rtc::kNumNanosecsPerMillisec * 1999);
- socket_host_->Send(dest1_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
- socket_host_->Send(dest2_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
- EXPECT_EQ(4U, sent_packets_.size());
- fake_clock_.SetTimeNanos(rtc::kNumNanosecsPerMillisec * 2002);
- socket_host_->Send(dest1_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
- socket_host_->Send(dest2_, packet, options, 0, TRAFFIC_ANNOTATION_FOR_TESTS);
- EXPECT_EQ(6U, sent_packets_.size());
-}
-
-// Verify that we can open UDP sockets listening in a given port range,
-// and fail if all ports in the range are already in use.
-TEST_F(P2PSocketHostUdpTest, PortRangeImplicitPort) {
- const uint16_t min_port = 10000;
- const uint16_t max_port = 10001;
- base::circular_deque<FakeDatagramServerSocket::UDPPacket> sent_packets;
- std::vector<uint16_t> used_ports;
- P2PSocketHostUdp::DatagramServerSocketFactory fake_socket_factory =
- base::Bind(&CreateFakeDatagramServerSocket, &sent_packets, &used_ports);
- P2PMessageThrottler throttler;
- MockIPCSender sender;
- EXPECT_CALL(
- sender,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnSocketCreated::ID))))
- .Times(max_port - min_port + 1)
- .WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
-
- for (unsigned port = min_port; port <= max_port; ++port) {
- std::unique_ptr<P2PSocketHostUdp> socket_host(new P2PSocketHostUdp(
- &sender, 0, &throttler, /*net_log=*/nullptr, fake_socket_factory));
- net::IPEndPoint local_address = ParseAddress(kTestLocalIpAddress, 0);
- bool rv = socket_host->Init(local_address, min_port, max_port,
- P2PHostAndIPEndPoint());
- EXPECT_TRUE(rv);
-
- FakeDatagramServerSocket* socket = GetSocketFromHost(socket_host.get());
- net::IPEndPoint bound_address;
- socket->GetLocalAddress(&bound_address);
- EXPECT_EQ(port, bound_address.port());
- }
-
- EXPECT_CALL(sender,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnError::ID))))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- std::unique_ptr<P2PSocketHostUdp> socket_host(
- new P2PSocketHostUdp(&sender, 0, &throttler, /*net_log=*/nullptr,
- std::move(fake_socket_factory)));
- net::IPEndPoint local_address = ParseAddress(kTestLocalIpAddress, 0);
- bool rv = socket_host->Init(local_address, min_port, max_port,
- P2PHostAndIPEndPoint());
- EXPECT_FALSE(rv);
-}
-
-// Verify that we can open a UDP socket listening in a given port included in
-// a given valid range.
-TEST_F(P2PSocketHostUdpTest, PortRangeExplictValidPort) {
- const uint16_t min_port = 10000;
- const uint16_t max_port = 10001;
- const uint16_t valid_port = min_port;
- base::circular_deque<FakeDatagramServerSocket::UDPPacket> sent_packets;
- std::vector<uint16_t> used_ports;
- P2PSocketHostUdp::DatagramServerSocketFactory fake_socket_factory =
- base::Bind(&CreateFakeDatagramServerSocket, &sent_packets, &used_ports);
- P2PMessageThrottler throttler;
- MockIPCSender sender;
- EXPECT_CALL(
- sender,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnSocketCreated::ID))))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-
- std::unique_ptr<P2PSocketHostUdp> socket_host(
- new P2PSocketHostUdp(&sender, 0, &throttler, /*net_log=*/nullptr,
- std::move(fake_socket_factory)));
- net::IPEndPoint local_address = ParseAddress(kTestLocalIpAddress, valid_port);
- bool rv = socket_host->Init(local_address, min_port, max_port,
- P2PHostAndIPEndPoint());
- EXPECT_TRUE(rv);
-
- FakeDatagramServerSocket* socket = GetSocketFromHost(socket_host.get());
- net::IPEndPoint bound_address;
- socket->GetLocalAddress(&bound_address);
- EXPECT_EQ(local_address.port(), bound_address.port());
-}
-
-// Verify that we cannot open a UDP socket listening in a given port not
-// included in a given valid range.
-TEST_F(P2PSocketHostUdpTest, PortRangeExplictInvalidPort) {
- const uint16_t min_port = 10000;
- const uint16_t max_port = 10001;
- const uint16_t invalid_port = max_port + 1;
- base::circular_deque<FakeDatagramServerSocket::UDPPacket> sent_packets;
- std::vector<uint16_t> used_ports;
- P2PSocketHostUdp::DatagramServerSocketFactory fake_socket_factory =
- base::Bind(&CreateFakeDatagramServerSocket, &sent_packets, &used_ports);
- P2PMessageThrottler throttler;
- MockIPCSender sender;
- EXPECT_CALL(sender,
- Send(MatchMessage(static_cast<uint32_t>(P2PMsg_OnError::ID))))
- .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-
- std::unique_ptr<P2PSocketHostUdp> socket_host(
- new P2PSocketHostUdp(&sender, 0, &throttler, /*net_log=*/nullptr,
- std::move(fake_socket_factory)));
- net::IPEndPoint local_address =
- ParseAddress(kTestLocalIpAddress, invalid_port);
- bool rv = socket_host->Init(local_address, min_port, max_port,
- P2PHostAndIPEndPoint());
- EXPECT_FALSE(rv);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h b/chromium/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h
index 6f00768bc50..8aeaed49765 100644
--- a/chromium/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h
+++ b/chromium/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h
@@ -137,7 +137,7 @@ class CONTENT_EXPORT BrowserPpapiHostImpl : public BrowserPpapiHost {
PepperRendererInstanceData renderer_data;
bool is_throttled;
- base::ObserverList<InstanceObserver> observer_list;
+ base::ObserverList<InstanceObserver>::Unchecked observer_list;
};
std::unique_ptr<ppapi::host::PpapiHost> ppapi_host_;
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_external_file_ref_backend.cc b/chromium/content/browser/renderer_host/pepper/pepper_external_file_ref_backend.cc
index 628f9c9bab7..c4654b4f5a8 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_external_file_ref_backend.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_external_file_ref_backend.cc
@@ -8,7 +8,7 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/public/browser/browser_thread.h"
#include "ppapi/c/pp_errors.h"
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_file_io_host.cc b/chromium/content/browser/renderer_host/pepper/pepper_file_io_host.cc
index 474c1683dcd..14641886701 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_file_io_host.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_file_io_host.cc
@@ -10,11 +10,10 @@
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "content/browser/renderer_host/pepper/pepper_file_ref_host.h"
#include "content/browser/renderer_host/pepper/pepper_file_system_browser_host.h"
#include "content/browser/renderer_host/pepper/pepper_security_helper.h"
-#include "content/common/fileapi/file_system_messages.h"
#include "content/common/view_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc b/chromium/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc
index 6166a7b6616..ca2abd58bb4 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc
@@ -459,7 +459,7 @@ void PepperFileSystemBrowserHost::GotReservedQuota(
std::string PepperFileSystemBrowserHost::GetPluginMimeType() const {
base::FilePath plugin_path = browser_ppapi_host_->GetPluginPath();
- PepperPluginInfo* info =
+ const PepperPluginInfo* info =
PluginService::GetInstance()->GetRegisteredPpapiPluginInfo(plugin_path);
if (!info || info->mime_types.empty())
return std::string();
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.cc b/chromium/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.cc
index 4822d0d57e4..3619dfae8c8 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.cc
@@ -10,7 +10,7 @@
#include "base/files/file.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/renderer_host/pepper/pepper_security_helper.h"
#include "content/public/browser/browser_ppapi_host.h"
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_gamepad_host.h b/chromium/content/browser/renderer_host/pepper/pepper_gamepad_host.h
index cc3bcb581f7..3cec62b2c39 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_gamepad_host.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_gamepad_host.h
@@ -49,11 +49,13 @@ class CONTENT_EXPORT PepperGamepadHost :
const IPC::Message& msg,
ppapi::host::HostMessageContext* context) override;
- // GamepadConsumer implementation.
- void OnGamepadConnected(unsigned index,
+ // device::GamepadConsumer implementation.
+ void OnGamepadConnected(uint32_t index,
const device::Gamepad& gamepad) override {}
- void OnGamepadDisconnected(unsigned index,
+ void OnGamepadDisconnected(uint32_t index,
const device::Gamepad& gamepad) override {}
+ void OnGamepadButtonOrAxisChanged(uint32_t index,
+ const device::Gamepad& gamepad) override {}
private:
int32_t OnRequestMemory(ppapi::host::HostMessageContext* context);
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.cc b/chromium/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.cc
index 94a1f646ba9..d1cbc98e979 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.cc
@@ -10,7 +10,6 @@
#include "base/logging.h"
#include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
-#include "content/browser/renderer_host/pepper/pepper_lookup_request.h"
#include "content/browser/renderer_host/pepper/pepper_socket_utils.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
@@ -18,9 +17,6 @@
#include "content/public/browser/storage_partition.h"
#include "content/public/common/socket_permission_request.h"
#include "net/base/address_list.h"
-#include "net/dns/host_resolver.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/private/ppb_host_resolver_private.h"
#include "ppapi/c/private/ppb_net_address_private.h"
@@ -38,28 +34,22 @@ namespace content {
namespace {
void PrepareRequestInfo(const PP_HostResolver_Private_Hint& hint,
- net::HostResolver::RequestInfo* request_info) {
- DCHECK(request_info);
-
- net::AddressFamily address_family;
+ network::mojom::ResolveHostParameters* params) {
switch (hint.family) {
case PP_NETADDRESSFAMILY_PRIVATE_IPV4:
- address_family = net::ADDRESS_FAMILY_IPV4;
+ params->dns_query_type = net::HostResolver::DnsQueryType::A;
break;
case PP_NETADDRESSFAMILY_PRIVATE_IPV6:
- address_family = net::ADDRESS_FAMILY_IPV6;
+ params->dns_query_type = net::HostResolver::DnsQueryType::AAAA;
break;
default:
- address_family = net::ADDRESS_FAMILY_UNSPECIFIED;
+ params->dns_query_type = net::HostResolver::DnsQueryType::UNSPECIFIED;
}
- request_info->set_address_family(address_family);
- net::HostResolverFlags host_resolver_flags = 0;
if (hint.flags & PP_HOST_RESOLVER_PRIVATE_FLAGS_CANONNAME)
- host_resolver_flags |= net::HOST_RESOLVER_CANONNAME;
+ params->include_canonical_name = true;
if (hint.flags & PP_HOST_RESOLVER_PRIVATE_FLAGS_LOOPBACK_ONLY)
- host_resolver_flags |= net::HOST_RESOLVER_LOOPBACK_ONLY;
- request_info->set_host_resolver_flags(host_resolver_flags);
+ params->loopback_only = true;
}
void CreateNetAddressListFromAddressList(
@@ -90,7 +80,8 @@ PepperHostResolverMessageFilter::PepperHostResolverMessageFilter(
: external_plugin_(host->external_plugin()),
private_api_(private_api),
render_process_id_(0),
- render_frame_id_(0) {
+ render_frame_id_(0),
+ binding_(this) {
DCHECK(host);
if (!host->GetRenderFrameIDsForInstance(
@@ -142,63 +133,56 @@ int32_t PepperHostResolverMessageFilter::OnMsgResolve(
return PP_ERROR_FAILED;
auto* storage_partition = render_process_host->GetStoragePartition();
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(
- &PepperHostResolverMessageFilter::DoResolve, this,
- context->MakeReplyMessageContext(), host_port, hint,
- base::WrapRefCounted(storage_partition->GetURLRequestContext())));
+ // Grab a reference to this class to ensure that it's fully alive if a
+ // connection error occurs (i.e. ref count is higher than 0 and there's no
+ // task from ResourceMessageFilterDeleteTraits to delete this object on the IO
+ // thread pending). Balanced in OnComplete();
+ AddRef();
+
+ network::mojom::ResolveHostClientPtr client_ptr;
+ binding_.Bind(mojo::MakeRequest(&client_ptr));
+ binding_.set_connection_error_handler(
+ base::BindOnce(&PepperHostResolverMessageFilter::OnComplete,
+ base::Unretained(this), net::ERR_FAILED, base::nullopt));
+
+ network::mojom::ResolveHostParametersPtr parameters =
+ network::mojom::ResolveHostParameters::New();
+ PrepareRequestInfo(hint, parameters.get());
+
+ storage_partition->GetNetworkContext()->ResolveHost(
+ net::HostPortPair(host_port.host, host_port.port), std::move(parameters),
+ std::move(client_ptr));
+ host_resolve_context_ = context->MakeReplyMessageContext();
+
return PP_OK_COMPLETIONPENDING;
}
-void PepperHostResolverMessageFilter::DoResolve(
- const ReplyMessageContext& context,
- const ppapi::HostPortPair& host_port,
- const PP_HostResolver_Private_Hint& hint,
- scoped_refptr<net::URLRequestContextGetter> url_request_context_getter) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- auto* url_request_context =
- url_request_context_getter->GetURLRequestContext();
- if (!url_request_context) {
- SendResolveError(PP_ERROR_FAILED, context);
- return;
- }
+void PepperHostResolverMessageFilter::OnComplete(
+ int result,
+ const base::Optional<net::AddressList>& resolved_addresses) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ binding_.Close();
- net::HostResolver* host_resolver = url_request_context->host_resolver();
- if (!host_resolver) {
- SendResolveError(PP_ERROR_FAILED, context);
- return;
- }
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&PepperHostResolverMessageFilter::OnLookupFinished, this,
+ result, std::move(resolved_addresses),
+ host_resolve_context_));
+ host_resolve_context_ = ppapi::host::ReplyMessageContext();
- net::HostResolver::RequestInfo request_info(
- net::HostPortPair(host_port.host, host_port.port));
- PrepareRequestInfo(hint, &request_info);
-
- std::unique_ptr<ReplyMessageContext> bound_info(
- new ReplyMessageContext(context));
-
- // The lookup request will delete itself on completion.
- PepperLookupRequest<ReplyMessageContext>* lookup_request =
- new PepperLookupRequest<ReplyMessageContext>(
- host_resolver,
- request_info,
- net::DEFAULT_PRIORITY,
- bound_info.release(),
- base::Bind(&PepperHostResolverMessageFilter::OnLookupFinished, this));
- lookup_request->Start();
+ Release(); // Balances AddRef in OnMsgResolve.
}
void PepperHostResolverMessageFilter::OnLookupFinished(
int net_result,
- const net::AddressList& addresses,
+ const base::Optional<net::AddressList>& addresses,
const ReplyMessageContext& context) {
if (net_result != net::OK) {
SendResolveError(NetErrorToPepperError(net_result), context);
} else {
- const std::string& canonical_name = addresses.canonical_name();
+ const std::string& canonical_name = addresses.value().canonical_name();
NetAddressList net_address_list;
- CreateNetAddressListFromAddressList(addresses, &net_address_list);
+ CreateNetAddressListFromAddressList(addresses.value(), &net_address_list);
if (net_address_list.empty())
SendResolveError(PP_ERROR_FAILED, context);
else
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.h b/chromium/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.h
index cd9f2121322..80b1e5c6b9c 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.h
@@ -14,15 +14,16 @@
#include "base/macros.h"
#include "content/common/content_export.h"
#include "content/public/common/process_type.h"
+#include "mojo/public/cpp/bindings/binding.h"
#include "ppapi/c/pp_instance.h"
#include "ppapi/host/resource_message_filter.h"
+#include "services/network/public/mojom/network_context.mojom.h"
struct PP_HostResolver_Private_Hint;
struct PP_NetAddress_Private;
namespace net {
class AddressList;
-class URLRequestContextGetter;
}
namespace ppapi {
@@ -38,7 +39,8 @@ namespace content {
class BrowserPpapiHostImpl;
class CONTENT_EXPORT PepperHostResolverMessageFilter
- : public ppapi::host::ResourceMessageFilter {
+ : public ppapi::host::ResourceMessageFilter,
+ public network::mojom::ResolveHostClient {
public:
PepperHostResolverMessageFilter(BrowserPpapiHostImpl* host,
PP_Instance instance,
@@ -61,16 +63,13 @@ class CONTENT_EXPORT PepperHostResolverMessageFilter
const ppapi::HostPortPair& host_port,
const PP_HostResolver_Private_Hint& hint);
- // Backend for OnMsgResolve(). Delegates host resolution to the
- // Browser's HostResolver. Must be called on the IO thread.
- void DoResolve(
- const ppapi::host::ReplyMessageContext& context,
- const ppapi::HostPortPair& host_port,
- const PP_HostResolver_Private_Hint& hint,
- scoped_refptr<net::URLRequestContextGetter> url_request_context_getter);
+ // network::mojom::ResolveHostClient overrides.
+ void OnComplete(
+ int result,
+ const base::Optional<net::AddressList>& resolved_addresses) override;
void OnLookupFinished(int net_result,
- const net::AddressList& addresses,
+ const base::Optional<net::AddressList>& addresses,
const ppapi::host::ReplyMessageContext& bound_info);
void SendResolveReply(int32_t result,
const std::string& canonical_name,
@@ -79,11 +78,21 @@ class CONTENT_EXPORT PepperHostResolverMessageFilter
void SendResolveError(int32_t error,
const ppapi::host::ReplyMessageContext& context);
+ // The following members are only accessed on the IO thread.
+
bool external_plugin_;
bool private_api_;
int render_process_id_;
int render_frame_id_;
+ // The following members are only accessed on the UI thread.
+
+ // A reference to |this| must always be taken while |binding_| is bound to
+ // ensure that if the error callback is called the object is alive.
+ mojo::Binding<network::mojom::ResolveHostClient> binding_;
+
+ ppapi::host::ReplyMessageContext host_resolve_context_;
+
DISALLOW_COPY_AND_ASSIGN(PepperHostResolverMessageFilter);
};
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_lookup_request.h b/chromium/content/browser/renderer_host/pepper/pepper_lookup_request.h
deleted file mode 100644
index 128b3632b51..00000000000
--- a/chromium/content/browser/renderer_host/pepper/pepper_lookup_request.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_LOOKUP_REQUEST_H_
-#define CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_LOOKUP_REQUEST_H_
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "net/base/address_list.h"
-#include "net/base/net_errors.h"
-#include "net/dns/host_resolver.h"
-#include "net/log/net_log_with_source.h"
-
-namespace content {
-
-template <class T>
-class PepperLookupRequest {
- public:
- typedef base::Callback<void(int, const net::AddressList&, const T&)>
- LookupRequestCallback;
-
- // Takes ownership over |bound_info|. |bound_info| will be passed to
- // callback, when lookup will finish.
- PepperLookupRequest(net::HostResolver* resolver,
- const net::HostResolver::RequestInfo& request_info,
- net::RequestPriority priority,
- T* bound_info,
- const LookupRequestCallback& callback)
- : resolver_(resolver),
- request_info_(request_info),
- priority_(priority),
- bound_info_(bound_info),
- callback_(callback) {}
-
- void Start() {
- int result =
- resolver_->Resolve(request_info_, priority_, &addresses_,
- base::Bind(&PepperLookupRequest<T>::OnLookupFinished,
- base::Unretained(this)),
- &request_, net::NetLogWithSource());
- if (result != net::ERR_IO_PENDING)
- OnLookupFinished(result);
- }
-
- private:
- void OnLookupFinished(int result) {
- callback_.Run(result, addresses_, *bound_info_);
- delete this;
- }
-
- net::HostResolver* resolver_;
- std::unique_ptr<net::HostResolver::Request> request_;
- net::HostResolver::RequestInfo request_info_;
- net::RequestPriority priority_;
- std::unique_ptr<T> bound_info_;
- LookupRequestCallback callback_;
-
- net::AddressList addresses_;
-
- DISALLOW_COPY_AND_ASSIGN(PepperLookupRequest);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_LOOKUP_REQUEST_H_
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_network_monitor_host.cc b/chromium/content/browser/renderer_host/pepper/pepper_network_monitor_host.cc
index ed62e219f02..9f0fc648abf 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_network_monitor_host.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_network_monitor_host.cc
@@ -6,8 +6,8 @@
#include <stddef.h>
+#include "base/task/post_task.h"
#include "base/task_runner_util.h"
-#include "base/task_scheduler/post_task.h"
#include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
#include "content/browser/renderer_host/pepper/pepper_socket_utils.h"
#include "content/public/browser/browser_thread.h"
@@ -90,7 +90,7 @@ void PepperNetworkMonitorHost::GetAndSendNetworkList() {
// Call GetNetworkList() on a thread that allows blocking IO.
base::PostTaskWithTraitsAndReplyWithResult(
- FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
base::Bind(&GetNetworkList),
base::Bind(&PepperNetworkMonitorHost::SendNetworkList,
weak_factory_.GetWeakPtr()));
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.cc b/chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.cc
index 3fcb804a5f8..75774080312 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.cc
@@ -6,56 +6,68 @@
#include "base/bind.h"
#include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
+#include "content/browser/renderer_host/pepper/pepper_proxy_lookup_helper.h"
#include "content/browser/renderer_host/pepper/pepper_socket_utils.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/site_instance.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/socket_permission_request.h"
-#include "net/base/net_errors.h"
-#include "net/log/net_log_with_source.h"
#include "net/proxy_resolution/proxy_info.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/host/dispatch_host_message.h"
#include "ppapi/host/ppapi_host.h"
#include "ppapi/proxy/ppapi_messages.h"
+#include "services/network/public/mojom/network_context.mojom.h"
+#include "services/network/public/mojom/proxy_lookup_client.mojom.h"
namespace content {
+namespace {
+
+bool LookUpProxyForURLCallback(
+ int render_process_host_id,
+ int render_frame_host_id,
+ const GURL& url,
+ network::mojom::ProxyLookupClientPtr proxy_lookup_client) {
+ RenderFrameHost* render_frame_host =
+ RenderFrameHost::FromID(render_process_host_id, render_frame_host_id);
+ if (!render_frame_host)
+ return false;
+
+ SiteInstance* site_instance = render_frame_host->GetSiteInstance();
+ StoragePartition* storage_partition = BrowserContext::GetStoragePartition(
+ site_instance->GetBrowserContext(), site_instance);
+
+ storage_partition->GetNetworkContext()->LookUpProxyForURL(
+ url, std::move(proxy_lookup_client));
+ return true;
+}
+
+} // namespace
+
PepperNetworkProxyHost::PepperNetworkProxyHost(BrowserPpapiHostImpl* host,
PP_Instance instance,
PP_Resource resource)
: ResourceHost(host->GetPpapiHost(), instance, resource),
- proxy_resolution_service_(nullptr),
+ render_process_id_(0),
+ render_frame_id_(0),
is_allowed_(false),
waiting_for_ui_thread_data_(true),
weak_factory_(this) {
- int render_process_id(0), render_frame_id(0);
- host->GetRenderFrameIDsForInstance(
- instance, &render_process_id, &render_frame_id);
+ host->GetRenderFrameIDsForInstance(instance, &render_process_id_,
+ &render_frame_id_);
BrowserThread::PostTaskAndReplyWithResult(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&GetUIThreadDataOnUIThread,
- render_process_id,
- render_frame_id,
- host->external_plugin()),
- base::Bind(&PepperNetworkProxyHost::DidGetUIThreadData,
- weak_factory_.GetWeakPtr()));
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&GetUIThreadDataOnUIThread, render_process_id_,
+ render_frame_id_, host->external_plugin()),
+ base::BindOnce(&PepperNetworkProxyHost::DidGetUIThreadData,
+ weak_factory_.GetWeakPtr()));
}
-PepperNetworkProxyHost::~PepperNetworkProxyHost() {
- while (!pending_requests_.empty()) {
- // If the proxy_resolution_service_ is NULL, we shouldn't have any outstanding
- // requests.
- DCHECK(proxy_resolution_service_);
- net::ProxyResolutionService::Request* request = pending_requests_.front();
- proxy_resolution_service_->CancelRequest(request);
- pending_requests_.pop();
- }
-}
+PepperNetworkProxyHost::~PepperNetworkProxyHost() = default;
PepperNetworkProxyHost::UIThreadData::UIThreadData() : is_allowed(false) {}
@@ -71,9 +83,6 @@ PepperNetworkProxyHost::GetUIThreadDataOnUIThread(int render_process_id,
bool is_external_plugin) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
PepperNetworkProxyHost::UIThreadData result;
- RenderProcessHost* rph = RenderProcessHost::FromID(render_process_id);
- if (rph)
- result.context_getter = rph->GetStoragePartition()->GetURLRequestContext();
SocketPermissionRequest request(
content::SocketPermissionRequest::RESOLVE_PROXY, std::string(), 0);
@@ -89,16 +98,7 @@ PepperNetworkProxyHost::GetUIThreadDataOnUIThread(int render_process_id,
void PepperNetworkProxyHost::DidGetUIThreadData(
const UIThreadData& ui_thread_data) {
is_allowed_ = ui_thread_data.is_allowed;
- if (ui_thread_data.context_getter.get() &&
- ui_thread_data.context_getter->GetURLRequestContext()) {
- proxy_resolution_service_ =
- ui_thread_data.context_getter->GetURLRequestContext()->proxy_resolution_service();
- }
waiting_for_ui_thread_data_ = false;
- if (!proxy_resolution_service_) {
- DLOG_IF(WARNING, proxy_resolution_service_)
- << "Failed to find a ProxyResolutionService for Pepper plugin.";
- }
TryToSendUnsentRequests();
}
@@ -132,27 +132,23 @@ void PepperNetworkProxyHost::TryToSendUnsentRequests() {
while (!unsent_requests_.empty()) {
const UnsentRequest& request = unsent_requests_.front();
- if (!proxy_resolution_service_) {
- SendFailureReply(PP_ERROR_FAILED, request.reply_context);
- } else if (!is_allowed_) {
+ if (!is_allowed_) {
SendFailureReply(PP_ERROR_NOACCESS, request.reply_context);
} else {
// Everything looks valid, so try to resolve the proxy.
- net::ProxyInfo* proxy_info = new net::ProxyInfo;
- net::ProxyResolutionService::Request* pending_request = nullptr;
- base::Callback<void(int)> callback =
- base::Bind(&PepperNetworkProxyHost::OnResolveProxyCompleted,
- weak_factory_.GetWeakPtr(),
- request.reply_context,
- base::Owned(proxy_info));
- int result = proxy_resolution_service_->ResolveProxy(
- request.url, std::string(), proxy_info, callback, &pending_request,
- nullptr, net::NetLogWithSource());
- pending_requests_.push(pending_request);
- // If it was handled synchronously, we must run the callback now;
- // proxy_resolution_service_ won't run it for us in this case.
- if (result != net::ERR_IO_PENDING)
- std::move(callback).Run(result);
+ auto lookup_helper = std::make_unique<PepperProxyLookupHelper>();
+ PepperProxyLookupHelper::LookUpProxyForURLCallback
+ look_up_proxy_for_url_callback = base::BindOnce(
+ &LookUpProxyForURLCallback, render_process_id_, render_frame_id_);
+ PepperProxyLookupHelper::LookUpCompleteCallback
+ look_up_complete_callback =
+ base::BindOnce(&PepperNetworkProxyHost::OnResolveProxyCompleted,
+ weak_factory_.GetWeakPtr(), request.reply_context,
+ lookup_helper.get());
+ lookup_helper->Start(request.url,
+ std::move(look_up_proxy_for_url_callback),
+ std::move(look_up_complete_callback));
+ pending_requests_.insert(std::move(lookup_helper));
}
unsent_requests_.pop();
}
@@ -160,20 +156,24 @@ void PepperNetworkProxyHost::TryToSendUnsentRequests() {
void PepperNetworkProxyHost::OnResolveProxyCompleted(
ppapi::host::ReplyMessageContext context,
- net::ProxyInfo* proxy_info,
- int result) {
- pending_requests_.pop();
-
- if (result != net::OK) {
- // Currently, the only proxy-specific error we could get is
- // MANDATORY_PROXY_CONFIGURATION_FAILED. There's really no action a plugin
- // can take in this case, so there's no need to distinguish it from other
- // failures.
+ PepperProxyLookupHelper* pending_request,
+ base::Optional<net::ProxyInfo> proxy_info) {
+ auto it = pending_requests_.find(pending_request);
+ DCHECK(it != pending_requests_.end());
+ pending_requests_.erase(it);
+
+ std::string pac_string;
+ if (!proxy_info) {
+ // This can happen in cases of network service crash, shutdown, or when
+ // the request fails with ERR_MANDATORY_PROXY_CONFIGURATION_FAILED. There's
+ // really no action a plugin can take, so there's no need to distinguish
+ // which error occurred.
context.params.set_result(PP_ERROR_FAILED);
+ } else {
+ pac_string = proxy_info->ToPacString();
}
- host()->SendReply(context,
- PpapiPluginMsg_NetworkProxy_GetProxyForURLReply(
- proxy_info->ToPacString()));
+ host()->SendReply(
+ context, PpapiPluginMsg_NetworkProxy_GetProxyForURLReply(pac_string));
}
void PepperNetworkProxyHost::SendFailureReply(
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.h b/chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.h
index a3b9424aeba..081c4045864 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.h
@@ -8,20 +8,22 @@
#include <stdint.h>
#include <queue>
+#include <set>
#include <string>
#include "base/compiler_specific.h"
#include "base/containers/queue.h"
+#include "base/containers/unique_ptr_adapters.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
#include "content/common/content_export.h"
-#include "net/proxy_resolution/proxy_resolution_service.h"
#include "ppapi/host/host_message_context.h"
#include "ppapi/host/resource_host.h"
+#include "url/gurl.h"
namespace net {
class ProxyInfo;
-class URLRequestContextGetter;
}
namespace ppapi {
@@ -33,6 +35,7 @@ struct ReplyMessageContext;
namespace content {
class BrowserPpapiHostImpl;
+class PepperProxyLookupHelper;
// The host for PPB_NetworkProxy. This class lives on the IO thread.
class CONTENT_EXPORT PepperNetworkProxyHost : public ppapi::host::ResourceHost {
@@ -44,15 +47,14 @@ class CONTENT_EXPORT PepperNetworkProxyHost : public ppapi::host::ResourceHost {
~PepperNetworkProxyHost() override;
private:
- // We retrieve the appropriate URLRequestContextGetter and whether this API
- // is allowed for the instance on the UI thread and pass those to
- // DidGetUIThreadData, which sets allowed_ and proxy_resolution_service_.
+ // We retrieve whether this API is allowed for the instance on the UI thread
+ // and pass it to DidGetUIThreadData, which sets allowed_.
struct UIThreadData {
UIThreadData();
UIThreadData(const UIThreadData& other);
~UIThreadData();
+
bool is_allowed;
- scoped_refptr<net::URLRequestContextGetter> context_getter;
};
static UIThreadData GetUIThreadDataOnUIThread(int render_process_id,
int render_frame_id,
@@ -67,39 +69,39 @@ class CONTENT_EXPORT PepperNetworkProxyHost : public ppapi::host::ResourceHost {
int32_t OnMsgGetProxyForURL(ppapi::host::HostMessageContext* context,
const std::string& url);
- // If we have a valid proxy_resolution_service_, send all messages in
- // unsent_requests_.
+ // Send all messages in |unsent_requests_|.
void TryToSendUnsentRequests();
void OnResolveProxyCompleted(ppapi::host::ReplyMessageContext context,
- net::ProxyInfo* proxy_info,
- int result);
+ PepperProxyLookupHelper* pending_request,
+ base::Optional<net::ProxyInfo> proxy_info);
void SendFailureReply(int32_t error,
ppapi::host::ReplyMessageContext context);
- // The following two members are invalid until we get some information from
- // the UI thread. However, these are only ever set or accessed on the IO
- // thread.
- net::ProxyResolutionService* proxy_resolution_service_;
+ // Used to find correct NetworkContext to perform proxy lookups.
+ int render_process_id_;
+ int render_frame_id_;
+
+ // The following member is invalid until we get some information from the UI
+ // thread. However, it is only ever set or accessed on the IO thread.
bool is_allowed_;
- // True initially, but set to false once the values for
- // proxy_resolution_service_ and is_allowed_ have been set.
+ // True initially, but set to false once is_allowed_ has been set.
bool waiting_for_ui_thread_data_;
- // We have to get the URLRequestContextGetter from the UI thread before we
- // can retrieve proxy_resolution_service_. If we receive any calls for
- // GetProxyForURL before proxy_resolution_service_ is available, we save them
- // in unsent_requests_.
+ // We have to get is_allowed_ from the UI thread before we can start a
+ // request. If we receive any calls for GetProxyForURL before is_allowed_ is
+ // available, we save them in unsent_requests_.
struct UnsentRequest {
GURL url;
ppapi::host::ReplyMessageContext reply_context;
};
base::queue<UnsentRequest> unsent_requests_;
- // Requests awaiting a response from ProxyResolutionService. We need to store
+ // Requests awaiting a response from the network service. We need to store
// these so that we can cancel them if we get destroyed.
- base::queue<net::ProxyResolutionService::Request*> pending_requests_;
+ std::set<std::unique_ptr<PepperProxyLookupHelper>, base::UniquePtrComparator>
+ pending_requests_;
base::WeakPtrFactory<PepperNetworkProxyHost> weak_factory_;
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_proxy_lookup_helper.cc b/chromium/content/browser/renderer_host/pepper/pepper_proxy_lookup_helper.cc
new file mode 100644
index 00000000000..95928393273
--- /dev/null
+++ b/chromium/content/browser/renderer_host/pepper/pepper_proxy_lookup_helper.cc
@@ -0,0 +1,106 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/renderer_host/pepper/pepper_proxy_lookup_helper.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/sequenced_task_runner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "content/public/browser/browser_thread.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "url/gurl.h"
+
+namespace content {
+
+// Runs the proxy lookup on the UI thread. Created on the
+// PepperProxyLookupHelper's thread, but then does all work on the UI thread,
+// and is deleted there by a task posted by the PepperProxyLookupHelper.
+class PepperProxyLookupHelper::UIThreadHelper
+ : public network::mojom::ProxyLookupClient {
+ public:
+ UIThreadHelper(const GURL& url,
+ LookUpProxyForURLCallback look_up_proxy_for_url_callback,
+ LookUpCompleteCallback look_up_complete_callback)
+ : binding_(this),
+ look_up_complete_callback_(std::move(look_up_complete_callback)),
+ callback_task_runner_(base::SequencedTaskRunnerHandle::Get()) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&UIThreadHelper::StartLookup, base::Unretained(this),
+ url, std::move(look_up_proxy_for_url_callback)));
+ }
+
+ ~UIThreadHelper() override { DCHECK_CURRENTLY_ON(BrowserThread::UI); }
+
+ private:
+ void StartLookup(const GURL& url,
+ LookUpProxyForURLCallback look_up_proxy_for_url_callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ network::mojom::ProxyLookupClientPtr proxy_lookup_client;
+ binding_.Bind(mojo::MakeRequest(&proxy_lookup_client));
+ binding_.set_connection_error_handler(
+ base::BindOnce(&UIThreadHelper::OnProxyLookupComplete,
+ base::Unretained(this), base::nullopt));
+ if (!std::move(look_up_proxy_for_url_callback)
+ .Run(url, std::move(proxy_lookup_client))) {
+ OnProxyLookupComplete(base::nullopt);
+ }
+ }
+
+ void OnProxyLookupComplete(
+ const base::Optional<net::ProxyInfo>& proxy_info) override {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ binding_.Close();
+ callback_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(look_up_complete_callback_), proxy_info));
+ }
+
+ mojo::Binding<network::mojom::ProxyLookupClient> binding_;
+
+ LookUpCompleteCallback look_up_complete_callback_;
+ scoped_refptr<base::SequencedTaskRunner> callback_task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(UIThreadHelper);
+};
+
+PepperProxyLookupHelper::PepperProxyLookupHelper() : weak_factory_(this) {}
+
+PepperProxyLookupHelper::~PepperProxyLookupHelper() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE,
+ std::move(ui_thread_helper_));
+}
+
+void PepperProxyLookupHelper::Start(
+ const GURL& url,
+ LookUpProxyForURLCallback look_up_proxy_for_url_callback,
+ LookUpCompleteCallback look_up_complete_callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(!look_up_complete_callback_);
+ DCHECK(!ui_thread_helper_);
+
+ look_up_complete_callback_ = std::move(look_up_complete_callback);
+
+ ui_thread_helper_ = std::make_unique<UIThreadHelper>(
+ url, std::move(look_up_proxy_for_url_callback),
+ base::BindOnce(&PepperProxyLookupHelper::OnProxyLookupComplete,
+ weak_factory_.GetWeakPtr()));
+}
+
+void PepperProxyLookupHelper::OnProxyLookupComplete(
+ base::Optional<net::ProxyInfo> proxy_info) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ std::move(look_up_complete_callback_).Run(std::move(proxy_info));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_proxy_lookup_helper.h b/chromium/content/browser/renderer_host/pepper/pepper_proxy_lookup_helper.h
new file mode 100644
index 00000000000..f6ea3869957
--- /dev/null
+++ b/chromium/content/browser/renderer_host/pepper/pepper_proxy_lookup_helper.h
@@ -0,0 +1,70 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_PROXY_LOOKUP_HELPER_H_
+#define CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_PROXY_LOOKUP_HELPER_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "base/sequence_checker.h"
+#include "content/common/content_export.h"
+#include "services/network/public/mojom/proxy_lookup_client.mojom.h"
+
+class GURL;
+
+namespace net {
+class ProxyInfo;
+}
+
+namespace content {
+
+// Class that runs a single proxy resolution on the UI thread. Lives on the
+// thread its created on, and uses a helper to run tasks off-thread. Can be
+// destroyed at any time.
+class CONTENT_EXPORT PepperProxyLookupHelper {
+ public:
+ // Callback to call LookUpProxyForURL. Called on the UI thread. Needed for
+ // testing. Returns false if unable to make the call, for whatever reason.
+ using LookUpProxyForURLCallback = base::OnceCallback<bool(
+ const GURL& url,
+ network::mojom::ProxyLookupClientPtr proxy_lookup_client)>;
+
+ // Callback to invoke when complete. Invoked on thread the
+ // PepperProxyLookupHelper was created on.
+ using LookUpCompleteCallback =
+ base::OnceCallback<void(base::Optional<net::ProxyInfo> proxy_info)>;
+
+ PepperProxyLookupHelper();
+ ~PepperProxyLookupHelper();
+
+ // Starts a lookup for |url| on the UI thread. Invokes
+ // |look_up_proxy_for_url_callback| on the UI thread to start the lookup, and
+ // calls |look_up_complete_callback| on the thread Start() was called on when
+ // complete. May only be invoked once.
+ void Start(const GURL& url,
+ LookUpProxyForURLCallback look_up_proxy_for_url_callback,
+ LookUpCompleteCallback look_up_complete_callback);
+
+ private:
+ class UIThreadHelper;
+
+ void OnProxyLookupComplete(base::Optional<net::ProxyInfo> proxy_info);
+
+ LookUpCompleteCallback look_up_complete_callback_;
+ std::unique_ptr<UIThreadHelper> ui_thread_helper_;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ base::WeakPtrFactory<PepperProxyLookupHelper> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PepperProxyLookupHelper);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_PROXY_LOOKUP_HELPER_H_
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_proxy_lookup_helper_unittest.cc b/chromium/content/browser/renderer_host/pepper/pepper_proxy_lookup_helper_unittest.cc
new file mode 100644
index 00000000000..25f87fdcad3
--- /dev/null
+++ b/chromium/content/browser/renderer_host/pepper/pepper_proxy_lookup_helper_unittest.cc
@@ -0,0 +1,203 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/renderer_host/pepper/pepper_proxy_lookup_helper.h"
+
+#include <memory>
+#include <string>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "base/run_loop.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/proxy_resolution/proxy_info.h"
+#include "services/network/public/mojom/proxy_lookup_client.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace content {
+namespace {
+
+constexpr char kTestURL[] = "http://foo/";
+
+class PepperProxyLookupHelperTest : public testing::Test {
+ public:
+ PepperProxyLookupHelperTest() = default;
+ ~PepperProxyLookupHelperTest() override = default;
+
+ // Initializes |lookup_helper_| on the IO thread, and starts it there. Returns
+ // once it has called into LookUpProxyForURLOnUIThread on the UI thread.
+ void StartLookup() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ base::RunLoop run_loop;
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&PepperProxyLookupHelperTest::StartLookupOnIOThread,
+ base::Unretained(this), run_loop.QuitClosure()));
+ run_loop.Run();
+
+ EXPECT_TRUE(lookup_helper_);
+ if (!fail_to_start_request_)
+ EXPECT_TRUE(proxy_lookup_client_);
+ }
+
+ // Takes the |ProxyLookupClientPtr| passed by |lookup_helper_| to
+ // LookUpProxyForURLOnUIThread(). May only be called after |lookup_helper_|
+ // has successfully called into LookUpProxyForURLOnUIThread().
+ network::mojom::ProxyLookupClientPtr ClaimProxyLookupClient() {
+ EXPECT_TRUE(proxy_lookup_client_);
+ return std::move(proxy_lookup_client_);
+ }
+
+ void DestroyLookupHelper() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ base::RunLoop run_loop;
+
+ BrowserThread::PostTaskAndReply(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(
+ &PepperProxyLookupHelperTest::DestroyLookupHelperOnIOThread,
+ base::Unretained(this)),
+ run_loop.QuitClosure());
+ run_loop.Run();
+ }
+
+ // Waits for |lookup_helper_| to call into OnLookupCompleteOnIOThread(),
+ // signally proxy lookup completion.
+ void WaitForLookupCompletion() {
+ EXPECT_TRUE(lookup_helper_);
+ lookup_complete_run_loop_.Run();
+ }
+
+ // Get the proxy information passed into OnLookupCompleteOnIOThread().
+ const base::Optional<net::ProxyInfo>& proxy_info() const {
+ return proxy_info_;
+ }
+
+ // Setting this to true will make LookUpProxyForURLOnUIThread, the callback
+ // invoked to start looking up the proxy, return false.
+ void set_fail_to_start_request(bool fail_to_start_request) {
+ fail_to_start_request_ = fail_to_start_request;
+ }
+
+ private:
+ // Must be called on the IO thread. Initializes |lookup_helper_| and starts a
+ // proxy lookup. Invokes |closure| on the UI thread once the |lookup_helper_|
+ // has invoked LookUpProxyForURLOnUIThread on the UI thread.
+ void StartLookupOnIOThread(base::OnceClosure closure) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(!lookup_helper_);
+
+ lookup_helper_ = std::make_unique<PepperProxyLookupHelper>();
+ lookup_helper_->Start(
+ GURL(kTestURL),
+ base::BindOnce(
+ &PepperProxyLookupHelperTest::LookUpProxyForURLOnUIThread,
+ base::Unretained(this), std::move(closure)),
+ base::BindOnce(&PepperProxyLookupHelperTest::OnLookupCompleteOnIOThread,
+ base::Unretained(this)));
+ }
+
+ // Callback passed to |lookup_helper_| to start the proxy lookup.
+ bool LookUpProxyForURLOnUIThread(
+ base::OnceClosure closure,
+ const GURL& url,
+ network::mojom::ProxyLookupClientPtr proxy_lookup_client) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ std::move(closure).Run();
+
+ if (fail_to_start_request_)
+ return false;
+
+ EXPECT_EQ(GURL(kTestURL), url);
+ proxy_lookup_client_ = std::move(proxy_lookup_client);
+ return true;
+ }
+
+ // Invoked by |lookup_helper_| on the IO thread once the proxy lookup has
+ // completed.
+ void OnLookupCompleteOnIOThread(base::Optional<net::ProxyInfo> proxy_info) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ proxy_info_ = std::move(proxy_info);
+ lookup_helper_.reset();
+ lookup_complete_run_loop_.Quit();
+ }
+
+ void DestroyLookupHelperOnIOThread() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ lookup_helper_.reset();
+ }
+
+ TestBrowserThreadBundle test_browser_thread_bundle_;
+
+ bool fail_to_start_request_ = false;
+
+ std::unique_ptr<PepperProxyLookupHelper> lookup_helper_;
+
+ base::Optional<net::ProxyInfo> proxy_info_;
+ network::mojom::ProxyLookupClientPtr proxy_lookup_client_;
+
+ base::RunLoop lookup_complete_run_loop_;
+};
+
+TEST_F(PepperProxyLookupHelperTest, Success) {
+ StartLookup();
+ net::ProxyInfo proxy_info_response;
+ proxy_info_response.UseNamedProxy("result:80");
+ ClaimProxyLookupClient()->OnProxyLookupComplete(proxy_info_response);
+ WaitForLookupCompletion();
+ ASSERT_TRUE(proxy_info());
+ EXPECT_EQ("PROXY result:80", proxy_info()->ToPacString());
+}
+
+// Basic failure case - an error is passed to the PepperProxyLookupHelper
+// through the ProxyLookupClient API.
+TEST_F(PepperProxyLookupHelperTest, Failure) {
+ StartLookup();
+ ClaimProxyLookupClient()->OnProxyLookupComplete(base::nullopt);
+ WaitForLookupCompletion();
+ EXPECT_FALSE(proxy_info());
+}
+
+// The mojo pipe is closed before the PepperProxyLookupHelper's callback is
+// invoked.
+TEST_F(PepperProxyLookupHelperTest, PipeClosed) {
+ StartLookup();
+ ClaimProxyLookupClient().reset();
+ WaitForLookupCompletion();
+ EXPECT_FALSE(proxy_info());
+}
+
+// The proxy lookup fails to start - instead, the callback to start the lookup
+// returns false.
+TEST_F(PepperProxyLookupHelperTest, FailToStartRequest) {
+ set_fail_to_start_request(true);
+
+ StartLookup();
+ WaitForLookupCompletion();
+ EXPECT_FALSE(proxy_info());
+}
+
+// Destroy the helper before it completes a lookup. Make sure it cancels the
+// connection, and memory tools don't detect a leak.
+TEST_F(PepperProxyLookupHelperTest, DestroyBeforeComplete) {
+ StartLookup();
+ base::RunLoop run_loop;
+ network::mojom::ProxyLookupClientPtr proxy_lookup_client =
+ ClaimProxyLookupClient();
+ proxy_lookup_client.set_connection_error_handler(run_loop.QuitClosure());
+ DestroyLookupHelper();
+ run_loop.Run();
+}
+
+} // namespace
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_socket_utils.cc b/chromium/content/browser/renderer_host/pepper/pepper_socket_utils.cc
index 2050cf6f4d3..13816b2f8fe 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_socket_utils.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_socket_utils.cc
@@ -186,5 +186,94 @@ void OpenUDPFirewallHole(const net::IPEndPoint& address,
}
#endif // defined(OS_CHROMEOS)
+net::MutableNetworkTrafficAnnotationTag PepperTCPNetworkAnnotationTag() {
+ return net::MutableNetworkTrafficAnnotationTag(
+ net::DefineNetworkTrafficAnnotation("pepper_tcp_socket",
+ R"(
+ semantics {
+ sender: "Pepper TCP Socket"
+ description:
+ "Pepper plugins use this API to send and receive data over the "
+ "network using TCP connections. This inteface is used by Flash and "
+ "PDF viewer, and Chrome Apps which use plugins to send/receive TCP "
+ "traffic (require Chrome Apps TCP socket permission). This "
+ "interface allows creation of client and server sockets."
+ trigger:
+ "A request from a Pepper plugin."
+ data: "Any data that the plugin sends."
+ destination: OTHER
+ destination_other:
+ "Data can be sent to any destination."
+ }
+ policy {
+ cookies_allowed: NO
+ setting:
+ "These requests cannot be disabled, but will not happen if user "
+ "does not use Flash, internal PDF Viewer, or Chrome Apps that use "
+ "Pepper interface."
+ chrome_policy {
+ DefaultPluginsSetting {
+ DefaultPluginsSetting: 2
+ }
+ }
+ chrome_policy {
+ AlwaysOpenPdfExternally {
+ AlwaysOpenPdfExternally: true
+ }
+ }
+ chrome_policy {
+ ExtensionInstallBlacklist {
+ ExtensionInstallBlacklist: {
+ entries: '*'
+ }
+ }
+ }
+ })"));
+}
+
+net::MutableNetworkTrafficAnnotationTag PepperUDPNetworkAnnotationTag() {
+ return net::MutableNetworkTrafficAnnotationTag(
+ net::DefineNetworkTrafficAnnotation("pepper_udp_socket",
+ R"(
+ semantics {
+ sender: "Pepper UDP Socket"
+ description:
+ "Pepper plugins use this API to send and receive data over the "
+ "network using UDP connections. This inteface is used by Flash and "
+ "PDF viewer, and Chrome Apps which use plugins to send/receive UDP "
+ "traffic (require Chrome Apps UDP socket permission)."
+ trigger:
+ "A request from a Pepper plugin."
+ data: "Any data that the plugin sends."
+ destination: OTHER
+ destination_other:
+ "Data can be sent to any destination."
+ }
+ policy {
+ cookies_allowed: NO
+ setting:
+ "These requests cannot be disabled, but will not happen if user "
+ "does not use Flash, internal PDF Viewer, or Chrome Apps that use "
+ "Pepper interface."
+ chrome_policy {
+ DefaultPluginsSetting {
+ DefaultPluginsSetting: 2
+ }
+ }
+ chrome_policy {
+ AlwaysOpenPdfExternally {
+ AlwaysOpenPdfExternally: true
+ }
+ }
+ chrome_policy {
+ ExtensionInstallBlacklist {
+ ExtensionInstallBlacklist: {
+ entries: '*'
+ }
+ }
+ }
+ })"));
+}
+
} // namespace pepper_socket_utils
} // namespace content
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_socket_utils.h b/chromium/content/browser/renderer_host/pepper/pepper_socket_utils.h
index b10c940800f..c9863ab62a8 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_socket_utils.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_socket_utils.h
@@ -9,6 +9,7 @@
#include "build/build_config.h"
#include "content/public/common/socket_permission_request.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
#include "ppapi/c/pp_stdint.h"
#if defined(OS_CHROMEOS)
@@ -72,6 +73,11 @@ void OpenUDPFirewallHole(const net::IPEndPoint& address,
FirewallHoleOpenCallback callback);
#endif // defined(OS_CHROMEOS)
+// Annotations for TCP and UDP network requests. Defined here to make it easier
+// to keep them in sync.
+net::MutableNetworkTrafficAnnotationTag PepperTCPNetworkAnnotationTag();
+net::MutableNetworkTrafficAnnotationTag PepperUDPNetworkAnnotationTag();
+
} // namespace pepper_socket_utils
} // namespace content
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc b/chromium/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
index 3a8cb7c6cd0..429d3d217da 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
@@ -141,11 +141,9 @@ int32_t PepperTCPServerSocketMessageFilter::OnMsgAccept(
ppapi::host::ReplyMessageContext reply_context(
context->MakeReplyMessageContext());
int net_result = socket_->Accept(
- &accepted_socket_,
- &accepted_address_,
+ &accepted_socket_, &accepted_address_,
base::Bind(&PepperTCPServerSocketMessageFilter::OnAcceptCompleted,
- base::Unretained(this),
- reply_context));
+ base::Unretained(this), reply_context));
if (net_result != net::ERR_IO_PENDING)
OnAcceptCompleted(reply_context, net_result);
return PP_OK_COMPLETIONPENDING;
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc b/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
index 17d9f021651..6eb9ecd9c87 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
@@ -33,8 +33,6 @@
#include "net/socket/ssl_client_socket.h"
#include "net/socket/tcp_client_socket.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
#include "ppapi/host/dispatch_host_message.h"
#include "ppapi/host/error_conversion.h"
#include "ppapi/host/ppapi_host.h"
@@ -70,6 +68,7 @@ PepperTCPSocketMessageFilter::PepperTCPSocketMessageFilter(
external_plugin_(host->external_plugin()),
render_process_id_(0),
render_frame_id_(0),
+ binding_(this),
host_(host),
factory_(factory),
instance_(instance),
@@ -107,6 +106,7 @@ PepperTCPSocketMessageFilter::PepperTCPSocketMessageFilter(
external_plugin_(host->external_plugin()),
render_process_id_(0),
render_frame_id_(0),
+ binding_(this),
host_(host),
factory_(nullptr),
instance_(instance),
@@ -214,6 +214,20 @@ void PepperTCPSocketMessageFilter::OnHostDestroyed() {
host_ = nullptr;
}
+void PepperTCPSocketMessageFilter::OnComplete(
+ int result,
+ const base::Optional<net::AddressList>& resolved_addresses) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ binding_.Close();
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&PepperTCPSocketMessageFilter::OnResolveCompleted, this,
+ result, std::move(resolved_addresses)));
+
+ Release(); // Balances AddRef in OnMsgConnect.
+}
+
int32_t PepperTCPSocketMessageFilter::OnMsgBind(
const ppapi::host::HostMessageContext* context,
const PP_NetAddress_Private& net_addr) {
@@ -267,13 +281,24 @@ int32_t PepperTCPSocketMessageFilter::OnMsgConnect(
if (!render_process_host)
return PP_ERROR_FAILED;
auto* storage_partition = render_process_host->GetStoragePartition();
+ // Grab a reference to this class to ensure that it's fully alive if a
+ // connection error occurs (i.e. ref count is higher than 0 and there's no
+ // task from ResourceMessageFilterDeleteTraits to delete this object on the IO
+ // thread pending). Balanced in OnComplete();
+ AddRef();
+
+ network::mojom::ResolveHostClientPtr client_ptr;
+ binding_.Bind(mojo::MakeRequest(&client_ptr));
+ binding_.set_connection_error_handler(
+ base::BindOnce(&PepperTCPSocketMessageFilter::OnComplete,
+ base::Unretained(this), net::ERR_FAILED, base::nullopt));
+ storage_partition->GetNetworkContext()->ResolveHost(
+ net::HostPortPair(host, port), nullptr, std::move(client_ptr));
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- base::BindOnce(
- &PepperTCPSocketMessageFilter::DoConnect, this,
- context->MakeReplyMessageContext(), host, port,
- base::WrapRefCounted(storage_partition->GetURLRequestContext())));
+ base::BindOnce(&PepperTCPSocketMessageFilter::HostResolvingStarted, this,
+ context->MakeReplyMessageContext()));
return PP_OK_COMPLETIONPENDING;
}
@@ -348,9 +373,8 @@ int32_t PepperTCPSocketMessageFilter::OnMsgSSLHandshake(
const ppapi::host::ReplyMessageContext reply_context(
context->MakeReplyMessageContext());
int net_result = ssl_socket_->Connect(
- base::Bind(&PepperTCPSocketMessageFilter::OnSSLHandshakeCompleted,
- base::Unretained(this),
- reply_context));
+ base::BindOnce(&PepperTCPSocketMessageFilter::OnSSLHandshakeCompleted,
+ base::Unretained(this), reply_context));
if (net_result != net::ERR_IO_PENDING)
OnSSLHandshakeCompleted(reply_context, net_result);
return PP_OK_COMPLETIONPENDING;
@@ -376,20 +400,16 @@ int32_t PepperTCPSocketMessageFilter::OnMsgRead(
int net_result = net::ERR_FAILED;
if (socket_) {
DCHECK_EQ(state_.state(), TCPSocketState::CONNECTED);
- net_result =
- socket_->Read(read_buffer_.get(),
- bytes_to_read,
- base::Bind(&PepperTCPSocketMessageFilter::OnReadCompleted,
- base::Unretained(this),
- reply_context));
+ net_result = socket_->Read(
+ read_buffer_.get(), bytes_to_read,
+ base::BindOnce(&PepperTCPSocketMessageFilter::OnReadCompleted,
+ base::Unretained(this), reply_context));
} else if (ssl_socket_) {
DCHECK_EQ(state_.state(), TCPSocketState::SSL_CONNECTED);
net_result = ssl_socket_->Read(
- read_buffer_.get(),
- bytes_to_read,
- base::Bind(&PepperTCPSocketMessageFilter::OnReadCompleted,
- base::Unretained(this),
- reply_context));
+ read_buffer_.get(), bytes_to_read,
+ base::BindOnce(&PepperTCPSocketMessageFilter::OnReadCompleted,
+ base::Unretained(this), reply_context));
}
if (net_result != net::ERR_IO_PENDING)
OnReadCompleted(reply_context, net_result);
@@ -413,10 +433,10 @@ int32_t PepperTCPSocketMessageFilter::OnMsgWrite(
return PP_ERROR_BADARGUMENT;
}
- write_buffer_base_ = new net::IOBuffer(data_size);
+ write_buffer_base_ = base::MakeRefCounted<net::IOBuffer>(data_size);
memcpy(write_buffer_base_->data(), data.data(), data_size);
- write_buffer_ =
- new net::DrainableIOBuffer(write_buffer_base_.get(), data_size);
+ write_buffer_ = base::MakeRefCounted<net::DrainableIOBuffer>(
+ write_buffer_base_, data_size);
DoWrite(context->MakeReplyMessageContext());
return PP_OK_COMPLETIONPENDING;
}
@@ -463,11 +483,9 @@ int32_t PepperTCPSocketMessageFilter::OnMsgAccept(
ppapi::host::ReplyMessageContext reply_context(
context->MakeReplyMessageContext());
int net_result = socket_->Accept(
- &accepted_socket_,
- &accepted_address_,
+ &accepted_socket_, &accepted_address_,
base::Bind(&PepperTCPSocketMessageFilter::OnAcceptCompleted,
- base::Unretained(this),
- reply_context));
+ base::Unretained(this), reply_context));
if (net_result != net::ERR_IO_PENDING)
OnAcceptCompleted(reply_context, net_result);
return PP_OK_COMPLETIONPENDING;
@@ -621,27 +639,12 @@ void PepperTCPSocketMessageFilter::DoBind(
state_.DoTransition(TCPSocketState::BIND, false);
}
-void PepperTCPSocketMessageFilter::DoConnect(
- const ppapi::host::ReplyMessageContext& context,
- const std::string& host,
- uint16_t port,
- scoped_refptr<net::URLRequestContextGetter> url_request_context_getter) {
+void PepperTCPSocketMessageFilter::HostResolvingStarted(
+ const ppapi::host::ReplyMessageContext& context) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
if (!state_.IsValidTransition(TCPSocketState::CONNECT)) {
- SendConnectError(context, PP_ERROR_FAILED);
- return;
- }
-
- auto* url_request_context =
- url_request_context_getter->GetURLRequestContext();
- if (!url_request_context) {
- SendConnectError(context, PP_ERROR_FAILED);
- return;
- }
-
- net::HostResolver* host_resolver = url_request_context->host_resolver();
- if (!host_resolver) {
+ NOTREACHED() << "This shouldn't be reached since the renderer only tries "
+ << "to connect once.";
SendConnectError(context, PP_ERROR_FAILED);
return;
}
@@ -649,15 +652,7 @@ void PepperTCPSocketMessageFilter::DoConnect(
state_.SetPendingTransition(TCPSocketState::CONNECT);
address_index_ = 0;
address_list_.clear();
- net::HostResolver::RequestInfo request_info(net::HostPortPair(host, port));
-
- int net_result = host_resolver->Resolve(
- request_info, net::DEFAULT_PRIORITY, &address_list_,
- base::Bind(&PepperTCPSocketMessageFilter::OnResolveCompleted,
- base::Unretained(this), context),
- &request_, net::NetLogWithSource());
- if (net_result != net::ERR_IO_PENDING)
- OnResolveCompleted(context, net_result);
+ host_resolve_context_ = context;
}
void PepperTCPSocketMessageFilter::DoConnectWithNetAddress(
@@ -697,60 +692,22 @@ void PepperTCPSocketMessageFilter::DoWrite(
DCHECK(state_.IsConnected());
int net_result = net::ERR_FAILED;
- net::NetworkTrafficAnnotationTag traffic_annotation =
- net::DefineNetworkTrafficAnnotation("pepper_tcp_socket", R"(
- semantics {
- sender: "Pepper TCP Socket"
- description:
- "Pepper plugins use this API to send and receive data over the "
- "network using TCP connections. This inteface is used by Flash and "
- "PDF viewer, and Chrome Apps which use plugins to send/receive TCP "
- "traffic (require Chrome Apps TCP socket permission)."
- trigger:
- "A request from a Pepper plugin."
- data: "Any data that the plugin sends."
- destination: OTHER
- destination_other:
- "Data can be sent to any destination."
- }
- policy {
- cookies_allowed: NO
- setting:
- "These requests cannot be disabled, but will not happen if user "
- "does not use Flash, internal PDF Viewer, or Chrome Apps that use "
- "Pepper interface."
- chrome_policy {
- DefaultPluginsSetting {
- DefaultPluginsSetting: 2
- }
- }
- chrome_policy {
- AlwaysOpenPdfExternally {
- AlwaysOpenPdfExternally: true
- }
- }
- chrome_policy {
- ExtensionInstallBlacklist {
- ExtensionInstallBlacklist: {
- entries: '*'
- }
- }
- }
- })");
if (socket_) {
DCHECK_EQ(state_.state(), TCPSocketState::CONNECTED);
net_result = socket_->Write(
write_buffer_.get(), write_buffer_->BytesRemaining(),
- base::Bind(&PepperTCPSocketMessageFilter::OnWriteCompleted,
- base::Unretained(this), context),
- traffic_annotation);
+ base::BindOnce(&PepperTCPSocketMessageFilter::OnWriteCompleted,
+ base::Unretained(this), context),
+ static_cast<net::NetworkTrafficAnnotationTag>(
+ pepper_socket_utils::PepperTCPNetworkAnnotationTag()));
} else if (ssl_socket_) {
DCHECK_EQ(state_.state(), TCPSocketState::SSL_CONNECTED);
net_result = ssl_socket_->Write(
write_buffer_.get(), write_buffer_->BytesRemaining(),
- base::Bind(&PepperTCPSocketMessageFilter::OnWriteCompleted,
- base::Unretained(this), context),
- traffic_annotation);
+ base::BindOnce(&PepperTCPSocketMessageFilter::OnWriteCompleted,
+ base::Unretained(this), context),
+ static_cast<net::NetworkTrafficAnnotationTag>(
+ pepper_socket_utils::PepperTCPNetworkAnnotationTag()));
}
if (net_result != net::ERR_IO_PENDING)
OnWriteCompleted(context, net_result);
@@ -779,9 +736,14 @@ void PepperTCPSocketMessageFilter::DoListen(
}
void PepperTCPSocketMessageFilter::OnResolveCompleted(
- const ppapi::host::ReplyMessageContext& context,
- int net_result) {
+ int net_result,
+ const base::Optional<net::AddressList>& resolved_addresses) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!host_resolve_context_.is_valid())
+ return;
+
+ ppapi::host::ReplyMessageContext context = host_resolve_context_;
+ host_resolve_context_ = ppapi::host::ReplyMessageContext();
if (!state_.IsPending(TCPSocketState::CONNECT)) {
DCHECK(state_.state() == TCPSocketState::CLOSED);
@@ -795,6 +757,7 @@ void PepperTCPSocketMessageFilter::OnResolveCompleted(
return;
}
+ address_list_ = resolved_addresses.value();
StartConnect(context);
}
@@ -837,9 +800,8 @@ void PepperTCPSocketMessageFilter::StartConnect(
int net_result = socket_->Connect(
address_list_[address_index_],
- base::Bind(&PepperTCPSocketMessageFilter::OnConnectCompleted,
- base::Unretained(this),
- context));
+ base::BindOnce(&PepperTCPSocketMessageFilter::OnConnectCompleted,
+ base::Unretained(this), context));
if (net_result != net::ERR_IO_PENDING)
OnConnectCompleted(context, net_result);
}
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h b/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h
index fec0b7cbf0c..03648b64ef4 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h
@@ -19,15 +19,16 @@
#include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
#include "content/browser/renderer_host/pepper/ssl_context_helper.h"
#include "content/common/content_export.h"
+#include "mojo/public/cpp/bindings/binding.h"
#include "net/base/address_list.h"
#include "net/base/ip_endpoint.h"
-#include "net/dns/host_resolver.h"
#include "net/socket/tcp_socket.h"
#include "ppapi/c/pp_instance.h"
#include "ppapi/c/ppb_tcp_socket.h"
#include "ppapi/c/private/ppb_net_address_private.h"
#include "ppapi/host/resource_message_filter.h"
#include "ppapi/shared_impl/ppb_tcp_socket_shared.h"
+#include "services/network/public/mojom/network_context.mojom.h"
#if defined(OS_CHROMEOS)
#include "chromeos/network/firewall_hole.h"
@@ -38,7 +39,6 @@ namespace net {
class DrainableIOBuffer;
class IOBuffer;
class SSLClientSocket;
-class URLRequestContextGetter;
}
namespace ppapi {
@@ -56,7 +56,8 @@ class ContentBrowserPepperHostFactory;
class CONTENT_EXPORT PepperTCPSocketMessageFilter
: public ppapi::host::ResourceMessageFilter,
- public BrowserPpapiHostImpl::InstanceObserver {
+ public BrowserPpapiHostImpl::InstanceObserver,
+ public network::mojom::ResolveHostClient {
public:
PepperTCPSocketMessageFilter(ContentBrowserPepperHostFactory* factory,
BrowserPpapiHostImpl* host,
@@ -91,6 +92,11 @@ class CONTENT_EXPORT PepperTCPSocketMessageFilter
void OnThrottleStateChanged(bool is_throttled) override;
void OnHostDestroyed() override;
+ // network::mojom::ResolveHostClient overrides.
+ void OnComplete(
+ int result,
+ const base::Optional<net::AddressList>& resolved_addresses) override;
+
int32_t OnMsgBind(const ppapi::host::HostMessageContext* context,
const PP_NetAddress_Private& net_addr);
int32_t OnMsgConnect(const ppapi::host::HostMessageContext* context,
@@ -119,19 +125,16 @@ class CONTENT_EXPORT PepperTCPSocketMessageFilter
void DoBind(const ppapi::host::ReplyMessageContext& context,
const PP_NetAddress_Private& net_addr);
- void DoConnect(
- const ppapi::host::ReplyMessageContext& context,
- const std::string& host,
- uint16_t port,
- scoped_refptr<net::URLRequestContextGetter> url_request_context_getter);
+ void HostResolvingStarted(const ppapi::host::ReplyMessageContext& context);
void DoConnectWithNetAddress(const ppapi::host::ReplyMessageContext& context,
const PP_NetAddress_Private& net_addr);
void DoWrite(const ppapi::host::ReplyMessageContext& context);
void DoListen(const ppapi::host::ReplyMessageContext& context,
int32_t backlog);
- void OnResolveCompleted(const ppapi::host::ReplyMessageContext& context,
- int net_result);
+ void OnResolveCompleted(
+ int net_result,
+ const base::Optional<net::AddressList>& resolved_addresses);
void StartConnect(const ppapi::host::ReplyMessageContext& context);
void OnConnectCompleted(const ppapi::host::ReplyMessageContext& context,
@@ -198,6 +201,10 @@ class CONTENT_EXPORT PepperTCPSocketMessageFilter
int render_process_id_;
int render_frame_id_;
+ // A reference to |this| must always be taken while |binding_| is bound to
+ // ensure that if the error callback is called the object is alive.
+ mojo::Binding<network::mojom::ResolveHostClient> binding_;
+
// The following fields are used only on the IO thread.
// Non-owning ptr.
BrowserPpapiHostImpl* host_;
@@ -237,6 +244,7 @@ class CONTENT_EXPORT PepperTCPSocketMessageFilter
net::AddressList address_list_;
// Where we are in the above list.
size_t address_index_;
+ ppapi::host::ReplyMessageContext host_resolve_context_;
// Non-null unless an SSL connection is requested.
std::unique_ptr<net::TCPSocket> socket_;
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_host.cc b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_host.cc
index 036149f4af4..6f4b48ee188 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_host.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_host.cc
@@ -5,8 +5,8 @@
#include "content/browser/renderer_host/pepper/pepper_truetype_font_host.h"
#include "base/bind.h"
+#include "base/task/post_task.h"
#include "base/task_runner_util.h"
-#include "base/task_scheduler/post_task.h"
#include "content/browser/renderer_host/pepper/pepper_truetype_font.h"
#include "content/public/browser/browser_ppapi_host.h"
#include "ppapi/c/pp_errors.h"
@@ -32,7 +32,7 @@ PepperTrueTypeFontHost::PepperTrueTypeFontHost(
// Initialize the font on a TaskScheduler thread. This must complete before
// using |font_|.
task_runner_ = base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::BACKGROUND});
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
SerializedTrueTypeFontDesc* actual_desc =
new SerializedTrueTypeFontDesc(desc);
base::PostTaskAndReplyWithResult(
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc b/chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
index 141d0b840a2..7a19d458a19 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
@@ -13,15 +13,20 @@
#include "build/build_config.h"
#include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
#include "content/browser/renderer_host/pepper/pepper_socket_utils.h"
+#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/site_instance.h"
+#include "content/public/browser/storage_partition.h"
#include "content/public/common/process_type.h"
#include "content/public/common/socket_permission_request.h"
#include "ipc/ipc_message_macros.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/log/net_log_source.h"
-#include "net/socket/udp_socket.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/private/ppb_net_address_private.h"
#include "ppapi/host/dispatch_host_message.h"
@@ -33,6 +38,7 @@
#include "ppapi/proxy/udp_socket_resource_constants.h"
#include "ppapi/shared_impl/private/net_address_private_impl.h"
#include "ppapi/shared_impl/socket_option_data.h"
+#include "services/network/public/mojom/network_context.mojom.h"
#if defined(OS_CHROMEOS)
#include "chromeos/network/firewall_hole.h"
@@ -42,20 +48,23 @@ using ppapi::NetAddressPrivateImpl;
using ppapi::host::NetErrorToPepperError;
using ppapi::proxy::UDPSocketResourceConstants;
+namespace content {
+
namespace {
+const PepperUDPSocketMessageFilter::CreateUDPSocketCallback*
+ g_create_udp_socket_callback_for_testing = nullptr;
+
size_t g_num_udp_filter_instances = 0;
} // namespace
-namespace content {
-
PepperUDPSocketMessageFilter::PendingSend::PendingSend(
const net::IPAddress& address,
int port,
- const scoped_refptr<net::IOBufferWithSize>& buffer,
+ std::vector<uint8_t> data,
const ppapi::host::ReplyMessageContext& context)
- : address(address), port(port), buffer(buffer), context(context) {}
+ : address(address), port(port), data(std::move(data)), context(context) {}
PepperUDPSocketMessageFilter::PendingSend::PendingSend(
const PendingSend& other) = default;
@@ -80,7 +89,13 @@ PepperUDPSocketMessageFilter::PepperUDPSocketMessageFilter(
render_process_id_(0),
render_frame_id_(0),
is_potentially_secure_plugin_context_(
- host->IsPotentiallySecurePluginContext(instance)) {
+ host->IsPotentiallySecurePluginContext(instance)),
+ binding_(this)
+#if defined(OS_CHROMEOS)
+ ,
+ firewall_hole_weak_ptr_factory_(this)
+#endif // defined(OS_CHROMEOS)
+{
++g_num_udp_filter_instances;
DCHECK(host);
@@ -91,15 +106,35 @@ PepperUDPSocketMessageFilter::PepperUDPSocketMessageFilter(
}
PepperUDPSocketMessageFilter::~PepperUDPSocketMessageFilter() {
- Close();
+ DCHECK(closed_);
+ DCHECK(!socket_);
+ DCHECK(!binding_);
--g_num_udp_filter_instances;
}
+void PepperUDPSocketMessageFilter::SetCreateUDPSocketCallbackForTesting(
+ const CreateUDPSocketCallback* create_udp_socket_callback) {
+ DCHECK(!create_udp_socket_callback ||
+ !g_create_udp_socket_callback_for_testing);
+ g_create_udp_socket_callback_for_testing = create_udp_socket_callback;
+}
+
// static
size_t PepperUDPSocketMessageFilter::GetNumInstances() {
return g_num_udp_filter_instances;
}
+void PepperUDPSocketMessageFilter::OnFilterDestroyed() {
+ ResourceMessageFilter::OnFilterDestroyed();
+ // Need to close the socket on the UI thread. Calling Close() also ensures
+ // that future messages will be ignored, so the mojo pipes won't be
+ // re-created, so after Close() runs, |this| can be safely deleted on the IO
+ // thread.
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&PepperUDPSocketMessageFilter::Close, this));
+}
+
scoped_refptr<base::TaskRunner>
PepperUDPSocketMessageFilter::OverrideTaskRunnerForMessage(
const IPC::Message& message) {
@@ -107,7 +142,6 @@ PepperUDPSocketMessageFilter::OverrideTaskRunnerForMessage(
case PpapiHostMsg_UDPSocket_SetOption::ID:
case PpapiHostMsg_UDPSocket_Close::ID:
case PpapiHostMsg_UDPSocket_RecvSlotAvailable::ID:
- return BrowserThread::GetTaskRunnerForThread(BrowserThread::IO);
case PpapiHostMsg_UDPSocket_Bind::ID:
case PpapiHostMsg_UDPSocket_SendTo::ID:
case PpapiHostMsg_UDPSocket_JoinGroup::ID:
@@ -142,14 +176,14 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSetOption(
const ppapi::host::HostMessageContext* context,
PP_UDPSocket_Option name,
const ppapi::SocketOptionData& value) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (closed_)
return PP_ERROR_FAILED;
switch (name) {
case PP_UDPSOCKET_OPTION_ADDRESS_REUSE: {
- if (socket_.get()) {
+ if (socket_) {
// AllowReuseAddress is only effective before Bind().
// Note that this limitation originally comes from Windows, but
// PPAPI tries to provide platform independent APIs.
@@ -172,16 +206,20 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSetOption(
if (!value.GetBool(&boolean_value))
return PP_ERROR_BADARGUMENT;
- // If the socket is already bound, proxy the value to UDPSocket.
- if (socket_.get())
- return NetErrorToPepperError(socket_->SetBroadcast(boolean_value));
+ if (socket_) {
+ socket_->SetBroadcast(
+ boolean_value,
+ CreateCompletionCallback<PpapiPluginMsg_UDPSocket_SetOptionReply>(
+ context));
+ return PP_OK_COMPLETIONPENDING;
+ }
- // UDPSocket instance is not yet created, so remember the value here.
if (boolean_value) {
socket_options_ |= SOCKET_OPTION_BROADCAST;
} else {
socket_options_ &= ~SOCKET_OPTION_BROADCAST;
}
+
return PP_OK;
}
case PP_UDPSOCKET_OPTION_SEND_BUFFER_SIZE: {
@@ -190,15 +228,18 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSetOption(
integer_value > UDPSocketResourceConstants::kMaxSendBufferSize)
return PP_ERROR_BADARGUMENT;
- // If the socket is already bound, proxy the value to UDPSocket.
- if (socket_.get()) {
- return NetErrorToPepperError(
- socket_->SetSendBufferSize(integer_value));
- }
-
- // UDPSocket instance is not yet created, so remember the value here.
socket_options_ |= SOCKET_OPTION_SNDBUF_SIZE;
sndbuf_size_ = integer_value;
+
+ // If the socket is already initialized, proxy the value to UDPSocket.
+ if (socket_) {
+ socket_->SetSendBufferSize(
+ integer_value,
+ CreateCompletionCallback<PpapiPluginMsg_UDPSocket_SetOptionReply>(
+ context));
+ return PP_OK_COMPLETIONPENDING;
+ }
+
return PP_OK;
}
case PP_UDPSOCKET_OPTION_RECV_BUFFER_SIZE: {
@@ -207,15 +248,18 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSetOption(
integer_value > UDPSocketResourceConstants::kMaxReceiveBufferSize)
return PP_ERROR_BADARGUMENT;
- // If the socket is already bound, proxy the value to UDPSocket.
- if (socket_.get()) {
- return NetErrorToPepperError(
- socket_->SetReceiveBufferSize(integer_value));
- }
-
- // UDPSocket instance is not yet created, so remember the value here.
socket_options_ |= SOCKET_OPTION_RCVBUF_SIZE;
rcvbuf_size_ = integer_value;
+
+ // If the socket is already initialized, proxy the value to UDPSocket.
+ if (socket_) {
+ socket_->SetReceiveBufferSize(
+ integer_value,
+ CreateCompletionCallback<PpapiPluginMsg_UDPSocket_SetOptionReply>(
+ context));
+ return PP_OK_COMPLETIONPENDING;
+ }
+
return PP_OK;
}
case PP_UDPSOCKET_OPTION_MULTICAST_LOOP: {
@@ -223,21 +267,22 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSetOption(
if (!value.GetBool(&boolean_value))
return PP_ERROR_BADARGUMENT;
- // If the socket is already bound, proxy the value to UDPSocket.
+ if (boolean_value) {
+ socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP;
+ } else {
+ socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP;
+ }
+
+ // If the socket is already initialized, either fail if permissions
+ // disallow multicast, or lie and claim it succeeded, to maintain previous
+ // behavior.
if (socket_) {
if (can_use_multicast_ != PP_OK)
return can_use_multicast_;
- return NetErrorToPepperError(
- socket_->SetMulticastLoopbackMode(boolean_value));
+ return PP_OK;
}
- // UDPSocket instance is not yet created, so remember the value here.
- if (boolean_value) {
- socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP;
- } else {
- socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP;
- }
return PP_OK;
}
case PP_UDPSOCKET_OPTION_MULTICAST_TTL: {
@@ -246,18 +291,20 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSetOption(
integer_value < 0 || integer_value > 255)
return PP_ERROR_BADARGUMENT;
- // If the socket is already bound, proxy the value to UDPSocket.
+ // UDPSocket instance is not yet created, so remember the value here.
+ socket_options_ |= SOCKET_OPTION_MULTICAST_TTL;
+ multicast_ttl_ = integer_value;
+
+ // If the socket is already initialized, either fail if permissions
+ // disallow multicast, or lie and claim it succeeded, to maintain previous
+ // behavior.
if (socket_) {
if (can_use_multicast_ != PP_OK)
return can_use_multicast_;
- return NetErrorToPepperError(
- socket_->SetMulticastTimeToLive(integer_value));
+ return PP_OK;
}
- // UDPSocket instance is not yet created, so remember the value here.
- socket_options_ |= SOCKET_OPTION_MULTICAST_TTL;
- multicast_ttl_ = integer_value;
return PP_OK;
}
default: {
@@ -273,6 +320,9 @@ int32_t PepperUDPSocketMessageFilter::OnMsgBind(
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(context);
+ if (closed_ || socket_)
+ return PP_ERROR_FAILED;
+
// Check for permissions to use multicast APIS. This check must be done while
// on the UI thread, so we cache the value here to be used later on.
PP_NetAddress_Private any_addr;
@@ -290,10 +340,83 @@ int32_t PepperUDPSocketMessageFilter::OnMsgBind(
return PP_ERROR_NOACCESS;
}
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(&PepperUDPSocketMessageFilter::DoBind, this,
- context->MakeReplyMessageContext(), addr));
+ net::IPAddressBytes address;
+ uint16_t port;
+ if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port))
+ return PP_ERROR_ADDRESS_INVALID;
+ net::IPEndPoint end_point(net::IPAddress(address), port);
+
+ network::mojom::UDPSocketOptionsPtr udp_socket_options =
+ network::mojom::UDPSocketOptions::New();
+ udp_socket_options->allow_address_reuse =
+ !!(socket_options_ & SOCKET_OPTION_ADDRESS_REUSE);
+ udp_socket_options->allow_broadcast =
+ !!(socket_options_ & SOCKET_OPTION_BROADCAST);
+ if (socket_options_ & SOCKET_OPTION_SNDBUF_SIZE)
+ udp_socket_options->send_buffer_size = sndbuf_size_;
+ if (socket_options_ & SOCKET_OPTION_RCVBUF_SIZE)
+ udp_socket_options->receive_buffer_size = rcvbuf_size_;
+
+ if (socket_options_ & SOCKET_OPTION_MULTICAST_LOOP) {
+ if (can_use_multicast_ != PP_OK) {
+ // TODO(mmenke): The above line implies |can_use_multicast_| is a PP
+ // error code, but the next line implies it is a net error code. Fix that.
+ return NetErrorToPepperError(can_use_multicast_);
+ }
+ // TODO(mmenke): This doesn't seem to be doing anything - this is the
+ // default behavior.
+ udp_socket_options->multicast_loopback_mode = true;
+ }
+ if (socket_options_ & SOCKET_OPTION_MULTICAST_TTL) {
+ if (can_use_multicast_ != PP_OK) {
+ // TODO(mmenke): The above line implies |can_use_multicast_| is a PP
+ // error code, but the next line implies it is a net error code. Fix that.
+ return NetErrorToPepperError(can_use_multicast_);
+ }
+
+ udp_socket_options->multicast_time_to_live = multicast_ttl_;
+ }
+
+ RenderFrameHost* render_frame_host =
+ RenderFrameHost::FromID(render_process_id_, render_frame_id_);
+ // If the RenderFrameHost has been closed, just fail the request.
+ if (!render_frame_host)
+ return PP_ERROR_NOACCESS;
+
+ network::mojom::UDPSocketReceiverPtr udp_socket_receiver;
+ // Avoid binding the receiver until the socket has been successfully Bound (in
+ // a socket sense), to avoid providing read data to the caller until it has
+ // been told that the socket was bound.
+ network::mojom::UDPSocketReceiverRequest receiver_request =
+ mojo::MakeRequest(&udp_socket_receiver);
+
+ SiteInstance* site_instance = render_frame_host->GetSiteInstance();
+ network::mojom::NetworkContext* network_context =
+ BrowserContext::GetStoragePartition(site_instance->GetBrowserContext(),
+ site_instance)
+ ->GetNetworkContext();
+ if (g_create_udp_socket_callback_for_testing) {
+ g_create_udp_socket_callback_for_testing->Run(
+ network_context, mojo::MakeRequest(&socket_),
+ std::move(udp_socket_receiver));
+ } else {
+ network_context->CreateUDPSocket(mojo::MakeRequest(&socket_),
+ std::move(udp_socket_receiver));
+ }
+
+ ppapi::host::ReplyMessageContext reply_context =
+ context->MakeReplyMessageContext();
+ // Watch the socket for errors during the the Bind call.
+ socket_.set_connection_error_handler(
+ base::BindOnce(&PepperUDPSocketMessageFilter::SendBindError,
+ base::Unretained(this), reply_context, PP_ERROR_FAILED));
+
+ // This is the actual socket Bind call (i.e., not a Mojo Bind call).
+ socket_->Bind(end_point, std::move(udp_socket_options),
+ base::BindOnce(&PepperUDPSocketMessageFilter::DoBindCallback,
+ base::Unretained(this),
+ std::move(receiver_request), reply_context));
+
return PP_OK_COMPLETIONPENDING;
}
@@ -304,6 +427,11 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSendTo(
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(context);
+ // Check |binding_| instead of |socket_| because |binding_| is only set
+ // after the Bind() call completes.
+ if (closed_ || !binding_)
+ return PP_ERROR_FAILED;
+
SocketPermissionRequest request =
pepper_socket_utils::CreateSocketPermissionRequest(
SocketPermissionRequest::UDP_SEND_TO, addr);
@@ -315,32 +443,61 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSendTo(
return PP_ERROR_NOACCESS;
}
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(&PepperUDPSocketMessageFilter::DoSendTo, this,
- context->MakeReplyMessageContext(), data, addr));
+ // Make sure a malicious plugin can't queue up an unlimited number of buffers.
+ size_t num_pending_sends = pending_sends_.size();
+ if (num_pending_sends == UDPSocketResourceConstants::kPluginSendBufferSlots) {
+ return PP_ERROR_FAILED;
+ }
+
+ size_t num_bytes = data.size();
+ if (num_bytes == 0 ||
+ num_bytes >
+ static_cast<size_t>(UDPSocketResourceConstants::kMaxWriteSize)) {
+ // Size of |data| is checked on the plugin side.
+ NOTREACHED();
+ return PP_ERROR_BADARGUMENT;
+ }
+
+ net::IPAddressBytes address;
+ uint16_t port;
+ if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
+ return PP_ERROR_ADDRESS_INVALID;
+ }
+
+ const uint8_t* data_ptr = reinterpret_cast<const uint8_t*>(data.data());
+ std::vector<uint8_t> data_vector(data_ptr, data_ptr + num_bytes);
+
+ pending_sends_.push(PendingSend(net::IPAddress(address), port,
+ std::move(data_vector),
+ context->MakeReplyMessageContext()));
+ // Can only start the send if there isn't another send pending.
+ if (num_pending_sends == 0)
+ StartPendingSend();
return PP_OK_COMPLETIONPENDING;
}
int32_t PepperUDPSocketMessageFilter::OnMsgClose(
const ppapi::host::HostMessageContext* context) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
Close();
return PP_OK;
}
int32_t PepperUDPSocketMessageFilter::OnMsgRecvSlotAvailable(
const ppapi::host::HostMessageContext* context) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (remaining_recv_slots_ <
UDPSocketResourceConstants::kPluginReceiveBufferSlots) {
- remaining_recv_slots_++;
- }
+ // If the pipe was closed, but the consumer has not yet closed the UDP
+ // socket, keep the read buffer filled with errors.
+ if (!binding_) {
+ PepperUDPSocketMessageFilter::SendRecvFromError(PP_ERROR_FAILED);
+ return PP_OK;
+ }
- if (!recvfrom_buffer_.get() && !closed_ && socket_.get()) {
- DCHECK_EQ(1u, remaining_recv_slots_);
- DoRecvFrom();
+ remaining_recv_slots_++;
+ socket_->ReceiveMore(1);
}
return PP_OK;
@@ -364,7 +521,11 @@ int32_t PepperUDPSocketMessageFilter::OnMsgJoinGroup(
if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &group, &port))
return PP_ERROR_ADDRESS_INVALID;
- return NetErrorToPepperError(socket_->JoinGroup(net::IPAddress(group)));
+ socket_->JoinGroup(
+ net::IPAddress(group),
+ CreateCompletionCallback<PpapiPluginMsg_UDPSocket_SetOptionReply>(
+ context));
+ return PP_OK_COMPLETIONPENDING;
}
int32_t PepperUDPSocketMessageFilter::OnMsgLeaveGroup(
@@ -385,309 +546,155 @@ int32_t PepperUDPSocketMessageFilter::OnMsgLeaveGroup(
if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &group, &port))
return PP_ERROR_ADDRESS_INVALID;
- return NetErrorToPepperError(socket_->LeaveGroup(net::IPAddress(group)));
+ socket_->LeaveGroup(
+ net::IPAddress(group),
+ CreateCompletionCallback<PpapiPluginMsg_UDPSocket_LeaveGroupReply>(
+ context));
+ return PP_OK_COMPLETIONPENDING;
}
-void PepperUDPSocketMessageFilter::DoBind(
+void PepperUDPSocketMessageFilter::DoBindCallback(
+ network::mojom::UDPSocketReceiverRequest receiver_request,
const ppapi::host::ReplyMessageContext& context,
- const PP_NetAddress_Private& addr) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ int result,
+ const base::Optional<net::IPEndPoint>& local_addr_out) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (closed_ || socket_.get()) {
- SendBindError(context, PP_ERROR_FAILED);
+ if (result != net::OK) {
+ SendBindError(context, NetErrorToPepperError(result));
return;
}
- auto socket = std::make_unique<net::UDPSocket>(
- net::DatagramSocket::DEFAULT_BIND, nullptr, net::NetLogSource());
-
- net::IPAddressBytes address;
- uint16_t port;
- if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
- SendBindError(context, PP_ERROR_ADDRESS_INVALID);
- return;
- }
- net::IPEndPoint end_point(net::IPAddress(address), port);
- {
- int net_result = socket->Open(end_point.GetFamily());
- if (net_result != net::OK) {
- SendBindError(context, NetErrorToPepperError(net_result));
- return;
- }
- }
-
- if (socket_options_ & SOCKET_OPTION_ADDRESS_REUSE) {
- int net_result = socket->AllowAddressReuse();
- if (net_result != net::OK) {
- SendBindError(context, NetErrorToPepperError(net_result));
- return;
- }
- }
- if (socket_options_ & SOCKET_OPTION_BROADCAST) {
- int net_result = socket->SetBroadcast(true);
- if (net_result != net::OK) {
- SendBindError(context, NetErrorToPepperError(net_result));
- return;
- }
- }
- if (socket_options_ & SOCKET_OPTION_SNDBUF_SIZE) {
- int net_result = socket->SetSendBufferSize(sndbuf_size_);
- if (net_result != net::OK) {
- SendBindError(context, NetErrorToPepperError(net_result));
- return;
- }
- }
- if (socket_options_ & SOCKET_OPTION_RCVBUF_SIZE) {
- int net_result = socket->SetReceiveBufferSize(rcvbuf_size_);
- if (net_result != net::OK) {
- SendBindError(context, NetErrorToPepperError(net_result));
- return;
- }
- }
- if (socket_options_ & SOCKET_OPTION_MULTICAST_LOOP) {
- if (can_use_multicast_ != PP_OK) {
- SendBindError(context, NetErrorToPepperError(can_use_multicast_));
- return;
- }
-
- int net_result = socket->SetMulticastLoopbackMode(true);
- if (net_result != net::OK) {
- SendBindError(context, NetErrorToPepperError(net_result));
- return;
- }
- }
- if (socket_options_ & SOCKET_OPTION_MULTICAST_TTL) {
- if (can_use_multicast_ != PP_OK) {
- SendBindError(context, NetErrorToPepperError(can_use_multicast_));
- return;
- }
-
- int net_result = socket->SetMulticastTimeToLive(multicast_ttl_);
- if (net_result != net::OK) {
- SendBindError(context, NetErrorToPepperError(net_result));
- return;
- }
- }
-
- {
- int net_result = socket->Bind(end_point);
- if (net_result != net::OK) {
- SendBindError(context, NetErrorToPepperError(net_result));
- return;
- }
- }
-
- net::IPEndPoint bound_address;
- {
- int net_result = socket->GetLocalAddress(&bound_address);
- if (net_result != net::OK) {
- SendBindError(context, NetErrorToPepperError(net_result));
- return;
- }
- }
-
PP_NetAddress_Private net_address = NetAddressPrivateImpl::kInvalidNetAddress;
- if (!NetAddressPrivateImpl::IPEndPointToNetAddress(
- bound_address.address().bytes(), bound_address.port(),
- &net_address)) {
+ if (!local_addr_out || !NetAddressPrivateImpl::IPEndPointToNetAddress(
+ local_addr_out->address().bytes(),
+ local_addr_out->port(), &net_address)) {
SendBindError(context, PP_ERROR_ADDRESS_INVALID);
return;
}
#if defined(OS_CHROMEOS)
- OpenFirewallHole(
- bound_address,
- base::Bind(&PepperUDPSocketMessageFilter::OnBindComplete, this,
- base::Passed(&socket), context, net_address));
-#else
- OnBindComplete(std::move(socket), context, net_address);
-#endif
+ pepper_socket_utils::OpenUDPFirewallHole(
+ *local_addr_out,
+ base::BindRepeating(&PepperUDPSocketMessageFilter::OnFirewallHoleOpened,
+ firewall_hole_weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(std::move(receiver_request)), context,
+ net_address));
+#else // !defined(OS_CHROMEOS)
+ OnBindComplete(std::move(receiver_request), context, net_address);
+#endif // !defined(OS_CHROMEOS)
}
void PepperUDPSocketMessageFilter::OnBindComplete(
- std::unique_ptr<net::UDPSocket> socket,
+ network::mojom::UDPSocketReceiverRequest receiver_request,
const ppapi::host::ReplyMessageContext& context,
const PP_NetAddress_Private& net_address) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- socket_.swap(socket);
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(socket_);
+
SendBindReply(context, PP_OK, net_address);
- DoRecvFrom();
+ binding_.Bind(std::move(receiver_request));
+ binding_.set_connection_error_handler(base::BindOnce(
+ &PepperUDPSocketMessageFilter::PipeClosed, base::Unretained(this)));
+ socket_.set_connection_error_handler(base::BindOnce(
+ &PepperUDPSocketMessageFilter::PipeClosed, base::Unretained(this)));
+ socket_->ReceiveMore(UDPSocketResourceConstants::kPluginReceiveBufferSlots);
}
#if defined(OS_CHROMEOS)
-void PepperUDPSocketMessageFilter::OpenFirewallHole(
- const net::IPEndPoint& local_address,
- base::Closure bind_complete) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- pepper_socket_utils::FirewallHoleOpenCallback callback = base::Bind(
- &PepperUDPSocketMessageFilter::OnFirewallHoleOpened, this, bind_complete);
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::BindOnce(&pepper_socket_utils::OpenUDPFirewallHole, local_address,
- callback));
-}
-
void PepperUDPSocketMessageFilter::OnFirewallHoleOpened(
- base::Closure bind_complete,
+ network::mojom::UDPSocketReceiverRequest receiver_request,
+ const ppapi::host::ReplyMessageContext& context,
+ const PP_NetAddress_Private& net_address,
std::unique_ptr<chromeos::FirewallHole> hole) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
LOG_IF(WARNING, !hole.get()) << "Firewall hole could not be opened.";
firewall_hole_.reset(hole.release());
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, bind_complete);
+ OnBindComplete(std::move(receiver_request), context, net_address);
}
#endif // defined(OS_CHROMEOS)
-void PepperUDPSocketMessageFilter::DoRecvFrom() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(!closed_);
- DCHECK(socket_.get());
- DCHECK(!recvfrom_buffer_.get());
- DCHECK_GT(remaining_recv_slots_, 0u);
-
- recvfrom_buffer_ =
- new net::IOBuffer(UDPSocketResourceConstants::kMaxReadSize);
-
- // Use base::Unretained(this), so that the lifespan of this object doesn't
- // have to last until the callback is called.
- // It is safe to do so because |socket_| is owned by this object. If this
- // object gets destroyed (and so does |socket_|), the callback won't be
- // called.
- int net_result = socket_->RecvFrom(
- recvfrom_buffer_.get(), UDPSocketResourceConstants::kMaxReadSize,
- &recvfrom_address_,
- base::Bind(&PepperUDPSocketMessageFilter::OnRecvFromCompleted,
- base::Unretained(this)));
- if (net_result != net::ERR_IO_PENDING)
- OnRecvFromCompleted(net_result);
-}
-
-void PepperUDPSocketMessageFilter::DoSendTo(
- const ppapi::host::ReplyMessageContext& context,
- const std::string& data,
- const PP_NetAddress_Private& addr) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(socket_.get());
-
- if (closed_ || !socket_.get()) {
- SendSendToError(context, PP_ERROR_FAILED);
- return;
- }
-
- size_t num_bytes = data.size();
- if (num_bytes == 0 ||
- num_bytes >
- static_cast<size_t>(UDPSocketResourceConstants::kMaxWriteSize)) {
- // Size of |data| is checked on the plugin side.
- NOTREACHED();
- SendSendToError(context, PP_ERROR_BADARGUMENT);
- return;
- }
-
- net::IPAddressBytes address;
- uint16_t port;
- if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
- SendSendToError(context, PP_ERROR_ADDRESS_INVALID);
- return;
- }
-
- scoped_refptr<net::IOBufferWithSize> buffer(
- new net::IOBufferWithSize(num_bytes));
- memcpy(buffer->data(), data.data(), num_bytes);
-
- // Make sure a malicious plugin can't queue up an unlimited number of buffers.
- size_t num_pending_sends = pending_sends_.size();
- if (num_pending_sends == UDPSocketResourceConstants::kPluginSendBufferSlots) {
- SendSendToError(context, PP_ERROR_FAILED);
- return;
- }
-
- pending_sends_.push(
- PendingSend(net::IPAddress(address), port, buffer, context));
- // If there are other sends pending, we can't start yet.
- if (num_pending_sends)
- return;
- int net_result = StartPendingSend();
- if (net_result != net::ERR_IO_PENDING)
- FinishPendingSend(net_result);
-}
-
-int PepperUDPSocketMessageFilter::StartPendingSend() {
+void PepperUDPSocketMessageFilter::StartPendingSend() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!pending_sends_.empty());
+ DCHECK(socket_);
+
const PendingSend& pending_send = pending_sends_.front();
// See OnMsgRecvFrom() for the reason why we use base::Unretained(this)
// when calling |socket_| methods.
- int net_result = socket_->SendTo(
- pending_send.buffer.get(),
- pending_send.buffer->size(),
+ socket_->SendTo(
net::IPEndPoint(pending_send.address, pending_send.port),
- base::Bind(&PepperUDPSocketMessageFilter::OnSendToCompleted,
- base::Unretained(this)));
- return net_result;
+ pending_send.data, pepper_socket_utils::PepperUDPNetworkAnnotationTag(),
+ base::BindOnce(&PepperUDPSocketMessageFilter::OnSendToCompleted,
+ base::Unretained(this)));
}
void PepperUDPSocketMessageFilter::Close() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (socket_.get() && !closed_)
- socket_->Close();
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ socket_.reset();
+ binding_.Close();
closed_ = true;
}
-void PepperUDPSocketMessageFilter::OnRecvFromCompleted(int net_result) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(recvfrom_buffer_.get());
+void PepperUDPSocketMessageFilter::OnReceived(
+ int result,
+ const base::Optional<net::IPEndPoint>& src_addr,
+ base::Optional<base::span<const uint8_t>> data) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(!closed_);
- int32_t pp_result = NetErrorToPepperError(net_result);
+ int32_t pp_result = NetErrorToPepperError(result);
// Convert IPEndPoint we get back from RecvFrom to a PP_NetAddress_Private
// to send back.
PP_NetAddress_Private addr = NetAddressPrivateImpl::kInvalidNetAddress;
- if (pp_result >= 0 &&
- !NetAddressPrivateImpl::IPEndPointToNetAddress(
- recvfrom_address_.address().bytes(), recvfrom_address_.port(),
- &addr)) {
+ if (pp_result == PP_OK &&
+ (!src_addr ||
+ !NetAddressPrivateImpl::IPEndPointToNetAddress(
+ src_addr->address().bytes(), src_addr->port(), &addr))) {
pp_result = PP_ERROR_ADDRESS_INVALID;
}
- if (pp_result >= 0) {
- SendRecvFromResult(PP_OK, std::string(recvfrom_buffer_->data(), pp_result),
- addr);
+ if (pp_result == PP_OK) {
+ std::string data_string;
+ if (data) {
+ data_string = std::string(reinterpret_cast<const char*>(data->data()),
+ data->size());
+ }
+ SendRecvFromResult(PP_OK, data_string, addr);
} else {
SendRecvFromError(pp_result);
}
- recvfrom_buffer_ = nullptr;
-
- DCHECK_GT(remaining_recv_slots_, 0u);
- remaining_recv_slots_--;
-
- if (remaining_recv_slots_ > 0 && !closed_ && socket_.get())
- DoRecvFrom();
+ // This should always be the case, but best to protect against a broken /
+ // taken over network service.
+ if (remaining_recv_slots_ > 0)
+ remaining_recv_slots_--;
}
void PepperUDPSocketMessageFilter::OnSendToCompleted(int net_result) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
FinishPendingSend(net_result);
- // Start pending sends until none are left or a send doesn't complete.
- while (!pending_sends_.empty()) {
- net_result = StartPendingSend();
- if (net_result == net::ERR_IO_PENDING)
- break;
- FinishPendingSend(net_result);
- }
+ if (!pending_sends_.empty())
+ StartPendingSend();
}
void PepperUDPSocketMessageFilter::FinishPendingSend(int net_result) {
DCHECK(!pending_sends_.empty());
const PendingSend& pending_send = pending_sends_.front();
int32_t pp_result = NetErrorToPepperError(net_result);
- if (pp_result < 0)
+ if (pp_result < 0) {
SendSendToError(pending_send.context, pp_result);
- else
- SendSendToReply(pending_send.context, PP_OK, pp_result);
+ } else {
+ // The cast should be safe because of the
+ // UDPSocketResourceConstants::kMaxSendBufferSize before enqueuing the send.
+ SendSendToReply(pending_send.context, PP_OK,
+ static_cast<int>(pending_send.data.size()));
+ }
pending_sends_.pop();
}
@@ -708,6 +715,19 @@ void PepperUDPSocketMessageFilter::SendRecvFromResult(
int32_t result,
const std::string& data,
const PP_NetAddress_Private& addr) {
+ // Unlike SendReply, which is safe to call on any thread, SendUnsolicitedReply
+ // calls are only safe to make on the IO thread.
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(
+ &PepperUDPSocketMessageFilter::SendRecvFromResultOnIOThread, this,
+ result, data, addr));
+}
+
+void PepperUDPSocketMessageFilter::SendRecvFromResultOnIOThread(
+ int32_t result,
+ const std::string& data,
+ const PP_NetAddress_Private& addr) {
if (resource_host()) {
resource_host()->host()->SendUnsolicitedReply(
resource_host()->pp_resource(),
@@ -727,6 +747,12 @@ void PepperUDPSocketMessageFilter::SendSendToReply(
void PepperUDPSocketMessageFilter::SendBindError(
const ppapi::host::ReplyMessageContext& context,
int32_t result) {
+ socket_.reset();
+#if defined(OS_CHROMEOS)
+ // In the unlikely case that this is due to a Mojo error while trying to open
+ // a hole in the firewall on ChromeOS, abandon opening a hole in the firewall.
+ firewall_hole_weak_ptr_factory_.InvalidateWeakPtrs();
+#endif // !defined(OS_CHROMEOS)
SendBindReply(context, result, NetAddressPrivateImpl::kInvalidNetAddress);
}
@@ -742,6 +768,19 @@ void PepperUDPSocketMessageFilter::SendSendToError(
SendSendToReply(context, result, 0);
}
+void PepperUDPSocketMessageFilter::PipeClosed() {
+ Close();
+
+ while (!pending_sends_.empty())
+ FinishPendingSend(PP_ERROR_FAILED);
+
+ // Any reads should fail, after a pipe error.
+ while (remaining_recv_slots_ > 0) {
+ --remaining_recv_slots_;
+ SendRecvFromError(PP_ERROR_FAILED);
+ }
+}
+
int32_t PepperUDPSocketMessageFilter::CanUseMulticastAPI(
const PP_NetAddress_Private& addr) {
// Check for plugin permissions.
@@ -759,4 +798,29 @@ int32_t PepperUDPSocketMessageFilter::CanUseMulticastAPI(
return PP_OK;
}
+template <class ReturnMessage>
+base::OnceCallback<void(int result)>
+PepperUDPSocketMessageFilter::CreateCompletionCallback(
+ const ppapi::host::HostMessageContext* context) {
+ std::unique_ptr<int> result = std::make_unique<int>(net::ERR_FAILED);
+ int* result_ptr = result.get();
+ base::ScopedClosureRunner closure_runner(
+ base::BindOnce(&PepperUDPSocketMessageFilter::ReturnResult<ReturnMessage>,
+ base::Unretained(this), context->MakeReplyMessageContext(),
+ base::Passed(std::move(result))));
+ return base::BindOnce(
+ [](base::ScopedClosureRunner closure_runner, int* result_ptr,
+ int net_result) { *result_ptr = net_result; },
+ std::move(closure_runner), result_ptr);
+}
+
+template <class ReturnMessage>
+void PepperUDPSocketMessageFilter::ReturnResult(
+ const ppapi::host::ReplyMessageContext& context,
+ std::unique_ptr<int> result) {
+ ppapi::host::ReplyMessageContext reply_context(context);
+ reply_context.params.set_result(NetErrorToPepperError(*result));
+ SendReply(reply_context, ReturnMessage());
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h b/chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h
index 37121831a0d..1e43afe7675 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h
@@ -6,26 +6,29 @@
#define CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_UDP_SOCKET_MESSAGE_FILTER_H_
#include <stddef.h>
+#include <stdint.h>
#include <memory>
#include <string>
+#include <vector>
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/containers/queue.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "build/build_config.h"
#include "content/common/content_export.h"
#include "content/public/common/process_type.h"
-#include "net/base/completion_callback.h"
+#include "mojo/public/cpp/bindings/binding.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
-#include "net/socket/udp_socket.h"
#include "ppapi/c/pp_instance.h"
#include "ppapi/c/pp_stdint.h"
#include "ppapi/c/ppb_udp_socket.h"
#include "ppapi/host/resource_message_filter.h"
+#include "services/network/public/mojom/udp_socket.mojom.h"
struct PP_NetAddress_Private;
@@ -34,11 +37,6 @@ struct PP_NetAddress_Private;
#include "content/public/browser/browser_thread.h"
#endif // defined(OS_CHROMEOS)
-namespace net {
-class IOBuffer;
-class IOBufferWithSize;
-}
-
namespace ppapi {
class SocketOptionData;
@@ -48,17 +46,32 @@ struct ReplyMessageContext;
}
}
+namespace network {
+namespace mojom {
+class NetworkContext;
+}
+} // namespace network
+
namespace content {
class BrowserPpapiHostImpl;
class CONTENT_EXPORT PepperUDPSocketMessageFilter
- : public ppapi::host::ResourceMessageFilter {
+ : public ppapi::host::ResourceMessageFilter,
+ public network::mojom::UDPSocketReceiver {
public:
PepperUDPSocketMessageFilter(BrowserPpapiHostImpl* host,
PP_Instance instance,
bool private_api);
+ using CreateUDPSocketCallback = base::RepeatingCallback<void(
+ network::mojom::NetworkContext* network_context,
+ network::mojom::UDPSocketRequest socket_request,
+ network::mojom::UDPSocketReceiverPtr socket_receiver)>;
+
+ static void SetCreateUDPSocketCallbackForTesting(
+ const CreateUDPSocketCallback* create_udp_socket_callback);
+
static size_t GetNumInstances();
protected:
@@ -77,18 +90,19 @@ class CONTENT_EXPORT PepperUDPSocketMessageFilter
struct PendingSend {
PendingSend(const net::IPAddress& address,
int port,
- const scoped_refptr<net::IOBufferWithSize>& buffer,
+ std::vector<uint8_t> data,
const ppapi::host::ReplyMessageContext& context);
PendingSend(const PendingSend& other);
~PendingSend();
net::IPAddress address;
int port;
- scoped_refptr<net::IOBufferWithSize> buffer;
+ std::vector<uint8_t> data;
ppapi::host::ReplyMessageContext context;
};
// ppapi::host::ResourceMessageFilter overrides.
+ void OnFilterDestroyed() override;
scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
const IPC::Message& message) override;
int32_t OnResourceMessageReceived(
@@ -111,25 +125,28 @@ class CONTENT_EXPORT PepperUDPSocketMessageFilter
int32_t OnMsgLeaveGroup(const ppapi::host::HostMessageContext* context,
const PP_NetAddress_Private& addr);
- void DoBind(const ppapi::host::ReplyMessageContext& context,
- const PP_NetAddress_Private& addr);
- void OnBindComplete(std::unique_ptr<net::UDPSocket> socket,
+ void DoBindCallback(network::mojom::UDPSocketReceiverRequest receiver_request,
+ const ppapi::host::ReplyMessageContext& context,
+ int result,
+ const base::Optional<net::IPEndPoint>& local_addr_out);
+ void OnBindComplete(network::mojom::UDPSocketReceiverRequest receiver_request,
const ppapi::host::ReplyMessageContext& context,
const PP_NetAddress_Private& net_address);
#if defined(OS_CHROMEOS)
- void OpenFirewallHole(const net::IPEndPoint& local_address,
- base::Closure bind_complete);
- void OnFirewallHoleOpened(base::Closure bind_complete,
- std::unique_ptr<chromeos::FirewallHole> hole);
+ void OnFirewallHoleOpened(
+ network::mojom::UDPSocketReceiverRequest receiver_request,
+ const ppapi::host::ReplyMessageContext& context,
+ const PP_NetAddress_Private& net_address,
+ std::unique_ptr<chromeos::FirewallHole> hole);
#endif // defined(OS_CHROMEOS)
- void DoRecvFrom();
- void DoSendTo(const ppapi::host::ReplyMessageContext& context,
- const std::string& data,
- const PP_NetAddress_Private& addr);
- int StartPendingSend();
+ void StartPendingSend();
void Close();
- void OnRecvFromCompleted(int net_result);
+ // network::mojom::UDPSocketReceiver override:
+ void OnReceived(int result,
+ const base::Optional<net::IPEndPoint>& src_addr,
+ base::Optional<base::span<const uint8_t>> data) override;
+
void OnSendToCompleted(int net_result);
void FinishPendingSend(int net_result);
@@ -139,6 +156,9 @@ class CONTENT_EXPORT PepperUDPSocketMessageFilter
void SendRecvFromResult(int32_t result,
const std::string& data,
const PP_NetAddress_Private& addr);
+ void SendRecvFromResultOnIOThread(int32_t result,
+ const std::string& data,
+ const PP_NetAddress_Private& addr);
void SendSendToReply(const ppapi::host::ReplyMessageContext& context,
int32_t result,
int32_t bytes_written);
@@ -148,9 +168,18 @@ class CONTENT_EXPORT PepperUDPSocketMessageFilter
void SendRecvFromError(int32_t result);
void SendSendToError(const ppapi::host::ReplyMessageContext& context,
int32_t result);
+ void PipeClosed();
int32_t CanUseMulticastAPI(const PP_NetAddress_Private& addr);
+ template <class ReturnMessage>
+ base::OnceCallback<void(int result)> CreateCompletionCallback(
+ const ppapi::host::HostMessageContext* context);
+
+ template <class ReturnMessage>
+ void ReturnResult(const ppapi::host::ReplyMessageContext& context,
+ std::unique_ptr<int> result);
+
// Bitwise-or of SocketOption flags. This stores the state about whether
// each option is set before Bind() is called.
int socket_options_;
@@ -163,20 +192,10 @@ class CONTENT_EXPORT PepperUDPSocketMessageFilter
int multicast_ttl_;
int32_t can_use_multicast_;
- std::unique_ptr<net::UDPSocket> socket_;
bool closed_;
-#if defined(OS_CHROMEOS)
- std::unique_ptr<chromeos::FirewallHole,
- content::BrowserThread::DeleteOnUIThread>
- firewall_hole_;
-#endif // defined(OS_CHROMEOS)
-
- scoped_refptr<net::IOBuffer> recvfrom_buffer_;
base::queue<PendingSend> pending_sends_;
- net::IPEndPoint recvfrom_address_;
-
size_t remaining_recv_slots_;
bool external_plugin_;
@@ -187,6 +206,27 @@ class CONTENT_EXPORT PepperUDPSocketMessageFilter
const bool is_potentially_secure_plugin_context_;
+ // Bound (in a Mojo sense) when binding (in a network sense) starts. Closed in
+ // Close() and on Mojo pipe errors. Must only be accessed (and destroyed) on
+ // UI thread.
+ network::mojom::UDPSocketPtr socket_;
+
+ // Bound (in a Mojo sense) when binding (in a network sense) completes.
+ // Binding late avoids receiving data when still setting up the socket. Closed
+ // in Close() and on Mojo pipe errors. Must only be accessed (and destroyed)
+ // on UI thread.
+ mojo::Binding<network::mojom::UDPSocketReceiver> binding_;
+
+#if defined(OS_CHROMEOS)
+ std::unique_ptr<chromeos::FirewallHole,
+ content::BrowserThread::DeleteOnUIThread>
+ firewall_hole_;
+ // Allows for cancellation of opening a hole in the firewall in the case the
+ // network service crashes.
+ base::WeakPtrFactory<PepperUDPSocketMessageFilter>
+ firewall_hole_weak_ptr_factory_;
+#endif // defined(OS_CHROMEOS)
+
DISALLOW_COPY_AND_ASSIGN(PepperUDPSocketMessageFilter);
};
diff --git a/chromium/content/browser/renderer_host/render_frame_metadata_provider_impl.h b/chromium/content/browser/renderer_host/render_frame_metadata_provider_impl.h
index fe6117100bf..1e5fdb2bfa5 100644
--- a/chromium/content/browser/renderer_host/render_frame_metadata_provider_impl.h
+++ b/chromium/content/browser/renderer_host/render_frame_metadata_provider_impl.h
@@ -65,7 +65,7 @@ class CONTENT_EXPORT RenderFrameMetadataProviderImpl
const cc::RenderFrameMetadata& metadata) override;
void OnFrameSubmissionForTesting(uint32_t frame_token) override;
- base::ObserverList<Observer> observers_;
+ base::ObserverList<Observer>::Unchecked observers_;
cc::RenderFrameMetadata last_render_frame_metadata_;
diff --git a/chromium/content/browser/renderer_host/render_message_filter.cc b/chromium/content/browser/renderer_host/render_message_filter.cc
index 8ca3b5ed1ff..cc6d5b62567 100644
--- a/chromium/content/browser/renderer_host/render_message_filter.cc
+++ b/chromium/content/browser/renderer_host/render_message_filter.cc
@@ -18,7 +18,7 @@
#include "base/numerics/safe_math.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/threading/thread.h"
#include "build/build_config.h"
#include "components/download/public/common/download_stats.h"
@@ -29,6 +29,9 @@
#include "content/browser/cache_storage/cache_storage_cache_handle.h"
#include "content/browser/cache_storage/cache_storage_context_impl.h"
#include "content/browser/cache_storage/cache_storage_manager.h"
+#include "content/browser/child_process_security_policy_impl.h"
+#include "content/browser/code_cache/generated_code_cache.h"
+#include "content/browser/code_cache/generated_code_cache_context.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
@@ -45,6 +48,8 @@
#include "content/public/browser/browser_context.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/resource_context.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/context_menu_params.h"
#include "content/public/common/url_constants.h"
@@ -59,6 +64,7 @@
#include "net/http/http_cache.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
+#include "services/network/public/mojom/network_context.mojom.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -88,6 +94,26 @@ const uint32_t kRenderFilteredMessageClasses[] = {ViewMsgStart};
void NoOpCacheStorageErrorCallback(CacheStorageCacheHandle cache_handle,
CacheStorageError error) {}
+base::Optional<url::Origin> GetRendererOrigin(const GURL& url,
+ int render_process_id) {
+ GURL requesting_url =
+ ChildProcessSecurityPolicyImpl::GetInstance()->GetOriginLock(
+ render_process_id);
+
+ if (!requesting_url.is_valid() || !url.is_valid())
+ return base::nullopt;
+
+ url::Origin origin = url::Origin::Create(requesting_url);
+
+ // Don't cache the code corresponding to unique origins. The same-origin
+ // checks should always fail for unique origins but the serialized value of
+ // unique origins does not ensure this.
+ if (origin.unique())
+ return base::nullopt;
+
+ return origin;
+}
+
} // namespace
RenderMessageFilter::RenderMessageFilter(
@@ -96,7 +122,8 @@ RenderMessageFilter::RenderMessageFilter(
net::URLRequestContextGetter* request_context,
RenderWidgetHelper* render_widget_helper,
MediaInternals* media_internals,
- CacheStorageContextImpl* cache_storage_context)
+ CacheStorageContextImpl* cache_storage_context,
+ GeneratedCodeCacheContext* generated_code_cache_context)
: BrowserMessageFilter(kRenderFilteredMessageClasses,
arraysize(kRenderFilteredMessageClasses)),
BrowserAssociatedInterface<mojom::RenderMessageFilter>(this, this),
@@ -107,6 +134,7 @@ RenderMessageFilter::RenderMessageFilter(
render_process_id_(render_process_id),
media_internals_(media_internals),
cache_storage_context_(cache_storage_context),
+ generated_code_cache_context_(generated_code_cache_context),
weak_ptr_factory_(this) {
DCHECK(request_context_.get());
@@ -209,22 +237,69 @@ void RenderMessageFilter::DidGenerateCacheableMetadata(
return;
}
- net::HttpCache* cache = request_context_->GetURLRequestContext()->
- http_transaction_factory()->GetCache();
- if (!cache)
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!base::FeatureList::IsEnabled(features::kIsolatedCodeCache)) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&RenderMessageFilter::DidGenerateCacheableMetadataOnUI,
+ this, url, expected_response_time, data));
+ } else {
+ if (!generated_code_cache_context_->generated_code_cache())
+ return;
+
+ base::Optional<url::Origin> requesting_origin =
+ GetRendererOrigin(url, render_process_id_);
+ if (!requesting_origin)
+ return;
+
+ generated_code_cache_context_->generated_code_cache()->WriteData(
+ url, *requesting_origin, expected_response_time, data);
+ }
+}
+
+void RenderMessageFilter::FetchCachedCode(const GURL& url,
+ FetchCachedCodeCallback callback) {
+ if (!generated_code_cache_context_->generated_code_cache()) {
+ std::move(callback).Run(base::Time(), std::vector<uint8_t>());
+ return;
+ }
+
+ base::Optional<url::Origin> requesting_origin =
+ GetRendererOrigin(url, render_process_id_);
+ if (!requesting_origin) {
+ std::move(callback).Run(base::Time(), std::vector<uint8_t>());
return;
+ }
- // Use the same priority for the metadata write as for script
- // resources (see defaultPriorityForResourceType() in WebKit's
- // CachedResource.cpp). Note that WebURLRequest::PriorityMedium
- // corresponds to net::LOW (see ConvertWebKitPriorityToNetPriority()
- // in weburlloader_impl.cc).
- const net::RequestPriority kPriority = net::LOW;
- scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(data.size()));
- if (!data.empty())
- memcpy(buf->data(), &data.front(), data.size());
- cache->WriteMetadata(url, kPriority, expected_response_time, buf.get(),
- data.size());
+ base::RepeatingCallback<void(const base::Time&, const std::vector<uint8_t>&)>
+ read_callback = base::BindRepeating(
+ &RenderMessageFilter::OnReceiveCachedCode,
+ weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback));
+ generated_code_cache_context_->generated_code_cache()->FetchEntry(
+ url, *requesting_origin, read_callback);
+}
+
+void RenderMessageFilter::OnReceiveCachedCode(
+ FetchCachedCodeCallback callback,
+ const base::Time& response_time,
+ const std::vector<uint8_t>& data) {
+ // TODO(crbug.com/867848): Pass the data as a mojo data pipe instead
+ // of vector<uint8>
+ std::move(callback).Run(response_time, data);
+}
+
+void RenderMessageFilter::ClearCodeCacheEntry(const GURL& url) {
+ if (!generated_code_cache_context_->generated_code_cache())
+ return;
+
+ base::Optional<url::Origin> requesting_origin =
+ GetRendererOrigin(url, render_process_id_);
+ if (!requesting_origin)
+ return;
+
+ generated_code_cache_context_->generated_code_cache()->DeleteEntry(
+ url, *requesting_origin);
}
void RenderMessageFilter::DidGenerateCacheableMetadataInCacheStorage(
@@ -273,4 +348,23 @@ void RenderMessageFilter::HasGpuProcess(HasGpuProcessCallback callback) {
GpuProcessHost::GetHasGpuProcess(std::move(callback));
}
+void RenderMessageFilter::DidGenerateCacheableMetadataOnUI(
+ const GURL& url,
+ base::Time expected_response_time,
+ const std::vector<uint8_t>& data) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ RenderProcessHost* host = RenderProcessHost::FromID(render_process_id_);
+ if (!host)
+ return;
+
+ // Use the same priority for the metadata write as for script
+ // resources (see defaultPriorityForResourceType() in WebKit's
+ // CachedResource.cpp). Note that WebURLRequest::PriorityMedium
+ // corresponds to net::LOW (see ConvertWebKitPriorityToNetPriority()
+ // in weburlloader_impl.cc).
+ const net::RequestPriority kPriority = net::LOW;
+ host->GetStoragePartition()->GetNetworkContext()->WriteCacheMetadata(
+ url, kPriority, expected_response_time, data);
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/render_message_filter.h b/chromium/content/browser/renderer_host/render_message_filter.h
index b90944a9f34..76eda81660d 100644
--- a/chromium/content/browser/renderer_host/render_message_filter.h
+++ b/chromium/content/browser/renderer_host/render_message_filter.h
@@ -58,6 +58,7 @@ class MediaInternals;
class RenderWidgetHelper;
class ResourceContext;
class ResourceDispatcherHostImpl;
+class GeneratedCodeCacheContext;
// This class filters out incoming IPC messages for the renderer process on the
// IPC thread.
@@ -72,7 +73,8 @@ class CONTENT_EXPORT RenderMessageFilter
net::URLRequestContextGetter* request_context,
RenderWidgetHelper* render_widget_helper,
MediaInternals* media_internals,
- CacheStorageContextImpl* cache_storage_context);
+ CacheStorageContextImpl* cache_storage_context,
+ GeneratedCodeCacheContext* generated_code_cache_context);
// BrowserMessageFilter methods:
bool OnMessageReceived(const IPC::Message& message) override;
@@ -103,6 +105,8 @@ class CONTENT_EXPORT RenderMessageFilter
void DidGenerateCacheableMetadata(const GURL& url,
base::Time expected_response_time,
const std::vector<uint8_t>& data) override;
+ void FetchCachedCode(const GURL& url, FetchCachedCodeCallback) override;
+ void ClearCodeCacheEntry(const GURL& url) override;
void DidGenerateCacheableMetadataInCacheStorage(
const GURL& url,
base::Time expected_response_time,
@@ -122,6 +126,9 @@ class CONTENT_EXPORT RenderMessageFilter
base::ThreadPriority priority);
#endif
+ void OnReceiveCachedCode(FetchCachedCodeCallback callback,
+ const base::Time& response_time,
+ const std::vector<uint8_t>& data);
void OnCacheStorageOpenCallback(const GURL& url,
base::Time expected_response_time,
scoped_refptr<net::IOBuffer> buf,
@@ -133,6 +140,11 @@ class CONTENT_EXPORT RenderMessageFilter
bool CheckBenchmarkingEnabled() const;
bool CheckPreparsedJsCachingEnabled() const;
+ // NetworkContext must be called from the UI thread.
+ void DidGenerateCacheableMetadataOnUI(const GURL& url,
+ base::Time expected_response_time,
+ const std::vector<uint8_t>& data);
+
// Cached resource request dispatcher host, guaranteed to be non-null. We do
// not own it; it is managed by the BrowserProcess, which has a wider scope
// than we do.
@@ -151,6 +163,10 @@ class CONTENT_EXPORT RenderMessageFilter
MediaInternals* media_internals_;
CacheStorageContextImpl* cache_storage_context_;
+ // TODO(crbug.com/867347): Consider registering its own Mojo interface rather
+ // than going through RenderMessageFilter.
+ GeneratedCodeCacheContext* generated_code_cache_context_;
+
base::WeakPtrFactory<RenderMessageFilter> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(RenderMessageFilter);
diff --git a/chromium/content/browser/renderer_host/render_process_host_browsertest.cc b/chromium/content/browser/renderer_host/render_process_host_browsertest.cc
index c81f8ed3587..b168086cac1 100644
--- a/chromium/content/browser/renderer_host/render_process_host_browsertest.cc
+++ b/chromium/content/browser/renderer_host/render_process_host_browsertest.cc
@@ -136,38 +136,6 @@ class NonSpareRendererContentBrowserClient : public TestContentBrowserClient {
DISALLOW_COPY_AND_ASSIGN(NonSpareRendererContentBrowserClient);
};
-// Sometimes the renderer process's ShutdownRequest (corresponding to the
-// ViewMsg_WasSwappedOut from a previous navigation) doesn't arrive until after
-// the browser process decides to re-use the renderer for a new purpose. This
-// test makes sure the browser doesn't let the renderer die in that case. See
-// http://crbug.com/87176.
-IN_PROC_BROWSER_TEST_F(RenderProcessHostTest,
- ShutdownRequestFromActiveTabIgnored) {
- ASSERT_TRUE(embedded_test_server()->Start());
-
- GURL test_url = embedded_test_server()->GetURL("/simple_page.html");
- NavigateToURL(shell(), test_url);
- RenderProcessHost* rph =
- shell()->web_contents()->GetMainFrame()->GetProcess();
-
- host_destructions_ = 0;
- process_exits_ = 0;
-
- rph->AddObserver(this);
-
- static_cast<mojom::RendererHost*>(static_cast<RenderProcessHostImpl*>(rph))
- ->ShutdownRequest();
-
- // If the RPH sends a mistaken ProcessShutdown, the renderer process
- // will take some time to die. Wait for a second tab to load in order to give
- // that time to happen.
- NavigateToURL(CreateBrowser(), test_url);
-
- EXPECT_EQ(0, process_exits_);
- if (!host_destructions_)
- rph->RemoveObserver(this);
-}
-
IN_PROC_BROWSER_TEST_F(RenderProcessHostTest,
GuestsAreNotSuitableHosts) {
// Set max renderers to 1 to force running out of processes.
@@ -731,7 +699,9 @@ class AudioStartObserver : public WebContentsObserver {
// Note: This test can't run when the Mojo Renderer is used since it does not
// create audio streams through the normal audio pathways; at present this is
// only used by Chromecast.
-#if BUILDFLAG(ENABLE_MOJO_RENDERER)
+//
+// crbug.com/864476: flaky on Android for unclear reasons.
+#if BUILDFLAG(ENABLE_MOJO_RENDERER) || defined(OS_ANDROID)
#define KillProcessZerosAudioStreams DISABLED_KillProcessZerosAudioStreams
#endif
IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, KillProcessZerosAudioStreams) {
@@ -740,8 +710,8 @@ IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, KillProcessZerosAudioStreams) {
embedded_test_server()->ServeFilesFromSourceDirectory(
media::GetTestDataPath());
ASSERT_TRUE(embedded_test_server()->Start());
- NavigateToURL(shell(),
- embedded_test_server()->GetURL("/webaudio_oscillator.html"));
+ ASSERT_TRUE(NavigateToURL(
+ shell(), embedded_test_server()->GetURL("/webaudio_oscillator.html")));
RenderProcessHostImpl* rph = static_cast<RenderProcessHostImpl*>(
shell()->web_contents()->GetMainFrame()->GetProcess());
@@ -986,7 +956,15 @@ IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, KeepAliveRendererProcess) {
rph->RemoveObserver(this);
}
-IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, KeepAliveRendererProcess_Hung) {
+// Test is flaky on Android builders: https://crbug.com/875179
+#if defined(OS_ANDROID)
+#define MAYBE_KeepAliveRendererProcess_Hung \
+ DISABLED_KeepAliveRendererProcess_Hung
+#else
+#define MAYBE_KeepAliveRendererProcess_Hung KeepAliveRendererProcess_Hung
+#endif
+IN_PROC_BROWSER_TEST_F(RenderProcessHostTest,
+ MAYBE_KeepAliveRendererProcess_Hung) {
embedded_test_server()->RegisterRequestHandler(
base::BindRepeating(HandleHungBeacon));
ASSERT_TRUE(embedded_test_server()->Start());
@@ -1013,8 +991,16 @@ IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, KeepAliveRendererProcess_Hung) {
rph->RemoveObserver(this);
}
+// Test is flaky on Android builders: https://crbug.com/875179
+#if defined(OS_ANDROID)
+#define MAYBE_FetchKeepAliveRendererProcess_Hung \
+ DISABLED_FetchKeepAliveRendererProcess_Hung
+#else
+#define MAYBE_FetchKeepAliveRendererProcess_Hung \
+ FetchKeepAliveRendererProcess_Hung
+#endif
IN_PROC_BROWSER_TEST_F(RenderProcessHostTest,
- FetchKeepAliveRendererProcess_Hung) {
+ MAYBE_FetchKeepAliveRendererProcess_Hung) {
embedded_test_server()->RegisterRequestHandler(
base::BindRepeating(HandleHungBeacon));
ASSERT_TRUE(embedded_test_server()->Start());
diff --git a/chromium/content/browser/renderer_host/render_process_host_impl.cc b/chromium/content/browser/renderer_host/render_process_host_impl.cc
index 05e0ee79e5a..989b52793c4 100644
--- a/chromium/content/browser/renderer_host/render_process_host_impl.cc
+++ b/chromium/content/browser/renderer_host/render_process_host_impl.cc
@@ -52,7 +52,7 @@
#include "base/supports_user_data.h"
#include "base/synchronization/lock.h"
#include "base/sys_info.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -66,6 +66,7 @@
#include "components/metrics/single_sample_metrics.h"
#include "components/tracing/common/tracing_switches.h"
#include "components/viz/common/switches.h"
+#include "components/viz/host/gpu_client.h"
#include "content/browser/appcache/appcache_dispatcher_host.h"
#include "content/browser/appcache/chrome_appcache_service.h"
#include "content/browser/background_fetch/background_fetch_context.h"
@@ -87,10 +88,11 @@
#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
#include "content/browser/dom_storage/dom_storage_message_filter.h"
#include "content/browser/field_trial_recorder.h"
-#include "content/browser/fileapi/fileapi_message_filter.h"
+#include "content/browser/fileapi/file_system_manager_impl.h"
+#include "content/browser/font_unique_name_lookup/font_unique_name_lookup_service.h"
#include "content/browser/frame_host/render_frame_message_filter.h"
+#include "content/browser/gpu/browser_gpu_client_delegate.h"
#include "content/browser/gpu/compositor_util.h"
-#include "content/browser/gpu/gpu_client_impl.h"
#include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/gpu/shader_cache_factory.h"
#include "content/browser/histogram_controller.h"
@@ -150,6 +152,7 @@
#include "content/common/view_messages.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host_factory.h"
@@ -185,6 +188,7 @@
#include "media/base/media_switches.h"
#include "media/media_buildflags.h"
#include "media/mojo/services/video_decode_perf_history.h"
+#include "media/webrtc/webrtc_switches.h"
#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/cpp/system/platform_handle.h"
@@ -192,6 +196,7 @@
#include "ppapi/buildflags/buildflags.h"
#include "services/device/public/mojom/battery_monitor.mojom.h"
#include "services/device/public/mojom/constants.mojom.h"
+#include "services/network/cross_origin_read_blocking.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/network_switches.h"
#include "services/network/public/mojom/network_service.mojom.h"
@@ -906,11 +911,11 @@ class SiteProcessCountTracker : public base::SupportsUserData::Data,
map_.erase(site_url);
}
- void FindRenderProcessesForSite(
- const GURL& site_url,
+ void FindRenderProcessesForSiteInstance(
+ SiteInstanceImpl* site_instance,
std::set<RenderProcessHost*>* foreground_processes,
std::set<RenderProcessHost*>* background_processes) {
- auto result = map_.find(site_url);
+ auto result = map_.find(site_instance->GetSiteURL());
if (result == map_.end())
return;
@@ -932,8 +937,10 @@ class SiteProcessCountTracker : public base::SupportsUserData::Data,
// allow such hosts to be reused. See https://crbug.com/780661.
if (!host->MayReuseHost() ||
!RenderProcessHostImpl::IsSuitableHost(
- host, host->GetBrowserContext(), site_url))
+ host, host->GetBrowserContext(), site_instance->GetSiteURL(),
+ site_instance->lock_url())) {
continue;
+ }
if (host->VisibleClientCount())
foreground_processes->insert(host);
@@ -1028,13 +1035,13 @@ class UnmatchedServiceWorkerProcessTracker
public RenderProcessHostObserver {
public:
// Registers |render_process_host| as having an unmatched service worker for
- // |site_url|.
- static void Register(BrowserContext* browser_context,
- RenderProcessHost* render_process_host,
- const GURL& site_url) {
- DCHECK(!site_url.is_empty());
+ // |site_instance|.
+ static void Register(RenderProcessHost* render_process_host,
+ SiteInstanceImpl* site_instance) {
+ BrowserContext* browser_context = site_instance->GetBrowserContext();
+ DCHECK(!site_instance->GetSiteURL().is_empty());
if (!ShouldTrackProcessForSite(browser_context, render_process_host,
- site_url))
+ site_instance->GetSiteURL()))
return;
UnmatchedServiceWorkerProcessTracker* tracker =
@@ -1046,14 +1053,15 @@ class UnmatchedServiceWorkerProcessTracker
browser_context->SetUserData(kUnmatchedServiceWorkerProcessTrackerKey,
base::WrapUnique(tracker));
}
- tracker->RegisterProcessForSite(render_process_host, site_url);
+ tracker->RegisterProcessForSite(render_process_host, site_instance);
}
- // Find a process with an unmatched service worker for |site_url| and removes
- // the process from the tracker if it exists.
- static RenderProcessHost* MatchWithSite(BrowserContext* browser_context,
- const GURL& site_url) {
- if (!ShouldFindReusableProcessHostForSite(browser_context, site_url))
+ // Find a process with an unmatched service worker for |site_instance| and
+ // removes the process from the tracker if it exists.
+ static RenderProcessHost* MatchWithSite(SiteInstanceImpl* site_instance) {
+ BrowserContext* browser_context = site_instance->GetBrowserContext();
+ if (!ShouldFindReusableProcessHostForSite(browser_context,
+ site_instance->GetSiteURL()))
return nullptr;
UnmatchedServiceWorkerProcessTracker* tracker =
@@ -1062,7 +1070,7 @@ class UnmatchedServiceWorkerProcessTracker
kUnmatchedServiceWorkerProcessTrackerKey));
if (!tracker)
return nullptr;
- return tracker->TakeFreshestProcessForSite(site_url);
+ return tracker->TakeFreshestProcessForSite(site_instance);
}
UnmatchedServiceWorkerProcessTracker() {}
@@ -1086,14 +1094,17 @@ class UnmatchedServiceWorkerProcessTracker
}
private:
- void RegisterProcessForSite(RenderProcessHost* host, const GURL& site_url) {
+ void RegisterProcessForSite(RenderProcessHost* host,
+ SiteInstanceImpl* site_instance) {
if (!HasProcess(host))
host->AddObserver(this);
- site_process_set_.insert(SiteProcessIDPair(site_url, host->GetID()));
+ site_process_set_.insert(
+ SiteProcessIDPair(site_instance->GetSiteURL(), host->GetID()));
}
- RenderProcessHost* TakeFreshestProcessForSite(const GURL& site_url) {
- RenderProcessHost* host = FindFreshestProcessForSite(site_url);
+ RenderProcessHost* TakeFreshestProcessForSite(
+ SiteInstanceImpl* site_instance) {
+ RenderProcessHost* host = FindFreshestProcessForSite(site_instance);
if (!host)
return nullptr;
@@ -1101,8 +1112,10 @@ class UnmatchedServiceWorkerProcessTracker
// |site_url|, for example if it was used for a ServiceWorker for a
// nonexistent extension URL. See https://crbug.com/782349 and
// https://crbug.com/780661.
+ GURL site_url(site_instance->GetSiteURL());
if (!host->MayReuseHost() || !RenderProcessHostImpl::IsSuitableHost(
- host, host->GetBrowserContext(), site_url))
+ host, host->GetBrowserContext(), site_url,
+ site_instance->lock_url()))
return nullptr;
site_process_set_.erase(SiteProcessIDPair(site_url, host->GetID()));
@@ -1111,7 +1124,9 @@ class UnmatchedServiceWorkerProcessTracker
return host;
}
- RenderProcessHost* FindFreshestProcessForSite(const GURL& site_url) const {
+ RenderProcessHost* FindFreshestProcessForSite(
+ SiteInstanceImpl* site_instance) const {
+ GURL site_url(site_instance->GetSiteURL());
for (const auto& site_process_pair : base::Reversed(site_process_set_)) {
if (site_process_pair.first == site_url)
return RenderProcessHost::FromID(site_process_pair.second);
@@ -1192,9 +1207,9 @@ bool ShouldBoostPriorityForPendingViews() {
// TODO(gab): End the experiment and turn ShouldBoostPriorityForPendingViews()
// into a constant when results are in.
static bool should_boost_for_pending_views =
- base::StartsWith(base::FieldTrialList::FindFullName(
- "BoostRendererPriorityForPendingViews"),
- "Enabled", base::CompareCase::SENSITIVE);
+ !base::StartsWith(base::FieldTrialList::FindFullName(
+ "BoostRendererPriorityForPendingViews"),
+ "Disabled", base::CompareCase::SENSITIVE);
return should_boost_for_pending_views;
#endif
}
@@ -1207,6 +1222,69 @@ void CopyFeatureSwitch(const base::CommandLine& src,
dest->AppendSwitchASCII(switch_name, base::JoinString(features, ","));
}
+void GetNetworkChangeManager(
+ network::mojom::NetworkChangeManagerRequest request) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ GetNetworkService()->GetNetworkChangeManager(std::move(request));
+}
+
+void RemoveCorbExceptionForPluginOnIOThread(int process_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // Without NetworkService the exception list is stored directly in the browser
+ // process.
+ if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
+ network::CrossOriginReadBlocking::RemoveExceptionForPlugin(process_id);
+}
+
+// This is the entry point (i.e. this is called on the UI thread *before*
+// we post a task for RemoveCorbExceptionForPluginOnIOThread).
+void RemoveCorbExceptionForPluginOnUIThread(int process_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ GetNetworkService()->RemoveCorbExceptionForPlugin(process_id);
+ } else {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&RemoveCorbExceptionForPluginOnIOThread, process_id));
+ }
+}
+
+void AddCorbExceptionForPluginOnUIThread(int process_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ RenderProcessHost* process = RenderProcessHostImpl::FromID(process_id);
+ if (!process) {
+ // In this case the exception won't be added via NetworkService (because of
+ // the early return below), but we need to proactively do clean-up on IO
+ // thread.
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&RemoveCorbExceptionForPluginOnIOThread, process_id));
+ return;
+ }
+ process->CleanupCorbExceptionForPluginUponDestruction();
+
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService))
+ GetNetworkService()->AddCorbExceptionForPlugin(process_id);
+}
+
+// This is the entry point (i.e. this is called on the IO thread *before*
+// we post a task for AddCorbExceptionForPluginOnUIThread).
+void AddCorbExceptionForPluginOnIOThread(int process_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // Without NetworkService the exception list is stored directly in the browser
+ // process.
+ if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
+ network::CrossOriginReadBlocking::AddExceptionForPlugin(process_id);
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&AddCorbExceptionForPluginOnUIThread, process_id));
+}
+
} // namespace
// Held by the RPH and used to control an (unowned) ConnectionFilterImpl from
@@ -1446,6 +1524,7 @@ RenderProcessHostImpl::RenderProcessHostImpl(
priority_(!blink::kLaunchingProcessIsBackgrounded,
false /* has_media_stream */,
frame_depth_,
+ false /* intersects_viewport */,
ShouldBoostPriorityForPendingViews(),
#if defined(OS_ANDROID)
// Only use |boost_for_pending_views| to infer is_background()
@@ -1531,12 +1610,12 @@ RenderProcessHostImpl::RenderProcessHostImpl(
InitializeChannelProxy();
- if (features::IsAshInBrowserProcess()) {
+ if (!features::IsUsingWindowService()) {
const int id = GetID();
const uint64_t tracing_id =
ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(id);
- gpu_client_.reset(new GpuClientImpl(
- id, tracing_id,
+ gpu_client_.reset(new viz::GpuClient(
+ std::make_unique<BrowserGpuClientDelegate>(), id, tracing_id,
BrowserThread::GetTaskRunnerForThread(BrowserThread::IO)));
}
@@ -1606,6 +1685,9 @@ RenderProcessHostImpl::~RenderProcessHostImpl() {
}
GetMemoryDumpProvider().RemoveHost(this);
+
+ if (cleanup_corb_exception_for_plugin_upon_destruction_)
+ RemoveCorbExceptionForPluginOnUIThread(GetID());
}
bool RenderProcessHostImpl::Init() {
@@ -1862,11 +1944,14 @@ void RenderProcessHostImpl::CreateMessageFilters() {
scoped_refptr<net::URLRequestContextGetter> request_context(
storage_partition_impl_->GetURLRequestContext());
+ // TODO(crbug.com/867347): Consider registering Mojo interface for
+ // GeneratedCodeCache rather than going through RenderMessageFilter.
scoped_refptr<RenderMessageFilter> render_message_filter =
base::MakeRefCounted<RenderMessageFilter>(
GetID(), GetBrowserContext(), request_context.get(),
widget_helper_.get(), media_internals,
- storage_partition_impl_->GetCacheStorageContext());
+ storage_partition_impl_->GetCacheStorageContext(),
+ storage_partition_impl_->GetGeneratedCodeCacheContext());
AddFilter(render_message_filter.get());
render_frame_message_filter_ = new RenderFrameMessageFilter(
@@ -1913,21 +1998,16 @@ void RenderProcessHostImpl::CreateMessageFilters() {
#if BUILDFLAG(ENABLE_PLUGINS)
AddFilter(new PepperRendererConnection(GetID()));
#endif
- AddFilter(new FileAPIMessageFilter(
- GetID(), storage_partition_impl_->GetURLRequestContext(),
- storage_partition_impl_->GetFileSystemContext(),
- blob_storage_context.get()));
AddFilter(new BlobDispatcherHost(GetID(), blob_storage_context));
#if defined(OS_MACOSX)
AddFilter(new TextInputClientMessageFilter());
#endif
p2p_socket_dispatcher_host_ =
- new P2PSocketDispatcherHost(request_context.get());
- AddFilter(p2p_socket_dispatcher_host_.get());
+ std::make_unique<P2PSocketDispatcherHost>(GetID());
AddFilter(new TraceMessageFilter(GetID()));
- AddFilter(new ResolveProxyMsgHelper(request_context.get()));
+ AddFilter(new ResolveProxyMsgHelper(GetID()));
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context(
static_cast<ServiceWorkerContextWrapper*>(
@@ -1975,13 +2055,20 @@ void RenderProcessHostImpl::DelayProcessShutdownForUnload(
timeout);
}
+// static
+void RenderProcessHostImpl::AddCorbExceptionForPlugin(int process_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ AddCorbExceptionForPluginOnIOThread(process_id);
+}
+
+void RenderProcessHostImpl::CleanupCorbExceptionForPluginUponDestruction() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ cleanup_corb_exception_for_plugin_upon_destruction_ = true;
+}
+
void RenderProcessHostImpl::RegisterMojoInterfaces() {
auto registry = std::make_unique<service_manager::BinderRegistry>();
- channel_->AddAssociatedInterfaceForIOThread(
- base::Bind(&IndexedDBDispatcherHost::AddBinding,
- base::Unretained(indexed_db_factory_.get())));
-
channel_->AddAssociatedInterfaceForIOThread(base::BindRepeating(
&ServiceWorkerDispatcherHost::AddBinding,
base::Unretained(service_worker_dispatcher_host_.get())));
@@ -2048,6 +2135,13 @@ void RenderProcessHostImpl::RegisterMojoInterfaces() {
registry->AddInterface(base::Bind(&hyphenation::HyphenationImpl::Create),
hyphenation::HyphenationImpl::GetTaskRunner());
#endif
+#if defined(OS_ANDROID)
+ if (base::FeatureList::IsEnabled(features::kFontSrcLocalMatching)) {
+ registry->AddInterface(
+ base::BindRepeating(&FontUniqueNameLookupService::Create),
+ FontUniqueNameLookupService::GetTaskRunner());
+ }
+#endif
registry->AddInterface(base::Bind(&device::GamepadHapticsManager::Create));
@@ -2055,14 +2149,25 @@ void RenderProcessHostImpl::RegisterMojoInterfaces() {
base::Bind(&PushMessagingManager::BindRequest,
base::Unretained(push_messaging_manager_.get())));
+ file_system_manager_impl_.reset(new FileSystemManagerImpl(
+ GetID(), storage_partition_impl_->GetFileSystemContext(),
+ ChromeBlobStorageContext::GetFor(GetBrowserContext())));
+ registry->AddInterface(
+ base::BindRepeating(&FileSystemManagerImpl::BindRequest,
+ base::Unretained(file_system_manager_impl_.get())));
+
if (gpu_client_) {
// |gpu_client_| outlives the registry, because its destruction is posted to
// IO thread from the destructor of |this|.
registry->AddInterface(base::BindRepeating(
- &GpuClientImpl::Add, base::Unretained(gpu_client_.get())));
+ &viz::GpuClient::Add, base::Unretained(gpu_client_.get())));
}
registry->AddInterface(
+ base::BindRepeating(&IndexedDBDispatcherHost::AddBinding,
+ base::Unretained(indexed_db_factory_.get())));
+
+ registry->AddInterface(
base::Bind(
&WebDatabaseHostImpl::Create, GetID(),
base::WrapRefCounted(storage_partition_impl_->GetDatabaseTracker())),
@@ -2096,9 +2201,15 @@ void RenderProcessHostImpl::RegisterMojoInterfaces() {
base::Unretained(storage_partition_impl_->GetAppCacheService()),
GetID()));
+ AddUIThreadInterface(
+ registry.get(),
+ base::BindRepeating(&P2PSocketDispatcherHost::BindRequest,
+ base::Unretained(p2p_socket_dispatcher_host_.get())));
+
AddUIThreadInterface(registry.get(), base::Bind(&FieldTrialRecorder::Create));
- associated_interfaces_ = std::make_unique<AssociatedInterfaceRegistryImpl>();
+ associated_interfaces_ =
+ std::make_unique<blink::AssociatedInterfaceRegistry>();
blink::AssociatedInterfaceRegistry* associated_registry =
associated_interfaces_.get();
associated_registry->AddInterface(base::Bind(
@@ -2132,6 +2243,12 @@ void RenderProcessHostImpl::RegisterMojoInterfaces() {
registry->AddInterface(base::BindRepeating(&KeySystemSupportImpl::Create));
#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
+ AddUIThreadInterface(registry.get(),
+ base::BindRepeating(&GetNetworkChangeManager));
+
+ registry->AddInterface(base::BindRepeating(
+ &RenderProcessHostImpl::BindVideoDecoderService, base::Unretained(this)));
+
// ---- Please do not register interfaces below this line ------
//
// This call should be done after registering all interfaces above, so that
@@ -2164,7 +2281,7 @@ void RenderProcessHostImpl::BindRouteProvider(
void RenderProcessHostImpl::GetRoute(
int32_t routing_id,
- mojom::AssociatedInterfaceProviderAssociatedRequest request) {
+ blink::mojom::AssociatedInterfaceProviderAssociatedRequest request) {
DCHECK(request.is_pending());
associated_interface_provider_bindings_.AddBinding(
this, std::move(request), routing_id);
@@ -2172,7 +2289,7 @@ void RenderProcessHostImpl::GetRoute(
void RenderProcessHostImpl::GetAssociatedInterface(
const std::string& name,
- mojom::AssociatedInterfaceAssociatedRequest request) {
+ blink::mojom::AssociatedInterfaceAssociatedRequest request) {
int32_t routing_id =
associated_interface_provider_bindings_.dispatch_context();
IPC::Listener* listener = listeners_.Lookup(routing_id);
@@ -2214,6 +2331,13 @@ void RenderProcessHostImpl::CreateStoragePartitionService(
storage_partition_impl_->Bind(id_, std::move(request));
}
+void RenderProcessHostImpl::BindVideoDecoderService(
+ media::mojom::InterfaceFactoryRequest request) {
+ if (!video_decoder_proxy_)
+ video_decoder_proxy_.reset(new VideoDecoderProxy());
+ video_decoder_proxy_->Add(std::move(request));
+}
+
void RenderProcessHostImpl::CreateRendererHost(
mojom::RendererHostAssociatedRequest request) {
renderer_host_binding_.Bind(std::move(request));
@@ -2496,6 +2620,10 @@ unsigned int RenderProcessHostImpl::GetFrameDepth() const {
return frame_depth_;
}
+bool RenderProcessHostImpl::GetIntersectsViewport() const {
+ return intersects_viewport_;
+}
+
#if defined(OS_ANDROID)
ChildProcessImportance RenderProcessHostImpl::GetEffectiveImportance() {
return effective_importance_;
@@ -2771,6 +2899,11 @@ void RenderProcessHostImpl::AppendRendererCommandLine(
child_connection_->service_token());
command_line->AppendSwitchASCII(switches::kRendererClientId,
std::to_string(GetID()));
+
+ if (SiteIsolationPolicy::UseDedicatedProcessesForAllSites()) {
+ // Disable V8 code mitigations if renderer processes are site-isolated.
+ command_line->AppendSwitch(switches::kNoV8UntrustedCodeMitigations);
+ }
}
void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
@@ -2815,6 +2948,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kDisableLogging,
switches::kDisableMediaSuspend,
switches::kDisableNotifications,
+ switches::kDisableOopRasterization,
switches::kDisableOriginTrialControlledBlinkFeatures,
switches::kDisablePepper3DImageChromium,
switches::kDisablePermissionsAPI,
@@ -2844,6 +2978,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kEnableLCDText,
switches::kEnableLogging,
switches::kEnableNetworkInformationDownlinkMax,
+ switches::kEnableOopRasterization,
switches::kEnablePluginPlaceholderTesting,
switches::kEnablePreciseMemoryInfo,
switches::kEnablePrintBrowser,
@@ -2863,7 +2998,6 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kEnableWebVR,
switches::kExplicitlyAllowedPorts,
switches::kFileUrlPathAlias,
- switches::kFMPNetworkQuietTimeout,
switches::kForceColorProfile,
switches::kForceDeviceScaleFactor,
switches::kForceGpuMemAvailableMb,
@@ -2878,6 +3012,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kMaxUntiledLayerHeight,
switches::kMSEAudioBufferSizeLimitMb,
switches::kMSEVideoBufferSizeLimitMb,
+ switches::kNetworkQuietTimeout,
switches::kNoZygote,
switches::kOverridePluginPowerSaverForTesting,
switches::kPassiveListenersDefault,
@@ -3174,9 +3309,7 @@ void RenderProcessHostImpl::OnAssociatedInterfaceRequest(
const std::string& interface_name,
mojo::ScopedInterfaceEndpointHandle handle) {
if (associated_interfaces_ &&
- associated_interfaces_->CanBindRequest(interface_name)) {
- associated_interfaces_->BindRequest(interface_name, std::move(handle));
- } else {
+ !associated_interfaces_->TryBindInterface(interface_name, &handle)) {
LOG(ERROR) << "Request for unknown Channel-associated interface: "
<< interface_name;
}
@@ -3443,18 +3576,13 @@ RenderProcessHostImpl::StartRtpDump(
bool incoming,
bool outgoing,
const WebRtcRtpPacketCallback& packet_callback) {
- if (!p2p_socket_dispatcher_host_.get())
- return WebRtcStopRtpDumpCallback();
-
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
- base::BindOnce(&P2PSocketDispatcherHost::StartRtpDump,
- p2p_socket_dispatcher_host_, incoming,
- outgoing, packet_callback));
+ p2p_socket_dispatcher_host_->StartRtpDump(incoming, outgoing,
+ packet_callback);
if (stop_rtp_dump_callback_.is_null()) {
stop_rtp_dump_callback_ =
- base::Bind(&P2PSocketDispatcherHost::StopRtpDumpOnUIThread,
- p2p_socket_dispatcher_host_);
+ base::Bind(&P2PSocketDispatcherHost::StopRtpDump,
+ p2p_socket_dispatcher_host_->GetWeakPtr());
}
return stop_rtp_dump_callback_;
}
@@ -3533,7 +3661,8 @@ void RenderProcessHostImpl::FilterURL(RenderProcessHost* rph,
// static
bool RenderProcessHostImpl::IsSuitableHost(RenderProcessHost* host,
BrowserContext* browser_context,
- const GURL& site_url) {
+ const GURL& site_url,
+ const GURL& lock_url) {
if (run_renderer_in_process()) {
DCHECK_EQ(host->GetBrowserContext(), browser_context)
<< " Single-process mode does not support multiple browser contexts.";
@@ -3558,10 +3687,11 @@ bool RenderProcessHostImpl::IsSuitableHost(RenderProcessHost* host,
if (!host->InSameStoragePartition(dest_partition))
return false;
- // Check WebUI bindings and origin locks.
+ // Check WebUI bindings and origin locks. Note that |lock_url| may differ
+ // from |site_url| if an effective URL is used.
auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
bool host_has_web_ui_bindings = policy->HasWebUIBindings(host->GetID());
- auto lock_state = policy->CheckOriginLock(host->GetID(), site_url);
+ auto lock_state = policy->CheckOriginLock(host->GetID(), lock_url);
if (host->HostHasNotBeenUsed()) {
// If the host hasn't been used, it won't have the expected WebUI bindings
// or origin locks just *yet* - skip the checks in this case. One example
@@ -3583,8 +3713,8 @@ bool RenderProcessHostImpl::IsSuitableHost(RenderProcessHost* host,
case CheckOriginLockResult::HAS_WRONG_LOCK:
return false;
case CheckOriginLockResult::NO_LOCK:
- if (!host->IsUnused() && SiteInstanceImpl::ShouldLockToOrigin(
- browser_context, host, site_url)) {
+ if (!host->IsUnused() &&
+ SiteInstanceImpl::ShouldLockToOrigin(browser_context, site_url)) {
// If this process has been used to host any other content, it cannot
// be reused if the destination site requires a dedicated process and
// should use a process locked to just that site.
@@ -3674,8 +3804,7 @@ bool RenderProcessHost::ShouldTryToUseExistingProcessHost(
// static
RenderProcessHost* RenderProcessHostImpl::GetExistingProcessHost(
- BrowserContext* browser_context,
- const GURL& site_url) {
+ SiteInstanceImpl* site_instance) {
// First figure out which existing renderers we can use.
std::vector<RenderProcessHost*> suitable_renderers;
suitable_renderers.reserve(g_all_hosts.Get().size());
@@ -3683,8 +3812,9 @@ RenderProcessHost* RenderProcessHostImpl::GetExistingProcessHost(
iterator iter(AllHostsIterator());
while (!iter.IsAtEnd()) {
if (iter.GetCurrentValue()->MayReuseHost() &&
- RenderProcessHostImpl::IsSuitableHost(iter.GetCurrentValue(),
- browser_context, site_url)) {
+ RenderProcessHostImpl::IsSuitableHost(
+ iter.GetCurrentValue(), site_instance->GetBrowserContext(),
+ site_instance->GetSiteURL(), site_instance->lock_url())) {
// The spare is always considered before process reuse.
DCHECK_NE(iter.GetCurrentValue(),
g_spare_render_process_host_manager.Get()
@@ -3738,19 +3868,29 @@ bool RenderProcessHost::ShouldUseProcessPerSite(BrowserContext* browser_context,
}
// static
-RenderProcessHost* RenderProcessHostImpl::GetProcessHostForSite(
+RenderProcessHost* RenderProcessHostImpl::GetSoleProcessHostForURL(
BrowserContext* browser_context,
const GURL& url) {
+ GURL site_url = SiteInstance::GetSiteForURL(browser_context, url);
+ GURL lock_url =
+ SiteInstanceImpl::DetermineProcessLockURL(browser_context, url);
+ return GetSoleProcessHostForSite(browser_context, site_url, lock_url);
+}
+
+// static
+RenderProcessHost* RenderProcessHostImpl::GetSoleProcessHostForSite(
+ BrowserContext* browser_context,
+ const GURL& site_url,
+ const GURL& lock_url) {
// Look up the map of site to process for the given browser_context.
SiteProcessMap* map = GetSiteProcessMapForBrowserContext(browser_context);
// See if we have an existing process with appropriate bindings for this site.
// If not, the caller should create a new process and register it. Note that
// IsSuitableHost expects a site URL rather than the full |url|.
- GURL site_url = SiteInstance::GetSiteForURL(browser_context, url);
RenderProcessHost* host = map->FindProcess(site_url.possibly_invalid_spec());
if (host && (!host->MayReuseHost() ||
- !IsSuitableHost(host, browser_context, site_url))) {
+ !IsSuitableHost(host, browser_context, site_url, lock_url))) {
// The registered process does not have an appropriate set of bindings for
// the url. Remove it from the map so we can register a better one.
RecordAction(
@@ -3762,25 +3902,23 @@ RenderProcessHost* RenderProcessHostImpl::GetProcessHostForSite(
return host;
}
-void RenderProcessHostImpl::RegisterProcessHostForSite(
+void RenderProcessHostImpl::RegisterSoleProcessHostForSite(
BrowserContext* browser_context,
RenderProcessHost* process,
- const GURL& url) {
+ SiteInstanceImpl* site_instance) {
// Look up the map of site to process for the given browser_context.
SiteProcessMap* map = GetSiteProcessMapForBrowserContext(browser_context);
// Only register valid, non-empty sites. Empty or invalid sites will not
// use process-per-site mode. We cannot check whether the process has
// appropriate bindings here, because the bindings have not yet been granted.
- std::string site =
- SiteInstance::GetSiteForURL(browser_context, url).possibly_invalid_spec();
+ std::string site = site_instance->GetSiteURL().possibly_invalid_spec();
if (!site.empty())
map->RegisterProcess(site, process);
}
// static
RenderProcessHost* RenderProcessHostImpl::GetProcessHostForSiteInstance(
- BrowserContext* browser_context,
SiteInstanceImpl* site_instance) {
const GURL site_url = site_instance->GetSiteURL();
SiteInstanceImpl::ProcessReusePolicy process_reuse_policy =
@@ -3789,11 +3927,13 @@ RenderProcessHost* RenderProcessHostImpl::GetProcessHostForSiteInstance(
RenderProcessHost* render_process_host = nullptr;
bool is_unmatched_service_worker = site_instance->is_for_service_worker();
+ BrowserContext* browser_context = site_instance->GetBrowserContext();
// First, attempt to reuse an existing RenderProcessHost if necessary.
switch (process_reuse_policy) {
case SiteInstanceImpl::ProcessReusePolicy::PROCESS_PER_SITE:
- render_process_host = GetProcessHostForSite(browser_context, site_url);
+ render_process_host = GetSoleProcessHostForSite(
+ browser_context, site_url, site_instance->lock_url());
break;
case SiteInstanceImpl::ProcessReusePolicy::USE_DEFAULT_SUBFRAME_PROCESS:
DCHECK(SiteIsolationPolicy::IsTopDocumentIsolationEnabled());
@@ -3803,7 +3943,7 @@ RenderProcessHost* RenderProcessHostImpl::GetProcessHostForSiteInstance(
break;
case SiteInstanceImpl::ProcessReusePolicy::REUSE_PENDING_OR_COMMITTED_SITE:
render_process_host =
- FindReusableProcessHostForSite(browser_context, site_url);
+ FindReusableProcessHostForSiteInstance(site_instance);
UMA_HISTOGRAM_BOOLEAN(
"SiteIsolation.ReusePendingOrCommittedSite.CouldReuse",
render_process_host != nullptr);
@@ -3821,8 +3961,8 @@ RenderProcessHost* RenderProcessHostImpl::GetProcessHostForSiteInstance(
if (!render_process_host &&
!(process_reuse_policy == SiteInstanceImpl::ProcessReusePolicy::DEFAULT &&
site_instance->is_for_service_worker())) {
- render_process_host = UnmatchedServiceWorkerProcessTracker::MatchWithSite(
- browser_context, site_url);
+ render_process_host =
+ UnmatchedServiceWorkerProcessTracker::MatchWithSite(site_instance);
}
// See if the spare RenderProcessHost can be used.
@@ -3838,16 +3978,16 @@ RenderProcessHost* RenderProcessHostImpl::GetProcessHostForSiteInstance(
// If not (or if none found), see if we should reuse an existing process.
if (!render_process_host &&
ShouldTryToUseExistingProcessHost(browser_context, site_url)) {
- render_process_host = GetExistingProcessHost(browser_context, site_url);
+ render_process_host = GetExistingProcessHost(site_instance);
}
// If we found a process to reuse, sanity check that it is suitable for
// hosting |site_url|. For example, if |site_url| requires a dedicated
// process, we should never pick a process used by, or locked to, a different
// site.
- if (render_process_host &&
- !RenderProcessHostImpl::IsSuitableHost(render_process_host,
- browser_context, site_url)) {
+ if (render_process_host && !RenderProcessHostImpl::IsSuitableHost(
+ render_process_host, browser_context, site_url,
+ site_instance->lock_url())) {
ChildProcessSecurityPolicyImpl* policy =
ChildProcessSecurityPolicyImpl::GetInstance();
base::debug::SetCrashKeyString(bad_message::GetRequestedSiteURLKey(),
@@ -3881,8 +4021,8 @@ RenderProcessHost* RenderProcessHostImpl::GetProcessHostForSiteInstance(
spare_process_manager.PrepareForFutureRequests(browser_context);
if (is_unmatched_service_worker) {
- UnmatchedServiceWorkerProcessTracker::Register(
- browser_context, render_process_host, site_url);
+ UnmatchedServiceWorkerProcessTracker::Register(render_process_host,
+ site_instance);
}
// Make sure the chosen process is in the correct StoragePartition for the
@@ -4083,22 +4223,6 @@ void RenderProcessHostImpl::ReleaseOnCloseACK(
holder->Hold(sessions, view_route_id);
}
-void RenderProcessHostImpl::ShutdownRequest() {
- // Notify any contents that the renderer might shut down.
- for (auto& observer : observers_) {
- observer.RenderProcessShutdownRequested(this);
- }
-
- // Don't shut down if there are active RenderViews, or if there are pending
- // RenderViews being swapped back in.
- // In single process mode, we never shutdown the renderer.
- if (pending_views_ || run_renderer_in_process() || GetActiveViewCount() > 0) {
- return;
- }
-
- child_control_interface_->ProcessShutdown();
-}
-
void RenderProcessHostImpl::SuddenTerminationChanged(bool enabled) {
SetSuddenTerminationAllowed(enabled);
}
@@ -4106,6 +4230,7 @@ void RenderProcessHostImpl::SuddenTerminationChanged(bool enabled) {
void RenderProcessHostImpl::UpdateProcessPriorityInputs() {
int32_t new_visible_widgets_count = 0;
unsigned int new_frame_depth = kMaxFrameDepthForPriority;
+ bool new_intersects_viewport = false;
#if defined(OS_ANDROID)
ChildProcessImportance new_effective_importance =
ChildProcessImportance::NORMAL;
@@ -4118,12 +4243,17 @@ void RenderProcessHostImpl::UpdateProcessPriorityInputs() {
if (priority.is_hidden) {
if (!new_visible_widgets_count) {
new_frame_depth = std::min(new_frame_depth, priority.frame_depth);
+ new_intersects_viewport =
+ new_intersects_viewport || priority.intersects_viewport;
}
} else {
if (new_visible_widgets_count) {
new_frame_depth = std::min(new_frame_depth, priority.frame_depth);
+ new_intersects_viewport =
+ new_intersects_viewport || priority.intersects_viewport;
} else {
new_frame_depth = priority.frame_depth;
+ new_intersects_viewport = priority.intersects_viewport;
}
new_visible_widgets_count++;
}
@@ -4135,16 +4265,16 @@ void RenderProcessHostImpl::UpdateProcessPriorityInputs() {
}
bool inputs_changed = new_visible_widgets_count != visible_clients_;
-
// Hide this update behind the ShouldBoostPriorityForPendingViews() experiment
// at the moment to avoid causing an undesired early UpdateProcessPriority().
// See the comment in OnProcessLaunched() and https://crbug.com/560446.
if (ShouldBoostPriorityForPendingViews()) {
- inputs_changed = inputs_changed || frame_depth_ != new_frame_depth;
+ inputs_changed = inputs_changed || frame_depth_ != new_frame_depth ||
+ intersects_viewport_ != new_intersects_viewport;
}
-
visible_clients_ = new_visible_widgets_count;
frame_depth_ = new_frame_depth;
+ intersects_viewport_ = new_intersects_viewport;
#if defined(OS_ANDROID)
inputs_changed =
inputs_changed || new_effective_importance != effective_importance_;
@@ -4167,7 +4297,7 @@ void RenderProcessHostImpl::UpdateProcessPriority() {
const ChildProcessLauncherPriority priority(
visible_clients_ > 0 || base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableRendererBackgrounding),
- media_stream_count_ > 0, frame_depth_,
+ media_stream_count_ > 0, frame_depth_, intersects_viewport_,
!!pending_views_ /* boost_for_pending_views */,
#if defined(OS_ANDROID)
// Same hack as in RenderProcessHostImpl::RenderProcessHostImpl.
@@ -4362,9 +4492,11 @@ RenderProcessHost* RenderProcessHostImpl::GetDefaultSubframeProcessHost(
}
// static
-RenderProcessHost* RenderProcessHostImpl::FindReusableProcessHostForSite(
- BrowserContext* browser_context,
- const GURL& site_url) {
+RenderProcessHost*
+RenderProcessHostImpl::FindReusableProcessHostForSiteInstance(
+ SiteInstanceImpl* site_instance) {
+ BrowserContext* browser_context = site_instance->GetBrowserContext();
+ GURL site_url(site_instance->GetSiteURL());
if (!ShouldFindReusableProcessHostForSite(browser_context, site_url))
return nullptr;
@@ -4377,8 +4509,8 @@ RenderProcessHost* RenderProcessHostImpl::FindReusableProcessHostForSite(
static_cast<SiteProcessCountTracker*>(
browser_context->GetUserData(kPendingSiteProcessCountTrackerKey));
if (pending_tracker) {
- pending_tracker->FindRenderProcessesForSite(
- site_url, &eligible_foreground_hosts, &eligible_background_hosts);
+ pending_tracker->FindRenderProcessesForSiteInstance(
+ site_instance, &eligible_foreground_hosts, &eligible_background_hosts);
}
if (eligible_foreground_hosts.empty()) {
@@ -4388,8 +4520,9 @@ RenderProcessHost* RenderProcessHostImpl::FindReusableProcessHostForSite(
static_cast<SiteProcessCountTracker*>(
browser_context->GetUserData(kCommittedSiteProcessCountTrackerKey));
if (committed_tracker) {
- committed_tracker->FindRenderProcessesForSite(
- site_url, &eligible_foreground_hosts, &eligible_background_hosts);
+ committed_tracker->FindRenderProcessesForSiteInstance(
+ site_instance, &eligible_foreground_hosts,
+ &eligible_background_hosts);
}
}
diff --git a/chromium/content/browser/renderer_host/render_process_host_impl.h b/chromium/content/browser/renderer_host/render_process_host_impl.h
index 582d8037c2b..37bc9b79afd 100644
--- a/chromium/content/browser/renderer_host/render_process_host_impl.h
+++ b/chromium/content/browser/renderer_host/render_process_host_impl.h
@@ -28,14 +28,13 @@
#include "content/browser/cache_storage/cache_storage_dispatcher_host.h"
#include "content/browser/child_process_launcher.h"
#include "content/browser/dom_storage/session_storage_namespace_impl.h"
+#include "content/browser/media/video_decoder_proxy.h"
#include "content/browser/renderer_host/embedded_frame_sink_provider_impl.h"
#include "content/browser/renderer_host/frame_sink_provider_impl.h"
#include "content/browser/renderer_host/media/renderer_audio_output_stream_factory_context_impl.h"
-#include "content/common/associated_interface_registry_impl.h"
#include "content/common/associated_interfaces.mojom.h"
#include "content/common/child_control.mojom.h"
#include "content/common/content_export.h"
-#include "content/common/indexed_db/indexed_db.mojom.h"
#include "content/common/media/media_stream.mojom.h"
#include "content/common/media/renderer_audio_output_stream_factory.mojom.h"
#include "content/common/renderer.mojom.h"
@@ -53,9 +52,12 @@
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/mojom/service.mojom.h"
-#include "services/ui/public/interfaces/gpu.mojom.h"
#include "services/viz/public/interfaces/compositing/compositing_mode_watcher.mojom.h"
+#include "services/ws/public/mojom/gpu.mojom.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
+#include "third_party/blink/public/mojom/associated_interfaces/associated_interfaces.mojom.h"
#include "third_party/blink/public/mojom/dom_storage/storage_partition_service.mojom.h"
+#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/gl/gpu_switching_observer.h"
@@ -69,10 +71,14 @@ class MessageLoop;
class SharedPersistentMemoryAllocator;
}
+namespace viz {
+class GpuClient;
+}
+
namespace content {
class BrowserPluginMessageFilter;
class ChildConnection;
-class GpuClientImpl;
+class FileSystemManagerImpl;
class IndexedDBDispatcherHost;
class InProcessChildThreadParams;
class MediaStreamTrackMetricsHost;
@@ -121,7 +127,7 @@ class CONTENT_EXPORT RenderProcessHostImpl
public ChildProcessLauncher::Client,
public ui::GpuSwitchingObserver,
public mojom::RouteProvider,
- public mojom::AssociatedInterfaceProvider,
+ public blink::mojom::AssociatedInterfaceProvider,
public mojom::RendererHost {
public:
// Special depth used when there are no PriorityClients.
@@ -152,6 +158,7 @@ class CONTENT_EXPORT RenderProcessHostImpl
void UpdateClientPriority(PriorityClient* client) override;
int VisibleClientCount() const override;
unsigned int GetFrameDepth() const override;
+ bool GetIntersectsViewport() const override;
bool IsForGuestsOnly() const override;
StoragePartition* GetStoragePartition() const override;
bool Shutdown(int exit_code) override;
@@ -220,6 +227,7 @@ class CONTENT_EXPORT RenderProcessHostImpl
void LockToOrigin(const GURL& lock_url) override;
void BindCacheStorage(blink::mojom::CacheStorageRequest request,
const url::Origin& origin) override;
+ void CleanupCorbExceptionForPluginUponDestruction() override;
mojom::RouteProvider* GetRemoteRouteProvider();
@@ -261,11 +269,16 @@ class CONTENT_EXPORT RenderProcessHostImpl
// Implementation of FilterURL below that can be shared with the mock class.
static void FilterURL(RenderProcessHost* rph, bool empty_allowed, GURL* url);
- // Returns true if |host| is suitable for launching a new view with |site_url|
- // in the given |browser_context|.
+ // Returns true if |host| is suitable for rendering a page in the given
+ // |browser_context|, where the page would utilize |site_url| as its
+ // SiteInstance site URL, and its process would be locked to |lock_url|.
+ // |site_url| and |lock_url| may differ in cases where an effective URL is
+ // not the actual site that the process is locked to, which happens for
+ // hosted apps.
static bool IsSuitableHost(RenderProcessHost* host,
BrowserContext* browser_context,
- const GURL& site_url);
+ const GURL& site_url,
+ const GURL& lock_url);
// Returns an existing RenderProcessHost for |url| in |browser_context|,
// if one exists. Otherwise a new RenderProcessHost should be created and
@@ -273,25 +286,45 @@ class CONTENT_EXPORT RenderProcessHostImpl
// This should only be used for process-per-site mode, which can be enabled
// globally with a command line flag or per-site, as determined by
// SiteInstanceImpl::ShouldUseProcessPerSite.
- static RenderProcessHost* GetProcessHostForSite(
+ // Important: |url| should be a full URL and *not* a site URL.
+ static RenderProcessHost* GetSoleProcessHostForURL(
BrowserContext* browser_context,
const GURL& url);
- // Registers the given |process| to be used for any instance of |url|
- // within |browser_context|.
+ // Variant of the above that takes in a SiteInstance site URL and the
+ // process's origin lock URL, when they are known.
+ static RenderProcessHost* GetSoleProcessHostForSite(
+ BrowserContext* browser_context,
+ const GURL& site_url,
+ const GURL& lock_url);
+
+ // Registers the given |process| to be used for all sites identified by
+ // |site_instance| within |browser_context|.
// This should only be used for process-per-site mode, which can be enabled
// globally with a command line flag or per-site, as determined by
// SiteInstanceImpl::ShouldUseProcessPerSite.
- static void RegisterProcessHostForSite(
- BrowserContext* browser_context,
- RenderProcessHost* process,
- const GURL& url);
+ static void RegisterSoleProcessHostForSite(BrowserContext* browser_context,
+ RenderProcessHost* process,
+ SiteInstanceImpl* site_instance);
// Returns a suitable RenderProcessHost to use for |site_instance|. Depending
// on the SiteInstance's ProcessReusePolicy and its url, this may be an
// existing RenderProcessHost or a new one.
+ //
+ // This is the main entrypoint into the process assignment logic, which
+ // handles all cases. These cases include:
+ // - process-per-site: see
+ // RegisterSoleProcessHostForSite/GetSoleProcessHostForSite.
+ // - TDI: see GetDefaultSubframeProcessHost.
+ // - REUSE_PENDING_OR_COMMITTED reuse policy (for ServiceWorkers and OOPIFs):
+ // see FindReusableProcessHostForSiteInstance.
+ // - normal process reuse when over process limit: see
+ // GetExistingProcessHost.
+ // - using the spare RenderProcessHost when possible: see
+ // MaybeTakeSpareRenderProcessHost.
+ // - process creation when an existing process couldn't be found: see
+ // CreateRenderProcessHost.
static RenderProcessHost* GetProcessHostForSiteInstance(
- BrowserContext* browser_context,
SiteInstanceImpl* site_instance);
// Should be called when |browser_context| is used in a navigation.
@@ -412,6 +445,15 @@ class CONTENT_EXPORT RenderProcessHostImpl
// before the process shuts down.
void DelayProcessShutdownForUnload(const base::TimeDelta& timeout);
+ FileSystemManagerImpl* GetFileSystemManagerForTesting() {
+ return file_system_manager_impl_.get();
+ }
+
+ // Adds a CORB (Cross-Origin Read Blocking) exception for |process_id|. The
+ // exception will be removed when the corresponding RenderProcessHostImpl is
+ // destroyed (see |cleanup_corb_exception_for_plugin_upon_destruction_|).
+ static void AddCorbExceptionForPlugin(int process_id);
+
protected:
// A proxy for our IPC::Channel that lives on the IO thread.
std::unique_ptr<IPC::ChannelProxy> channel_;
@@ -436,7 +478,6 @@ class CONTENT_EXPORT RenderProcessHostImpl
friend class ChildProcessLauncherBrowserTest_ChildSpawnFail_Test;
friend class VisitRelayingRenderProcessHost;
friend class StoragePartitonInterceptor;
- friend class SecurityExploitBrowserTest;
class ConnectionFilterController;
class ConnectionFilterImpl;
@@ -461,14 +502,14 @@ class CONTENT_EXPORT RenderProcessHostImpl
void RegisterMojoInterfaces();
// mojom::RouteProvider:
- void GetRoute(
- int32_t routing_id,
- mojom::AssociatedInterfaceProviderAssociatedRequest request) override;
+ void GetRoute(int32_t routing_id,
+ blink::mojom::AssociatedInterfaceProviderAssociatedRequest
+ request) override;
- // mojom::AssociatedInterfaceProvider:
+ // blink::mojom::AssociatedInterfaceProvider:
void GetAssociatedInterface(
const std::string& name,
- mojom::AssociatedInterfaceAssociatedRequest request) override;
+ blink::mojom::AssociatedInterfaceAssociatedRequest request) override;
// mojom::RendererHost
using BrowserHistogramCallback =
@@ -476,7 +517,6 @@ class CONTENT_EXPORT RenderProcessHostImpl
void GetBrowserHistogram(const std::string& name,
BrowserHistogramCallback callback) override;
void SuddenTerminationChanged(bool enabled) override;
- void ShutdownRequest() override;
void BindRouteProvider(mojom::RouteProviderAssociatedRequest request);
@@ -488,6 +528,7 @@ class CONTENT_EXPORT RenderProcessHostImpl
void CreateStoragePartitionService(
blink::mojom::StoragePartitionServiceRequest request);
void CreateRendererHost(mojom::RendererHostAssociatedRequest request);
+ void BindVideoDecoderService(media::mojom::InterfaceFactoryRequest request);
// Control message handlers.
void OnUserMetricsRecordAction(const std::string& action);
@@ -543,20 +584,19 @@ class CONTENT_EXPORT RenderProcessHostImpl
// Get an existing RenderProcessHost associated with the given browser
// context, if possible. The renderer process is chosen randomly from
// suitable renderers that share the same context and type (determined by the
- // site url).
+ // site url of |site_instance|).
// Returns nullptr if no suitable renderer process is available, in which case
// the caller is free to create a new renderer.
static RenderProcessHost* GetExistingProcessHost(
- content::BrowserContext* browser_context,
- const GURL& site_url);
+ SiteInstanceImpl* site_instance);
FRIEND_TEST_ALL_PREFIXES(RenderProcessHostUnitTest,
GuestsAreNotSuitableHosts);
- // Returns a RenderProcessHost that is rendering |site_url| in one of its
- // frames, or that is expecting a navigation to |site_url|.
- static RenderProcessHost* FindReusableProcessHostForSite(
- BrowserContext* browser_context,
- const GURL& site_url);
+ // Returns a RenderProcessHost that is rendering a URL corresponding to
+ // |site_instance| in one of its frames, or that is expecting a navigation to
+ // that SiteInstance.
+ static RenderProcessHost* FindReusableProcessHostForSiteInstance(
+ SiteInstanceImpl* site_instance);
void CreateMediaStreamDispatcherHost(
MediaStreamManager* media_stream_manager,
@@ -646,10 +686,10 @@ class CONTENT_EXPORT RenderProcessHostImpl
// Mojo interfaces provided to the child process are registered here if they
// need consistent delivery ordering with legacy IPC, and are process-wide in
// nature (e.g. metrics, memory usage).
- std::unique_ptr<AssociatedInterfaceRegistryImpl> associated_interfaces_;
+ std::unique_ptr<blink::AssociatedInterfaceRegistry> associated_interfaces_;
mojo::AssociatedBinding<mojom::RouteProvider> route_provider_binding_;
- mojo::AssociatedBindingSet<mojom::AssociatedInterfaceProvider, int32_t>
+ mojo::AssociatedBindingSet<blink::mojom::AssociatedInterfaceProvider, int32_t>
associated_interface_provider_bindings_;
// These fields are cached values that are updated in
@@ -662,6 +702,10 @@ class CONTENT_EXPORT RenderProcessHostImpl
// widgets the lowest depth of all hidden clients. Initialized to max depth
// when there are no clients.
unsigned int frame_depth_ = kMaxFrameDepthForPriority;
+ // |intersects_viewport_| similar to |frame_depth_| can be used to rank
+ // processes of same visibility. It indicates process has frames that
+ // intersect with the viewport.
+ bool intersects_viewport_ = false;
#if defined(OS_ANDROID)
// Highest importance of all clients that contribute priority.
ChildProcessImportance effective_importance_ = ChildProcessImportance::NORMAL;
@@ -715,7 +759,7 @@ class CONTENT_EXPORT RenderProcessHostImpl
StoragePartitionImpl* storage_partition_impl_;
// The observers watching our lifetime.
- base::ObserverList<RenderProcessHostObserver> observers_;
+ base::ObserverList<RenderProcessHostObserver>::Unchecked observers_;
// True if the process can be shut down suddenly. If this is true, then we're
// sure that all the RenderViews in the process can be shutdown suddenly. If
@@ -757,7 +801,7 @@ class CONTENT_EXPORT RenderProcessHostImpl
BrowserThread::DeleteOnIOThread>
audio_output_stream_factory_context_;
- scoped_refptr<P2PSocketDispatcherHost> p2p_socket_dispatcher_host_;
+ std::unique_ptr<P2PSocketDispatcherHost> p2p_socket_dispatcher_host_;
// Must be accessed on UI thread.
std::vector<int> aec_dump_consumers_;
@@ -771,6 +815,8 @@ class CONTENT_EXPORT RenderProcessHostImpl
std::unique_ptr<MediaStreamTrackMetricsHost, BrowserThread::DeleteOnIOThread>
media_stream_track_metrics_host_;
+ std::unique_ptr<VideoDecoderProxy> video_decoder_proxy_;
+
// Forwards messages between WebRTCInternals in the browser process
// and PeerConnectionTracker in the renderer process.
// It holds a raw pointer to webrtc_eventlog_host_, and therefore should be
@@ -808,7 +854,9 @@ class CONTENT_EXPORT RenderProcessHostImpl
#endif
scoped_refptr<ResourceMessageFilter> resource_message_filter_;
- std::unique_ptr<GpuClientImpl, BrowserThread::DeleteOnIOThread> gpu_client_;
+ std::unique_ptr<FileSystemManagerImpl, BrowserThread::DeleteOnIOThread>
+ file_system_manager_impl_;
+ std::unique_ptr<viz::GpuClient, BrowserThread::DeleteOnIOThread> gpu_client_;
std::unique_ptr<PushMessagingManager, BrowserThread::DeleteOnIOThread>
push_messaging_manager_;
@@ -837,6 +885,8 @@ class CONTENT_EXPORT RenderProcessHostImpl
std::unique_ptr<mojo::Binding<viz::mojom::CompositingModeReporter>>
compositing_mode_reporter_;
+ bool cleanup_corb_exception_for_plugin_upon_destruction_ = false;
+
base::WeakPtrFactory<RenderProcessHostImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(RenderProcessHostImpl);
diff --git a/chromium/content/browser/renderer_host/render_process_host_unittest.cc b/chromium/content/browser/renderer_host/render_process_host_unittest.cc
index b036f1a9a31..9a91cd8279e 100644
--- a/chromium/content/browser/renderer_host/render_process_host_unittest.cc
+++ b/chromium/content/browser/renderer_host/render_process_host_unittest.cc
@@ -42,12 +42,16 @@ TEST_F(RenderProcessHostUnitTest, GuestsAreNotSuitableHosts) {
MockRenderProcessHost guest_host(browser_context());
guest_host.set_is_for_guests_only(true);
+ scoped_refptr<SiteInstanceImpl> site_instance =
+ SiteInstanceImpl::CreateForURL(browser_context(), test_url);
EXPECT_FALSE(RenderProcessHostImpl::IsSuitableHost(
- &guest_host, browser_context(), test_url));
+ &guest_host, browser_context(), site_instance->GetSiteURL(),
+ site_instance->lock_url()));
EXPECT_TRUE(RenderProcessHostImpl::IsSuitableHost(
- process(), browser_context(), test_url));
- EXPECT_EQ(process(), RenderProcessHostImpl::GetExistingProcessHost(
- browser_context(), test_url));
+ process(), browser_context(), site_instance->GetSiteURL(),
+ site_instance->lock_url()));
+ EXPECT_EQ(process(),
+ RenderProcessHostImpl::GetExistingProcessHost(site_instance.get()));
}
#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
diff --git a/chromium/content/browser/renderer_host/render_view_host_impl.cc b/chromium/content/browser/renderer_host/render_view_host_impl.cc
index 1f491537c8f..a25a92f7eb0 100644
--- a/chromium/content/browser/renderer_host/render_view_host_impl.cc
+++ b/chromium/content/browser/renderer_host/render_view_host_impl.cc
@@ -481,11 +481,18 @@ WebPreferences RenderViewHostImpl::ComputeWebkitPrefs() {
NOTREACHED();
}
+ // On Android, Touch event feature detection is enabled by default,
+ // Otherwise default is disabled.
+ std::string touch_enabled_default_switch =
+ switches::kTouchEventFeatureDetectionDisabled;
+#if defined(OS_ANDROID)
+ touch_enabled_default_switch = switches::kTouchEventFeatureDetectionEnabled;
+#endif // defined(OS_ANDROID)
const std::string touch_enabled_switch =
command_line.HasSwitch(switches::kTouchEventFeatureDetection)
? command_line.GetSwitchValueASCII(
switches::kTouchEventFeatureDetection)
- : switches::kTouchEventFeatureDetectionAuto;
+ : touch_enabled_default_switch;
prefs.touch_event_feature_detection_enabled =
(touch_enabled_switch == switches::kTouchEventFeatureDetectionAuto)
? (ui::GetTouchScreensAvailability() ==
@@ -493,6 +500,7 @@ WebPreferences RenderViewHostImpl::ComputeWebkitPrefs() {
: (touch_enabled_switch.empty() ||
touch_enabled_switch ==
switches::kTouchEventFeatureDetectionEnabled);
+
std::tie(prefs.available_pointer_types, prefs.available_hover_types) =
ui::GetAvailablePointerAndHoverTypes();
prefs.primary_pointer_type =
@@ -906,14 +914,14 @@ void RenderViewHostImpl::OnFocus() {
void RenderViewHostImpl::RenderWidgetDidForwardMouseEvent(
const blink::WebMouseEvent& mouse_event) {
if (mouse_event.GetType() == WebInputEvent::kMouseWheel &&
- GetWidget()->ignore_input_events()) {
+ GetWidget()->IsIgnoringInputEvents()) {
delegate_->OnIgnoredUIEvent();
}
}
bool RenderViewHostImpl::MayRenderWidgetForwardKeyboardEvent(
const NativeWebKeyboardEvent& key_event) {
- if (GetWidget()->ignore_input_events()) {
+ if (GetWidget()->IsIgnoringInputEvents()) {
if (key_event.GetType() == WebInputEvent::kRawKeyDown)
delegate_->OnIgnoredUIEvent();
return false;
diff --git a/chromium/content/browser/renderer_host/render_widget_host_delegate.cc b/chromium/content/browser/renderer_host/render_widget_host_delegate.cc
index 00c3a8c727d..aa01d7b2207 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_delegate.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_delegate.cc
@@ -17,11 +17,20 @@ KeyboardEventProcessingResult RenderWidgetHostDelegate::PreHandleKeyboardEvent(
return KeyboardEventProcessingResult::NOT_HANDLED;
}
+bool RenderWidgetHostDelegate::PreHandleMouseEvent(
+ const blink::WebMouseEvent& event) {
+ return false;
+}
+
bool RenderWidgetHostDelegate::HandleWheelEvent(
const blink::WebMouseWheelEvent& event) {
return false;
}
+bool RenderWidgetHostDelegate::ShouldIgnoreInputEvents() {
+ return false;
+}
+
bool RenderWidgetHostDelegate::PreHandleGestureEvent(
const blink::WebGestureEvent& event) {
return false;
diff --git a/chromium/content/browser/renderer_host/render_widget_host_delegate.h b/chromium/content/browser/renderer_host/render_widget_host_delegate.h
index b054514ea74..387c81db0e0 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_delegate.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_delegate.h
@@ -23,6 +23,7 @@
#include "ui/gfx/range/range.h"
namespace blink {
+class WebMouseEvent;
class WebMouseWheelEvent;
class WebGestureEvent;
}
@@ -89,6 +90,13 @@ class CONTENT_EXPORT RenderWidgetHostDelegate {
virtual KeyboardEventProcessingResult PreHandleKeyboardEvent(
const NativeWebKeyboardEvent& event);
+ // Callback to give the browser a chance to handle the specified mouse
+ // event before sending it to the renderer.
+ // Returns true if the |event| was handled.
+ // TODO(carlosil, nasko): remove once committed interstitial pages are
+ // fully implemented.
+ virtual bool PreHandleMouseEvent(const blink::WebMouseEvent& event);
+
// Callback to inform the browser that the renderer did not process the
// specified events. This gives an opportunity to the browser to process the
// event (used for keyboard shortcuts).
@@ -104,6 +112,9 @@ class CONTENT_EXPORT RenderWidgetHostDelegate {
virtual void DidReceiveInputEvent(RenderWidgetHostImpl* render_widget_host,
const blink::WebInputEvent::Type type) {}
+ // Asks whether the page is in a state of ignoring input events.
+ virtual bool ShouldIgnoreInputEvents();
+
// Callback to give the browser a chance to handle the specified gesture
// event before sending it to the renderer.
// Returns true if the |event| was handled.
@@ -138,7 +149,8 @@ class CONTENT_EXPORT RenderWidgetHostDelegate {
#if defined(OS_MACOSX)
virtual void DidChangeTextSelection(const base::string16& text,
- const gfx::Range& range) {}
+ const gfx::Range& range,
+ size_t offset) {}
#endif
// Request the renderer to Move the caret to the new position.
@@ -272,6 +284,7 @@ class CONTENT_EXPORT RenderWidgetHostDelegate {
// Get the UKM source ID for current content. This is used for providing
// data about the content to the URL-keyed metrics service.
+ // Note: This is also exposed by the RenderFrameHostDelegate.
virtual ukm::SourceId GetUkmSourceIdForLastCommittedSource() const;
// Notifies the delegate that a focused editable element has been touched
@@ -283,9 +296,6 @@ class CONTENT_EXPORT RenderWidgetHostDelegate {
// not a WebContents, returns nullptr.
virtual WebContents* GetAsWebContents();
- // Notifies that a CompositorFrame was received from the renderer.
- virtual void DidReceiveCompositorFrame() {}
-
// Gets the size set by a top-level frame with auto-resize enabled.
virtual gfx::Size GetAutoResizeSize();
diff --git a/chromium/content/browser/renderer_host/render_widget_host_impl.cc b/chromium/content/browser/renderer_host/render_widget_host_impl.cc
index 9ab96c3f933..437b43ade73 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_impl.cc
@@ -27,7 +27,7 @@
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/default_tick_clock.h"
#include "base/trace_event/trace_event.h"
@@ -292,7 +292,8 @@ class UnboundWidgetInputHandler : public mojom::WidgetInputHandler {
void ImeCommitText(const base::string16& text,
const std::vector<ui::ImeTextSpan>& ime_text_spans,
const gfx::Range& range,
- int32_t relative_cursor_position) override {
+ int32_t relative_cursor_position,
+ ImeCommitTextCallback callback) override {
DLOG(WARNING) << "Input request on unbound interface";
}
void ImeFinishComposingText(bool keep_selection) override {
@@ -350,7 +351,6 @@ RenderWidgetHostImpl::RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
is_unresponsive_(false),
in_flight_event_count_(0),
in_get_backing_store_(false),
- ignore_input_events_(false),
text_direction_updated_(false),
text_direction_(blink::kWebTextDirectionLeftToRight),
text_direction_canceled_(false),
@@ -407,8 +407,8 @@ RenderWidgetHostImpl::RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
const auto* command_line = base::CommandLine::ForCurrentProcess();
if (!command_line->HasSwitch(switches::kDisableHangMonitor)) {
input_event_ack_timeout_.reset(new TimeoutMonitor(
- base::Bind(&RenderWidgetHostImpl::RendererIsUnresponsive,
- weak_factory_.GetWeakPtr())));
+ base::BindRepeating(&RenderWidgetHostImpl::OnInputEventAckTimeout,
+ weak_factory_.GetWeakPtr())));
}
if (!command_line->HasSwitch(switches::kDisableNewContentRenderingTimeout)) {
@@ -570,6 +570,14 @@ void RenderWidgetHostImpl::SetFrameDepth(unsigned int depth) {
UpdatePriority();
}
+void RenderWidgetHostImpl::SetIntersectsViewport(bool intersects) {
+ if (intersects_viewport_ == intersects)
+ return;
+
+ intersects_viewport_ = intersects;
+ UpdatePriority();
+}
+
void RenderWidgetHostImpl::UpdatePriority() {
if (!destroyed_)
process_->UpdateClientPriority(this);
@@ -672,8 +680,6 @@ bool RenderWidgetHostImpl::OnMessageReceived(const IPC::Message &msg) {
OnTextInputStateChanged)
IPC_MESSAGE_HANDLER(ViewHostMsg_LockMouse, OnLockMouse)
IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse, OnUnlockMouse)
- IPC_MESSAGE_HANDLER(ViewHostMsg_ShowDisambiguationPopup,
- OnShowDisambiguationPopup)
IPC_MESSAGE_HANDLER(ViewHostMsg_SelectionBoundsChanged,
OnSelectionBoundsChanged)
IPC_MESSAGE_HANDLER(ViewHostMsg_FocusedNodeTouched, OnFocusedNodeTouched)
@@ -1189,19 +1195,8 @@ void RenderWidgetHostImpl::DidNavigate(uint32_t next_source_id) {
// |visual_properties_ack_pending_| and make sure the next resize will be
// acked if the last resize before navigation was supposed to be acked.
visual_properties_ack_pending_ = false;
- viz::LocalSurfaceId old_surface_id = view_->GetLocalSurfaceId();
if (view_)
view_->DidNavigate();
- viz::LocalSurfaceId new_surface_id = view_->GetLocalSurfaceId();
- // If |view_| didn't allocate a new surface id, then don't start
- // |new_content_rendering_timeout_|. Two reasons:
- // 1. It's not needed (because this was the first navigation event)
- // 2. If we don't change the surface id, then we will not get the call to
- // OnFirstSurfaceActivation, and not stop the timer (even if we get new
- // frames).
- // https://crbug.com/853651, https://crbug.com/535375
- if (old_surface_id == new_surface_id)
- return;
} else {
// It is possible for a compositor frame to arrive before the browser is
// notified about the page being committed, in which case no timer is
@@ -1247,7 +1242,11 @@ void RenderWidgetHostImpl::ForwardMouseEventWithLatencyInfo(
return;
}
- if (ShouldDropInputEvents())
+ if (IsIgnoringInputEvents())
+ return;
+
+ // Delegate must be non-null, due to |IsIgnoringInputEvents()| test.
+ if (delegate_->PreHandleMouseEvent(mouse_event))
return;
auto* touch_emulator = GetExistingTouchEmulator();
@@ -1273,7 +1272,7 @@ void RenderWidgetHostImpl::ForwardWheelEventWithLatencyInfo(
TRACE_EVENT2("input", "RenderWidgetHostImpl::ForwardWheelEvent", "dx",
wheel_event.delta_x, "dy", wheel_event.delta_y);
- if (ShouldDropInputEvents())
+ if (IsIgnoringInputEvents())
return;
auto* touch_emulator = GetExistingTouchEmulator();
@@ -1304,7 +1303,7 @@ void RenderWidgetHostImpl::ForwardGestureEventWithLatencyInfo(
TRACE_EVENT1("input", "RenderWidgetHostImpl::ForwardGestureEvent", "type",
WebInputEvent::GetName(gesture_event.GetType()));
// Early out if necessary, prior to performing latency logic.
- if (ShouldDropInputEvents())
+ if (IsIgnoringInputEvents())
return;
bool scroll_update_needs_wrapping = false;
@@ -1393,7 +1392,7 @@ void RenderWidgetHostImpl::ForwardGestureEventWithLatencyInfo(
gesture_event));
}
- // Delegate must be non-null, due to |ShouldDropInputEvents()| test.
+ // Delegate must be non-null, due to |IsIgnoringInputEvents()| test.
if (delegate_->PreHandleGestureEvent(gesture_event))
return;
@@ -1459,7 +1458,7 @@ void RenderWidgetHostImpl::ForwardKeyboardEventWithCommands(
return;
}
- if (ShouldDropInputEvents())
+ if (IsIgnoringInputEvents())
return;
if (!process_->IsInitializedAndNotDead())
@@ -1722,6 +1721,7 @@ RenderProcessHost::Priority RenderWidgetHostImpl::GetPriority() {
RenderProcessHost::Priority priority = {
is_hidden_,
frame_depth_,
+ intersects_viewport_,
#if defined(OS_ANDROID)
importance_,
#endif
@@ -1982,8 +1982,9 @@ void RenderWidgetHostImpl::ImeCommitText(
const std::vector<ui::ImeTextSpan>& ime_text_spans,
const gfx::Range& replacement_range,
int relative_cursor_pos) {
- GetWidgetInputHandler()->ImeCommitText(
- text, ime_text_spans, replacement_range, relative_cursor_pos);
+ GetWidgetInputHandler()->ImeCommitText(text, ime_text_spans,
+ replacement_range, relative_cursor_pos,
+ base::OnceClosure());
}
void RenderWidgetHostImpl::ImeFinishComposingText(bool keep_selection) {
@@ -2077,18 +2078,24 @@ void RenderWidgetHostImpl::Destroy(bool also_delete) {
}
}
-void RenderWidgetHostImpl::RendererIsUnresponsive() {
+void RenderWidgetHostImpl::OnInputEventAckTimeout() {
+ RendererIsUnresponsive(base::BindRepeating(
+ &RenderWidgetHostImpl::RestartInputEventAckTimeoutIfNecessary,
+ weak_factory_.GetWeakPtr()));
+}
+
+void RenderWidgetHostImpl::RendererIsUnresponsive(
+ base::RepeatingClosure restart_hang_monitor_timeout) {
NotificationService::current()->Notify(
NOTIFICATION_RENDER_WIDGET_HOST_HANG,
Source<RenderWidgetHost>(this),
NotificationService::NoDetails());
is_unresponsive_ = true;
- if (delegate_)
- delegate_->RendererUnresponsive(
- this, base::BindRepeating(
- &RenderWidgetHostImpl::RestartInputEventAckTimeoutIfNecessary,
- weak_factory_.GetWeakPtr()));
+ if (delegate_) {
+ delegate_->RendererUnresponsive(this,
+ std::move(restart_hang_monitor_timeout));
+ }
// Do not add code after this since the Delegate may delete this
// RenderWidgetHostImpl in RendererUnresponsive.
@@ -2104,8 +2111,12 @@ void RenderWidgetHostImpl::RendererIsResponsive() {
void RenderWidgetHostImpl::ClearDisplayedGraphics() {
NotifyNewContentRenderingTimeoutForTesting();
- if (view_)
- view_->ClearCompositorFrame();
+ if (view_) {
+ if (enable_surface_synchronization_)
+ view_->ResetFallbackToFirstNavigationSurface();
+ else
+ view_->ClearCompositorFrame();
+ }
}
void RenderWidgetHostImpl::OnRenderProcessGone(int status, int exit_code) {
@@ -2225,7 +2236,7 @@ void RenderWidgetHostImpl::DidUpdateVisualProperties(
NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_VISUAL_PROPERTIES,
Source<RenderWidgetHost>(this), NotificationService::NoDetails());
- if (!view_ || is_hidden_)
+ if (!view_)
return;
viz::ScopedSurfaceIdAllocator scoped_allocator =
@@ -2321,8 +2332,10 @@ bool RenderWidgetHostImpl::IsWheelScrollInProgress() {
}
void RenderWidgetHostImpl::SetMouseCapture(bool capture) {
- if (delegate_)
- delegate_->GetInputEventRouter()->SetMouseCaptureTarget(GetView(), capture);
+ if (!delegate_ || !delegate_->GetInputEventRouter())
+ return;
+
+ delegate_->GetInputEventRouter()->SetMouseCaptureTarget(GetView(), capture);
}
void RenderWidgetHostImpl::OnInvalidFrameToken(uint32_t frame_token) {
@@ -2417,39 +2430,6 @@ RenderWidgetHostImpl::GetKeyboardLayoutMap() {
return view_->GetKeyboardLayoutMap();
}
-void RenderWidgetHostImpl::OnShowDisambiguationPopup(
- const gfx::Rect& rect_pixels,
- const gfx::Size& size,
- base::SharedMemoryHandle handle) {
- DCHECK(!rect_pixels.IsEmpty());
- DCHECK(!size.IsEmpty());
-
- SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height());
- size_t shm_size = info.computeMinByteSize();
-
- base::SharedMemory shm(handle, false /* read_only */);
- if (shm_size == 0 || !shm.Map(shm_size)) {
- bad_message::ReceivedBadMessage(GetProcess(),
- bad_message::RWH_SHARED_BITMAP);
- return;
- }
-
- SkBitmap zoomed_bitmap;
- zoomed_bitmap.installPixels(info, shm.memory(), info.minRowBytes());
-
- // Note that |rect| is in coordinates of pixels relative to the window origin.
- // Aura-based systems will want to convert this to DIPs.
- if (view_)
- view_->ShowDisambiguationPopup(rect_pixels, zoomed_bitmap);
-
- // It is assumed that the disambiguation popup will make a copy of the
- // provided zoomed image, so we delete |zoomed_bitmap| and free shared memory.
-}
-
-void RenderWidgetHostImpl::SetIgnoreInputEvents(bool ignore_input_events) {
- ignore_input_events_ = ignore_input_events;
-}
-
bool RenderWidgetHostImpl::KeyPressListenersHandleEvent(
const NativeWebKeyboardEvent& event) {
if (event.skip_in_browser || event.GetType() != WebKeyboardEvent::kRawKeyDown)
@@ -2477,7 +2457,7 @@ InputEventAckState RenderWidgetHostImpl::FilterInputEvent(
// Don't ignore touch cancel events, since they may be sent while input
// events are being ignored in order to keep the renderer from getting
// confused about how many touches are active.
- if (ShouldDropInputEvents() && event.GetType() != WebInputEvent::kTouchCancel)
+ if (IsIgnoringInputEvents() && event.GetType() != WebInputEvent::kTouchCancel)
return INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS;
if (!process_->IsInitializedAndNotDead())
@@ -2626,13 +2606,16 @@ void RenderWidgetHostImpl::OnTouchEventAck(
for (auto& input_event_observer : input_event_observers_)
input_event_observer.OnInputEventAck(ack_source, ack_result, event.event);
- auto* touch_emulator = GetExistingTouchEmulator();
- if (touch_emulator &&
- touch_emulator->HandleTouchEventAck(event.event, ack_result)) {
- return;
- }
+ auto* input_event_router =
+ delegate() ? delegate()->GetInputEventRouter() : nullptr;
- if (view_)
+ // At present interstitial pages might not have an input event router, so we
+ // just have the view process the ack directly in that case; the view is
+ // guaranteed to be a top-level view with an appropriate implementation of
+ // ProcessAckedTouchEvent().
+ if (input_event_router)
+ input_event_router->ProcessAckedTouchEvent(event, ack_result, view_.get());
+ else if (view_)
view_->ProcessAckedTouchEvent(event, ack_result);
}
@@ -2644,8 +2627,9 @@ void RenderWidgetHostImpl::OnUnexpectedEventAck(UnexpectedEventAckType type) {
}
}
-bool RenderWidgetHostImpl::ShouldDropInputEvents() const {
- return ignore_input_events_ || process_->IgnoreInputEvents() || !delegate_;
+bool RenderWidgetHostImpl::IsIgnoringInputEvents() const {
+ return process_->IgnoreInputEvents() || !delegate_ ||
+ delegate_->ShouldIgnoreInputEvents();
}
void RenderWidgetHostImpl::SetBackgroundOpaque(bool opaque) {
@@ -2988,9 +2972,6 @@ void RenderWidgetHostImpl::SubmitCompositorFrame(
}
}
}
-
- if (delegate_)
- delegate_->DidReceiveCompositorFrame();
}
void RenderWidgetHostImpl::DidProcessFrame(uint32_t frame_token) {
@@ -3075,16 +3056,6 @@ void RenderWidgetHostImpl::ProgressFlingIfNeeded(TimeTicks current_time) {
fling_scheduler_->ProgressFlingOnBeginFrameIfneeded(current_time);
}
-void RenderWidgetHostImpl::DidReceiveFirstFrameAfterNavigation() {
- DCHECK(enable_surface_synchronization_);
- did_receive_first_frame_after_navigation_ = true;
- if (!new_content_rendering_timeout_ ||
- !new_content_rendering_timeout_->IsRunning()) {
- return;
- }
- new_content_rendering_timeout_->Stop();
-}
-
void RenderWidgetHostImpl::ForceFirstFrameAfterNavigationTimeout() {
if (did_receive_first_frame_after_navigation_ ||
!new_content_rendering_timeout_) {
diff --git a/chromium/content/browser/renderer_host/render_widget_host_impl.h b/chromium/content/browser/renderer_host/render_widget_host_impl.h
index 4af5870e7c4..c2d8cd56243 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_impl.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_impl.h
@@ -199,7 +199,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl
RenderWidgetHostViewBase* GetView() const override;
bool IsLoading() const override;
bool IsCurrentlyUnresponsive() const override;
- void SetIgnoreInputEvents(bool ignore_input_events) override;
bool SynchronizeVisualProperties() override;
void AddKeyPressEventCallback(const KeyPressEventCallback& callback) override;
void RemoveKeyPressEventCallback(
@@ -288,6 +287,7 @@ class CONTENT_EXPORT RenderWidgetHostImpl
}
void SetFrameDepth(unsigned int depth);
+ void SetIntersectsViewport(bool intersects);
void UpdatePriority();
// Tells the renderer to die and optionally delete |this|.
@@ -479,12 +479,8 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// Cancels an ongoing composition.
void ImeCancelComposition();
- bool ignore_input_events() const {
- return ignore_input_events_;
- }
-
- // Whether forwarded WebInputEvents should be dropped.
- bool ShouldDropInputEvents() const;
+ // Whether forwarded WebInputEvents are being ignored.
+ bool IsIgnoringInputEvents() const;
bool has_touch_handler() const { return has_touch_handler_; }
@@ -683,8 +679,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl
bool FlingCancellationIsDeferred() const;
void SetNeedsBeginFrameForFlingProgress();
- void DidReceiveFirstFrameAfterNavigation();
-
// The RenderWidgetHostImpl will keep showing the old page (for a while) after
// navigation until the first frame of the new page arrives. This reduces
// flicker. However, if for some reason it is known that the frames won't be
@@ -712,10 +706,21 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// Returns the keyboard layout mapping.
base::flat_map<std::string, std::string> GetKeyboardLayoutMap();
- void DidStopFlinging() override;
+ void DidStopFlinging();
void GetContentRenderingTimeoutFrom(RenderWidgetHostImpl* other);
+ // Called on delayed response from the renderer by either
+ // 1) |hang_monitor_timeout_| (slow to ack input events) or
+ // 2) NavigationHandle::OnCommitTimeout (slow to commit).
+ void RendererIsUnresponsive(
+ base::RepeatingClosure restart_hang_monitor_timeout);
+
+ // Called if we know the renderer is responsive. When we currently think the
+ // renderer is unresponsive, this will clear that state and call
+ // NotifyRendererResponsive.
+ void RendererIsResponsive();
+
protected:
// ---------------------------------------------------------------------------
// The following method is overridden by RenderViewHost to send upwards to
@@ -793,18 +798,10 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// destructor is called as well.
void Destroy(bool also_delete);
- // Called by |input_event_ack_timeout_| on delayed response from the renderer.
- void RendererIsUnresponsive();
-
// Called by |new_content_rendering_timeout_| if a renderer has loaded new
// content but failed to produce a compositor frame in a defined time.
void ClearDisplayedGraphics();
- // Called if we know the renderer is responsive. When we currently think the
- // renderer is unresponsive, this will clear that state and call
- // NotifyRendererResponsive.
- void RendererIsResponsive();
-
// IPC message handlers
void OnRenderProcessGone(int status, int error_code);
void OnClose();
@@ -821,9 +818,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl
void OnLockMouse(bool user_gesture,
bool privileged);
void OnUnlockMouse();
- void OnShowDisambiguationPopup(const gfx::Rect& rect_pixels,
- const gfx::Size& size,
- base::SharedMemoryHandle handle);
void OnSelectionBoundsChanged(
const ViewHostMsg_SelectionBounds_Params& params);
void OnSetNeedsBeginFrames(bool needs_begin_frames);
@@ -890,6 +884,10 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// was noticed because of input event ack timeout.
void RestartInputEventAckTimeoutIfNecessary();
+ // Called by |input_event_ack_timeout_| when an input event timed out without
+ // getting an ack from the renderer.
+ void OnInputEventAckTimeout();
+
void SetupInputRouter();
// Start intercepting system keyboard events.
@@ -951,6 +949,11 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// is depth 1, ie just below the root widget.
unsigned int frame_depth_ = 1u;
+ // Indicates that widget has a frame that intersects with the viewport. Note
+ // this is independent of |is_hidden_|. For widgets not associated with
+ // RenderFrame/View, assume false.
+ bool intersects_viewport_ = false;
+
#if defined(OS_ANDROID)
// Tracks the current importance of widget.
ChildProcessImportance importance_ = ChildProcessImportance::NORMAL;
@@ -983,11 +986,11 @@ class CONTENT_EXPORT RenderWidgetHostImpl
std::vector<MouseEventCallback> mouse_event_callbacks_;
// Input event callbacks.
- base::ObserverList<RenderWidgetHost::InputEventObserver>
+ base::ObserverList<RenderWidgetHost::InputEventObserver>::Unchecked
input_event_observers_;
// The observers watching us.
- base::ObserverList<RenderWidgetHostObserver> observers_;
+ base::ObserverList<RenderWidgetHostObserver>::Unchecked observers_;
// If true, then we should repaint when restoring even if we have a
// backingstore. This flag is set to true if we receive a paint message
@@ -1009,9 +1012,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// operation to finish.
base::TimeTicks repaint_start_time_;
- // Set to true if we shouldn't send input events from the render widget.
- bool ignore_input_events_;
-
// Set when we update the text direction of the selected input element.
bool text_direction_updated_;
blink::WebTextDirection text_direction_;
diff --git a/chromium/content/browser/renderer_host/render_widget_host_input_event_router.cc b/chromium/content/browser/renderer_host/render_widget_host_input_event_router.cc
index 52a1434b1b4..e3d18fefaf8 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_input_event_router.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -154,6 +154,9 @@ void RenderWidgetHostInputEventRouter::OnRenderWidgetHostViewBaseDestroyed(
if (view == last_fling_start_target_)
last_fling_start_target_ = nullptr;
+ if (view == last_fling_start_bubbled_target_)
+ last_fling_start_bubbled_target_ = nullptr;
+
event_targeter_->ViewWillBeDestroyed(view);
}
@@ -173,7 +176,7 @@ RenderWidgetHostInputEventRouter::HittestDelegate::HittestDelegate(
bool RenderWidgetHostInputEventRouter::HittestDelegate::RejectHitTarget(
const viz::SurfaceDrawQuad* surface_quad,
const gfx::Point& point_in_quad_space) {
- auto it = hittest_data_.find(surface_quad->primary_surface_id);
+ auto it = hittest_data_.find(surface_quad->surface_range.end());
if (it != hittest_data_.end() && it->second.ignored_for_hittest)
return true;
return false;
@@ -182,7 +185,7 @@ bool RenderWidgetHostInputEventRouter::HittestDelegate::RejectHitTarget(
bool RenderWidgetHostInputEventRouter::HittestDelegate::AcceptHitTarget(
const viz::SurfaceDrawQuad* surface_quad,
const gfx::Point& point_in_quad_space) {
- auto it = hittest_data_.find(surface_quad->primary_surface_id);
+ auto it = hittest_data_.find(surface_quad->surface_range.end());
if (it != hittest_data_.end() && !it->second.ignored_for_hittest)
return true;
return false;
@@ -573,9 +576,12 @@ void RenderWidgetHostInputEventRouter::DispatchTouchEvent(
// of the touch sequence, though this could be wrong; a better approach
// might be to always transform each point to the |touch_target_.target|
// for the duration of the sequence.
- DCHECK(target_location.has_value());
- touch_target_.delta =
- target_location.value() - touch_event.touches[0].PositionInWidget();
+ if (target_location.has_value()) {
+ touch_target_.delta =
+ target_location.value() - touch_event.touches[0].PositionInWidget();
+ } else {
+ touch_target_.delta = gfx::Vector2dF();
+ }
DCHECK(touchscreen_gesture_target_map_.find(
touch_event.unique_touch_event_id) ==
@@ -596,6 +602,14 @@ void RenderWidgetHostInputEventRouter::DispatchTouchEvent(
}
DCHECK_GE(active_touches_, 0);
+ // Debugging for crbug.com/814674.
+ if (touch_target_.target && !IsViewInMap(touch_target_.target)) {
+ NOTREACHED() << "Touch events should not be routed to a destroyed target "
+ "View.";
+ touch_target_.target = nullptr;
+ base::debug::DumpWithoutCrashing();
+ }
+
if (!touch_target_.target) {
TouchEventWithLatencyInfo touch_with_latency(touch_event, latency);
root_view->ProcessAckedTouchEvent(touch_with_latency,
@@ -619,6 +633,28 @@ void RenderWidgetHostInputEventRouter::DispatchTouchEvent(
touch_target_.target = nullptr;
}
+void RenderWidgetHostInputEventRouter::ProcessAckedTouchEvent(
+ const TouchEventWithLatencyInfo& event,
+ InputEventAckState ack_result,
+ RenderWidgetHostViewBase* view) {
+ // TODO(wjmaclean): Eventually we will keep track of which outgoing touch
+ // events are emulated and which aren't, so the decision to hand off to the
+ // touch emulator won't just rely on the existence of the touch emulator.
+ if (touch_emulator_ &&
+ touch_emulator_->HandleTouchEventAck(event.event, ack_result)) {
+ return;
+ }
+
+ if (!view)
+ return;
+
+ auto* root_view = view->GetRootView();
+ if (!root_view)
+ return;
+
+ root_view->ProcessAckedTouchEvent(event, ack_result);
+}
+
void RenderWidgetHostInputEventRouter::RouteTouchEvent(
RenderWidgetHostViewBase* root_view,
blink::WebTouchEvent* event,
@@ -795,7 +831,8 @@ void RenderWidgetHostInputEventRouter::BubbleScrollEvent(
DCHECK(event.GetType() == blink::WebInputEvent::kGestureScrollBegin ||
event.GetType() == blink::WebInputEvent::kGestureScrollUpdate ||
event.GetType() == blink::WebInputEvent::kGestureScrollEnd ||
- event.GetType() == blink::WebInputEvent::kGestureFlingStart);
+ event.GetType() == blink::WebInputEvent::kGestureFlingStart ||
+ event.GetType() == blink::WebInputEvent::kGestureFlingCancel);
ui::LatencyInfo latency_info =
ui::WebInputEventTraits::CreateLatencyInfoForWebGestureEvent(event);
@@ -824,7 +861,26 @@ void RenderWidgetHostInputEventRouter::BubbleScrollEvent(
}
bubbling_gesture_scroll_target_.target = target_view;
+ } else if (event.GetType() == blink::WebInputEvent::kGestureFlingCancel) {
+ // TODO(828422): Remove once this issue no longer occurs.
+ if (resending_view == last_fling_start_bubbled_target_) {
+ ReportBubblingScrollToSameView(event, resending_view);
+ last_fling_start_bubbled_target_ = nullptr;
+ return;
+ }
+ // GFC event must get bubbled to the same target view that the last GFS has
+ // been bubbled.
+ if (last_fling_start_bubbled_target_) {
+ last_fling_start_bubbled_target_->ProcessGestureEvent(
+ GestureEventInTarget(event, last_fling_start_bubbled_target_),
+ latency_info);
+ last_fling_start_bubbled_target_ = nullptr;
+ }
+ return;
} else { // !(event.GetType() == blink::WebInputEvent::kGestureScrollBegin)
+ // && !(event.GetType() ==
+ // blink::WebInputEvent::kGestureFlingCancel)
+
if (!bubbling_gesture_scroll_target_.target) {
// The GestureScrollBegin event is not bubbled, don't bubble the rest of
// the scroll events.
@@ -856,6 +912,12 @@ void RenderWidgetHostInputEventRouter::BubbleScrollEvent(
bubbling_gesture_scroll_target_.target->ProcessGestureEvent(
GestureEventInTarget(event, bubbling_gesture_scroll_target_.target),
latency_info);
+
+ // The GFC should be sent to the view that handles the GFS.
+ if (event.GetType() == blink::WebInputEvent::kGestureFlingStart) {
+ last_fling_start_bubbled_target_ = bubbling_gesture_scroll_target_.target;
+ }
+
if (event.GetType() == blink::WebInputEvent::kGestureScrollEnd ||
event.GetType() == blink::WebInputEvent::kGestureFlingStart) {
first_bubbling_scroll_target_.target = nullptr;
@@ -1061,6 +1123,9 @@ void RenderWidgetHostInputEventRouter::DispatchTouchscreenGestureEvent(
if (target_allowed_touch_action.value() &
cc::TouchAction::kTouchActionPinchZoom) {
gesture_pinch_did_send_scroll_begin_ = true;
+ // The pinch gesture will be sent to the root view and it may not have a
+ // valid touch action yet. In this case, set the touch action to auto.
+ rwhi->input_router()->ForceSetTouchActionAuto();
SendGestureScrollBegin(root_view, gesture_event);
} else {
// When target does not allow touch-action: pinch, instead of sending
@@ -1197,6 +1262,11 @@ void RenderWidgetHostInputEventRouter::DispatchTouchscreenGestureEvent(
map_size_key,
base::StringPrintf("%u", static_cast<int>(owner_map_.size())));
+ if (events_being_flushed_) {
+ touchscreen_gesture_target_.target->host()
+ ->input_router()
+ ->ForceSetTouchActionAuto();
+ }
touchscreen_gesture_target_.target->ProcessGestureEvent(event, latency);
if (gesture_event.GetType() == blink::WebInputEvent::kGestureFlingStart)
@@ -1368,6 +1438,11 @@ RenderWidgetHostInputEventRouter::FindTargetSynchronously(
return RenderWidgetTargetResult();
}
+void RenderWidgetHostInputEventRouter::SetEventsBeingFlushed(
+ bool events_being_flushed) {
+ events_being_flushed_ = events_being_flushed;
+}
+
void RenderWidgetHostInputEventRouter::DispatchEventToTarget(
RenderWidgetHostViewBase* root_view,
RenderWidgetHostViewBase* target,
diff --git a/chromium/content/browser/renderer_host/render_widget_host_input_event_router.h b/chromium/content/browser/renderer_host/render_widget_host_input_event_router.h
index 68d7cf064c2..f32c2cee069 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_input_event_router.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_input_event_router.h
@@ -15,17 +15,27 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "build/build_config.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "components/viz/host/hit_test/hit_test_query.h"
#include "components/viz/service/surfaces/surface_hittest_delegate.h"
+#include "content/browser/renderer_host/event_with_latency_info.h"
#include "content/browser/renderer_host/input/touch_emulator_client.h"
#include "content/browser/renderer_host/render_widget_host_view_base_observer.h"
#include "content/browser/renderer_host/render_widget_targeter.h"
#include "content/common/content_export.h"
+#include "content/public/common/input_event_ack_state.h"
#include "ui/gfx/geometry/vector2d_conversions.h"
struct FrameHostMsg_HittestData_Params;
+#if defined(OS_WIN)
+// Flaky on Windows. https://crbug.com/868308
+#define MAYBE_TouchpadPinchOverOOPIF DISABLED_TouchpadPinchOverOOPIF
+#else
+#define MAYBE_TouchpadPinchOverOOPIF TouchpadPinchOverOOPIF
+#endif // OS_WIN
+
namespace blink {
class WebGestureEvent;
class WebInputEvent;
@@ -78,6 +88,9 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter
blink::WebGestureEvent* event,
const ui::LatencyInfo& latency);
void OnHandledTouchStartOrFirstTouchMove(uint32_t unique_touch_event_id);
+ void ProcessAckedTouchEvent(const TouchEventWithLatencyInfo& event,
+ InputEventAckState ack_result,
+ RenderWidgetHostViewBase* view);
void RouteTouchEvent(RenderWidgetHostViewBase* root_view,
blink::WebTouchEvent *event,
const ui::LatencyInfo& latency);
@@ -272,6 +285,9 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter
const blink::WebInputEvent& event,
const ui::LatencyInfo& latency,
const base::Optional<gfx::PointF>& target_location) override;
+ // Notify whether the events in the queue are being flushed due to touch ack
+ // timeout, or the flushing has completed.
+ void SetEventsBeingFlushed(bool events_being_flushed) override;
FrameSinkIdOwnerMap owner_map_;
TargetMap touchscreen_gesture_target_map_;
@@ -295,6 +311,12 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter
// Tracked for the purpose of targeting subsequent fling cancel events.
RenderWidgetHostViewBase* last_fling_start_target_ = nullptr;
+ // During scroll bubbling we bubble the GFS to the target view so that its
+ // fling controller takes care of flinging. In this case we should also send
+ // the GFC to the bubbling target so that the fling controller currently in
+ // charge of the fling progress could handle the fling cancellelation as well.
+ RenderWidgetHostViewBase* last_fling_start_bubbled_target_ = nullptr;
+
// Tracked for the purpose of providing a root_view when dispatching emulated
// touch/gesture events.
RenderWidgetHostViewBase* last_emulated_event_root_view_;
@@ -311,6 +333,7 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter
std::unique_ptr<RenderWidgetTargeter> event_targeter_;
bool use_viz_hit_test_ = false;
+ bool events_being_flushed_ = false;
std::unique_ptr<TouchEmulator> touch_emulator_;
@@ -327,7 +350,7 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter
FRIEND_TEST_ALL_PREFIXES(SitePerProcessHitTestBrowserTest,
InputEventRouterTouchpadGestureTargetTest);
FRIEND_TEST_ALL_PREFIXES(SitePerProcessHitTestBrowserTest,
- TouchpadPinchOverOOPIF);
+ MAYBE_TouchpadPinchOverOOPIF);
FRIEND_TEST_ALL_PREFIXES(SitePerProcessMouseWheelHitTestBrowserTest,
InputEventRouterWheelTargetTest);
FRIEND_TEST_ALL_PREFIXES(SitePerProcessMacBrowserTest,
diff --git a/chromium/content/browser/renderer_host/render_widget_host_input_event_router_unittest.cc b/chromium/content/browser/renderer_host/render_widget_host_input_event_router_unittest.cc
index f25a7637f5c..310d80202ed 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_input_event_router_unittest.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_input_event_router_unittest.cc
@@ -4,9 +4,17 @@
#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
+#include <vector>
+
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
#include "build/build_config.h"
+#include "components/viz/common/features.h"
+#include "components/viz/common/hit_test/aggregated_hit_test_region.h"
+#include "components/viz/host/hit_test/hit_test_query.h"
+#include "components/viz/host/host_frame_sink_manager.h"
+#include "components/viz/test/host_frame_sink_manager_test_api.h"
+#include "content/browser/compositor/surface_utils.h"
#include "content/browser/compositor/test/test_image_transport_factory.h"
#include "content/browser/renderer_host/frame_connector_delegate.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
@@ -53,6 +61,7 @@ class TestRenderWidgetHostViewChildFrame
public:
explicit TestRenderWidgetHostViewChildFrame(RenderWidgetHost* widget)
: RenderWidgetHostViewChildFrame(widget),
+ frame_sink_id_(2, 1),
last_gesture_seen_(blink::WebInputEvent::kUndefined) {}
~TestRenderWidgetHostViewChildFrame() override = default;
@@ -66,12 +75,22 @@ class TestRenderWidgetHostViewChildFrame
unique_id_for_last_touch_ack_ = touch.event.unique_touch_event_id;
}
+ void SetBounds(const gfx::Rect& rect) override { bounds_ = rect; }
+
+ gfx::Rect GetViewBounds() const override { return bounds_; }
+
+ const viz::FrameSinkId& GetFrameSinkId() const override {
+ return frame_sink_id_;
+ }
+
blink::WebInputEvent::Type last_gesture_seen() { return last_gesture_seen_; }
uint32_t last_id_for_touch_ack() { return unique_id_for_last_touch_ack_; }
void Reset() { last_gesture_seen_ = blink::WebInputEvent::kUndefined; }
private:
+ gfx::Rect bounds_;
+ viz::FrameSinkId frame_sink_id_;
blink::WebInputEvent::Type last_gesture_seen_;
uint32_t unique_id_for_last_touch_ack_ = 0;
};
@@ -85,6 +104,7 @@ class MockRootRenderWidgetHostView : public TestRenderWidgetHostView {
RenderWidgetHost* rwh,
std::map<RenderWidgetHostViewBase*, viz::FrameSinkId>& frame_sink_id_map)
: TestRenderWidgetHostView(rwh),
+ frame_sink_id_(1, 1),
frame_sink_id_map_(frame_sink_id_map),
current_hittest_result_(nullptr),
force_query_renderer_on_hit_test_(false),
@@ -120,6 +140,16 @@ class MockRootRenderWidgetHostView : public TestRenderWidgetHostView {
unique_id_for_last_touch_ack_ = touch.event.unique_touch_event_id;
}
+ void SetBounds(const gfx::Rect& rect) override { bounds_ = rect; }
+
+ gfx::Rect GetViewBounds() const override { return bounds_; }
+
+ const viz::FrameSinkId& GetFrameSinkId() const override {
+ return frame_sink_id_;
+ }
+
+ viz::FrameSinkId GetRootFrameSinkId() override { return frame_sink_id_; }
+
blink::WebInputEvent::Type last_gesture_seen() { return last_gesture_seen_; }
uint32_t last_id_for_touch_ack() { return unique_id_for_last_touch_ack_; }
@@ -134,6 +164,8 @@ class MockRootRenderWidgetHostView : public TestRenderWidgetHostView {
void Reset() { last_gesture_seen_ = blink::WebInputEvent::kUndefined; }
private:
+ gfx::Rect bounds_;
+ viz::FrameSinkId frame_sink_id_;
std::map<RenderWidgetHostViewBase*, viz::FrameSinkId>& frame_sink_id_map_;
RenderWidgetHostViewBase* current_hittest_result_;
bool force_query_renderer_on_hit_test_;
@@ -147,6 +179,12 @@ class RenderWidgetHostInputEventRouterTest : public testing::Test {
public:
RenderWidgetHostInputEventRouterTest() {}
+ // Initializes the hit testing data required when
+ // features::IsVizHitTestingEnabled. Where both |view_root_flags| and
+ // |view_other_flags| are viz::HitTestRegionFlags, representing the type of
+ // events to be responded to by each view, along with how they are processed.
+ void InitVizHitTestData(int view_root_flags, int view_other_flags);
+
protected:
// testing::Test:
void SetUp() override {
@@ -189,8 +227,8 @@ class RenderWidgetHostInputEventRouterTest : public testing::Test {
// Set up the RWHIER's FrameSinkId to RWHV map so that we can control the
// result of RWHIER's hittesting.
- frame_sink_id_map_ = {{view_root_.get(), viz::FrameSinkId(1, 1)},
- {view_other_.get(), viz::FrameSinkId(2, 2)}};
+ frame_sink_id_map_ = {{view_root_.get(), view_root_->GetFrameSinkId()},
+ {view_other_.get(), view_other_->GetFrameSinkId()}};
rwhier_.AddFrameSinkIdOwner(frame_sink_id_map_[view_root_.get()],
view_root_.get());
rwhier_.AddFrameSinkIdOwner(frame_sink_id_map_[view_other_.get()],
@@ -217,6 +255,8 @@ class RenderWidgetHostInputEventRouterTest : public testing::Test {
MockRenderWidgetHostDelegate delegate_;
std::unique_ptr<BrowserContext> browser_context_;
+ std::unique_ptr<viz::HostFrameSinkManagerTestApi>
+ host_frame_sink_manager_test_api_;
std::unique_ptr<MockRenderProcessHost> process_host1_;
std::unique_ptr<MockRenderProcessHost> process_host2_;
std::unique_ptr<MockWidgetImpl> widget_impl1_;
@@ -236,6 +276,42 @@ class RenderWidgetHostInputEventRouterTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostInputEventRouterTest);
};
+void RenderWidgetHostInputEventRouterTest::InitVizHitTestData(
+ int view_root_flags,
+ int view_other_flags) {
+ if (!features::IsVizHitTestingEnabled())
+ return;
+ DCHECK(GetHostFrameSinkManager());
+ // Bounds chosen so that both |view_root_| and |view_other_| occupy (0, 0);
+ // the default position in WebPointerProperties. This is done as the test
+ // suite overrides enough of the classic hit testing path that there the
+ // bounds do not matter. However Viz hit-testing always performs a contains
+ // check on input events. This allows both views to handle the input
+ // targetting in the tests below.
+ view_root_->SetBounds(gfx::Rect(0, 0, 10, 10));
+ view_other_->SetBounds(gfx::Rect(0, 0, 10, 5));
+
+ host_frame_sink_manager_test_api_ =
+ std::make_unique<viz::HostFrameSinkManagerTestApi>(
+ GetHostFrameSinkManager());
+ viz::HostFrameSinkManager::DisplayHitTestQueryMap hit_test_map;
+ hit_test_map[view_root_->GetFrameSinkId()] =
+ std::make_unique<viz::HitTestQuery>();
+
+ std::vector<viz::AggregatedHitTestRegion> hit_test_data;
+ hit_test_data.push_back(viz::AggregatedHitTestRegion(
+ view_root_->GetFrameSinkId(), view_root_flags,
+ view_root_->GetViewBounds(), gfx::Transform(), 1));
+ hit_test_data.push_back(viz::AggregatedHitTestRegion(
+ view_other_->GetFrameSinkId(), view_other_flags,
+ view_other_->GetViewBounds(), gfx::Transform(), 0));
+ hit_test_map[view_root_->GetFrameSinkId()]
+ ->OnAggregatedHitTestRegionListUpdated(hit_test_data);
+
+ host_frame_sink_manager_test_api_->SetDisplayHitTestQuery(
+ std::move(hit_test_map));
+}
+
// Make sure that when a touch scroll crosses out of the area for a
// RenderWidgetHostView, the RenderWidgetHostInputEventRouter continues to
// route gesture events to the same RWHV until the end of the gesture.
@@ -247,6 +323,11 @@ TEST_F(RenderWidgetHostInputEventRouterTest,
// We start the touch in the area for |view_other_|.
view_root_->SetHittestResult(view_other_.get());
+ // Each view will want to process the touch event.
+ InitVizHitTestData(viz::HitTestRegionFlags::kHitTestTouch |
+ viz::HitTestRegionFlags::kHitTestMine,
+ viz::HitTestRegionFlags::kHitTestTouch |
+ viz::HitTestRegionFlags::kHitTestMine);
blink::WebTouchEvent touch_event(
blink::WebInputEvent::kTouchStart, blink::WebInputEvent::kNoModifiers,
@@ -299,9 +380,20 @@ TEST_F(RenderWidgetHostInputEventRouterTest,
rwhier_.RouteGestureEvent(view_root_.get(), &gesture_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
- // Now the touch moves out of |view_other_| and into |view_root_|, but
- // |view_other_| should continue to be the target for gesture events.
+ // The continuation of the touch moves should maintain their current target of
+ // |view_other_|, even if they move outside of that view, and into
+ // |view_root_|.
+ //
+ // Since this test is not using actual view sizes, nor event positions, we
+ // need to setup our hit testing overrides to prevent targeting |view_other_|.
+ //
+ // If the target is maintained through the gesture this will pass. If instead
+ // the hit testing logic is refered to, then this test will fail.
view_root_->SetHittestResult(view_root_.get());
+ InitVizHitTestData(viz::HitTestRegionFlags::kHitTestTouch |
+ viz::HitTestRegionFlags::kHitTestMine,
+ viz::HitTestRegionFlags::kHitTestTouch |
+ viz::HitTestRegionFlags::kHitTestIgnore);
view_root_->Reset();
view_other_->Reset();
@@ -369,6 +461,13 @@ TEST_F(RenderWidgetHostInputEventRouterTest, DoNotCoalesceTouchEvents) {
RenderWidgetTargeter* targeter = rwhier_.GetRenderWidgetTargeterForTests();
view_root_->SetHittestResult(view_root_.get());
view_root_->set_force_query_renderer_on_hit_test(true);
+ // Also force the renderer to be queried.
+ InitVizHitTestData(viz::HitTestRegionFlags::kHitTestTouch |
+ viz::HitTestRegionFlags::kHitTestMine |
+ viz::HitTestRegionFlags::kHitTestAsk,
+ viz::HitTestRegionFlags::kHitTestTouch |
+ viz::HitTestRegionFlags::kHitTestMine |
+ viz::HitTestRegionFlags::kHitTestAsk);
// We need to set up a comm pipe, or else the targeter will crash when it
// tries to query the renderer. It doesn't matter that the pipe isn't
@@ -423,6 +522,13 @@ TEST_F(RenderWidgetHostInputEventRouterTest, DoNotCoalesceGestureEvents) {
RenderWidgetTargeter* targeter = rwhier_.GetRenderWidgetTargeterForTests();
view_root_->SetHittestResult(view_root_.get());
view_root_->set_force_query_renderer_on_hit_test(true);
+ // Also force the renderer to be queried.
+ InitVizHitTestData(viz::HitTestRegionFlags::kHitTestTouch |
+ viz::HitTestRegionFlags::kHitTestMine |
+ viz::HitTestRegionFlags::kHitTestAsk,
+ viz::HitTestRegionFlags::kHitTestTouch |
+ viz::HitTestRegionFlags::kHitTestMine |
+ viz::HitTestRegionFlags::kHitTestAsk);
// We need to set up a comm pipe, or else the targeter will crash when it
// tries to query the renderer. It doesn't matter that the pipe isn't
diff --git a/chromium/content/browser/renderer_host/render_widget_host_ns_view_client.h b/chromium/content/browser/renderer_host/render_widget_host_ns_view_client.h
index 92f4fd7407f..5efb19f2379 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_ns_view_client.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_ns_view_client.h
@@ -13,6 +13,7 @@ namespace blink {
class WebGestureEvent;
class WebMouseEvent;
class WebMouseWheelEvent;
+class WebTouchEvent;
} // namespace blink
namespace ui {
@@ -53,6 +54,8 @@ class RenderWidgetHostNSViewLocalClient {
// Forward events to the renderer or the input router, as appropriate.
virtual void RouteOrProcessMouseEvent(
const blink::WebMouseEvent& web_event) = 0;
+ virtual void RouteOrProcessTouchEvent(
+ const blink::WebTouchEvent& web_event) = 0;
virtual void RouteOrProcessWheelEvent(
const blink::WebMouseWheelEvent& web_event) = 0;
diff --git a/chromium/content/browser/renderer_host/render_widget_host_unittest.cc b/chromium/content/browser/renderer_host/render_widget_host_unittest.cc
index e5de66d7b7c..138cac8c271 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -524,6 +524,7 @@ class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
handle_wheel_event_(false),
handle_wheel_event_called_(false),
unresponsive_timer_fired_(false),
+ ignore_input_events_(false),
render_view_host_delegate_view_(new MockRenderViewHostDelegateView()) {}
~MockRenderWidgetHostDelegate() override {}
@@ -582,6 +583,10 @@ class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
return mock_delegate_view();
}
+ void SetIgnoreInputEvents(bool ignore_input_events) {
+ ignore_input_events_ = ignore_input_events;
+ }
+
protected:
KeyboardEventProcessingResult PreHandleKeyboardEvent(
const NativeWebKeyboardEvent& event) override {
@@ -610,6 +615,8 @@ class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
unresponsive_timer_fired_ = true;
}
+ bool ShouldIgnoreInputEvents() override { return ignore_input_events_; }
+
void ExecuteEditCommand(
const std::string& command,
const base::Optional<base::string16>& value) override {}
@@ -633,6 +640,8 @@ class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
bool unresponsive_timer_fired_;
+ bool ignore_input_events_;
+
std::unique_ptr<MockRenderViewHostDelegateView>
render_view_host_delegate_view_;
@@ -1694,7 +1703,7 @@ TEST_F(RenderWidgetHostTest, SwapCompositorFrameWithBadSourceId) {
TEST_F(RenderWidgetHostTest, IgnoreInputEvent) {
host_->SetupForInputRouterTest();
- host_->SetIgnoreInputEvents(true);
+ delegate_->SetIgnoreInputEvents(true);
SimulateKeyboardEvent(WebInputEvent::kRawKeyDown);
EXPECT_FALSE(host_->mock_input_router()->sent_keyboard_event_);
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_android.cc b/chromium/content/browser/renderer_host/render_widget_host_view_android.cc
index f56a9746443..c0460f053f2 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -21,6 +21,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/sys_info.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "cc/base/math_util.h"
#include "cc/layers/layer.h"
#include "cc/layers/surface_layer.h"
#include "cc/trees/latency_info_swap_promise.h"
@@ -40,7 +41,6 @@
#include "content/browser/android/overscroll_controller_android.h"
#include "content/browser/android/selection/selection_popup_controller.h"
#include "content/browser/android/synchronous_compositor_host.h"
-#include "content/browser/android/tap_disambiguator.h"
#include "content/browser/android/text_suggestion_host_android.h"
#include "content/browser/bad_message.h"
#include "content/browser/compositor/surface_utils.h"
@@ -48,6 +48,7 @@
#include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/media/android/media_web_contents_observer_android.h"
#include "content/browser/renderer_host/compositor_impl_android.h"
+#include "content/browser/renderer_host/delegated_frame_host_client_android.h"
#include "content/browser/renderer_host/dip_util.h"
#include "content/browser/renderer_host/frame_metadata_util.h"
#include "content/browser/renderer_host/input/input_router.h"
@@ -148,12 +149,8 @@ void RecordToolTypeForActionDown(const ui::MotionEventAndroid& event) {
}
}
-bool FloatEquals(float a, float b) {
- return std::abs(a - b) < FLT_EPSILON;
-}
-
void WakeUpGpu(GpuProcessHost* host) {
- if (host && host->wake_up_gpu_before_drawing()) {
+ if (host && host->gpu_host()->wake_up_gpu_before_drawing()) {
host->gpu_service()->WakeUpGpu();
}
}
@@ -171,7 +168,6 @@ RenderWidgetHostViewAndroid::RenderWidgetHostViewAndroid(
is_window_activity_started_(true),
is_in_vr_(false),
ime_adapter_android_(nullptr),
- tap_disambiguator_(nullptr),
selection_popup_controller_(nullptr),
text_suggestion_host_(nullptr),
gesture_listener_manager_(nullptr),
@@ -198,9 +194,12 @@ RenderWidgetHostViewAndroid::RenderWidgetHostViewAndroid(
view_.set_event_handler(this);
if (using_browser_compositor_) {
+ delegated_frame_host_client_ =
+ std::make_unique<DelegatedFrameHostClientAndroid>(this);
delegated_frame_host_ = std::make_unique<ui::DelegatedFrameHostAndroid>(
- &view_, CompositorImpl::GetHostFrameSinkManager(), this,
- host()->GetFrameSinkId(), features::IsSurfaceSynchronizationEnabled());
+ &view_, CompositorImpl::GetHostFrameSinkManager(),
+ delegated_frame_host_client_.get(), host()->GetFrameSinkId(),
+ features::IsSurfaceSynchronizationEnabled());
if (is_showing_) {
delegated_frame_host_->WasShown(
local_surface_id_allocator_.GetCurrentLocalSurfaceId(),
@@ -218,7 +217,14 @@ RenderWidgetHostViewAndroid::RenderWidgetHostViewAndroid(
host()->SetView(this);
touch_selection_controller_client_manager_ =
std::make_unique<TouchSelectionControllerClientManagerAndroid>(this);
+
UpdateNativeViewTree(parent_native_view);
+ // This RWHVA may have been created speculatively. We should give any
+ // existing RWHVAs priority for receiving input events, otherwise a
+ // speculative RWHVA could be sent input events intended for the currently
+ // showing RWHVA.
+ if (parent_native_view)
+ parent_native_view->MoveToBack(&view_);
CreateOverscrollControllerIfPossible();
@@ -387,7 +393,7 @@ void RenderWidgetHostViewAndroid::OnRenderFrameMetadataChangedBeforeActivation(
float top_content_offset_dip = IsUseZoomForDSFEnabled()
? top_content_offset / dip_scale
: top_content_offset;
- view_.UpdateFrameInfo({scrollable_viewport_size_dip, top_content_offset});
+ view_.UpdateFrameInfo({scrollable_viewport_size_dip, top_content_offset_dip});
bool controls_changed = UpdateControls(
view_.GetDipScale(), metadata.top_controls_height,
metadata.top_controls_shown_ratio, metadata.bottom_controls_height,
@@ -415,6 +421,7 @@ void RenderWidgetHostViewAndroid::OnRenderFrameMetadataChangedBeforeActivation(
page_scale_ = metadata.page_scale_factor;
min_page_scale_ = metadata.min_page_scale_factor;
max_page_scale_ = metadata.max_page_scale_factor;
+ current_surface_size_ = metadata.viewport_size_in_pixels;
}
void RenderWidgetHostViewAndroid::Focus() {
@@ -820,6 +827,8 @@ void RenderWidgetHostViewAndroid::ResetGestureDetection() {
}
void RenderWidgetHostViewAndroid::OnDidNavigateMainFrameToNewPage() {
+ if (view_.parent())
+ view_.parent()->MoveToFront(&view_);
ResetGestureDetection();
}
@@ -871,12 +880,17 @@ void RenderWidgetHostViewAndroid::UpdateBackgroundColor() {
view_.OnBackgroundColorChanged(color);
}
+bool RenderWidgetHostViewAndroid::HasFallbackSurface() const {
+ return delegated_frame_host_ && delegated_frame_host_->HasFallbackSurface();
+}
+
void RenderWidgetHostViewAndroid::CopyFromSurface(
const gfx::Rect& src_subrect,
const gfx::Size& output_size,
base::OnceCallback<void(const SkBitmap&)> callback) {
TRACE_EVENT0("cc", "RenderWidgetHostViewAndroid::CopyFromSurface");
- if (!IsSurfaceAvailableForCopy()) {
+ if (!features::IsSurfaceSynchronizationEnabled() &&
+ !IsSurfaceAvailableForCopy()) {
std::move(callback).Run(SkBitmap());
return;
}
@@ -915,12 +929,9 @@ uint32_t RenderWidgetHostViewAndroid::GetCaptureSequenceNumber() const {
return latest_capture_sequence_number_;
}
-void RenderWidgetHostViewAndroid::ShowDisambiguationPopup(
- const gfx::Rect& rect_pixels, const SkBitmap& zoomed_bitmap) {
- if (!tap_disambiguator_)
- return;
-
- tap_disambiguator_->ShowPopup(rect_pixels, zoomed_bitmap);
+void RenderWidgetHostViewAndroid::OnInterstitialPageAttached() {
+ if (view_.parent())
+ view_.parent()->MoveToFront(&view_);
}
void RenderWidgetHostViewAndroid::OnInterstitialPageGoingAway() {
@@ -957,14 +968,6 @@ void RenderWidgetHostViewAndroid::ReclaimResources(
renderer_compositor_frame_sink_->ReclaimResources(resources);
}
-void RenderWidgetHostViewAndroid::OnFrameTokenChanged(uint32_t frame_token) {
- OnFrameTokenChangedForView(frame_token);
-}
-
-void RenderWidgetHostViewAndroid::DidReceiveFirstFrameAfterNavigation() {
- host_->DidReceiveFirstFrameAfterNavigation();
-}
-
void RenderWidgetHostViewAndroid::DidCreateNewRendererCompositorFrameSink(
viz::mojom::CompositorFrameSinkClient* renderer_compositor_frame_sink) {
if (!delegated_frame_host_) {
@@ -1039,6 +1042,11 @@ void RenderWidgetHostViewAndroid::ClearCompositorFrame() {
EvictDelegatedFrame();
}
+void RenderWidgetHostViewAndroid::ResetFallbackToFirstNavigationSurface() {
+ if (delegated_frame_host_)
+ delegated_frame_host_->ResetFallbackToFirstNavigationSurface();
+}
+
bool RenderWidgetHostViewAndroid::RequestRepaintForTesting() {
return SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(),
base::nullopt);
@@ -1333,7 +1341,8 @@ bool RenderWidgetHostViewAndroid::UpdateControls(
float top_content_offset = top_controls_height * top_controls_shown_ratio;
float top_shown_pix = top_content_offset * to_pix;
float top_translate = top_shown_pix - top_controls_pix;
- bool top_changed = !FloatEquals(top_shown_pix, prev_top_shown_pix_);
+ bool top_changed =
+ !cc::MathUtil::IsFloatNearlyTheSame(top_shown_pix, prev_top_shown_pix_);
// TODO(mthiesse, https://crbug.com/853686): Remove the IsInVR check once
// there are no use cases for ignoring the initial update.
if (top_changed || (!controls_initialized_ && IsInVR()))
@@ -1343,7 +1352,8 @@ bool RenderWidgetHostViewAndroid::UpdateControls(
float bottom_controls_pix = bottom_controls_height * to_pix;
float bottom_shown_pix = bottom_controls_pix * bottom_controls_shown_ratio;
- bool bottom_changed = !FloatEquals(bottom_shown_pix, prev_bottom_shown_pix_);
+ bool bottom_changed = !cc::MathUtil::IsFloatNearlyTheSame(
+ bottom_shown_pix, prev_bottom_shown_pix_);
float bottom_translate = bottom_controls_pix - bottom_shown_pix;
if (bottom_changed || (!controls_initialized_ && IsInVR()))
view_.OnBottomControlsChanged(bottom_translate, bottom_shown_pix);
@@ -1357,6 +1367,9 @@ void RenderWidgetHostViewAndroid::OnDidUpdateVisualPropertiesComplete(
const cc::RenderFrameMetadata& metadata) {
SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(),
metadata.local_surface_id);
+ // We've just processed new RenderFrameMetadata and potentially embedded a
+ // new surface for that data. Check if we need to evict it.
+ EvictFrameIfNecessary();
}
void RenderWidgetHostViewAndroid::ShowInternal() {
@@ -1848,17 +1861,6 @@ bool RenderWidgetHostViewAndroid::ShowSelectionMenu(
GetTouchHandleHeight());
}
-void RenderWidgetHostViewAndroid::ResolveTapDisambiguation(
- double timestamp_seconds,
- gfx::Point tap_viewport_offset,
- bool is_long_press) {
- DCHECK(host());
- host()->Send(new ViewMsg_ResolveTapDisambiguation(
- host()->GetRoutingID(),
- base::TimeTicks() + base::TimeDelta::FromSecondsD(timestamp_seconds),
- tap_viewport_offset, is_long_press));
-}
-
void RenderWidgetHostViewAndroid::MoveCaret(const gfx::Point& point) {
if (host() && host()->delegate())
host()->delegate()->MoveCaret(point);
@@ -2076,8 +2078,6 @@ bool RenderWidgetHostViewAndroid::RequiresDoubleTapGestureEvents() const {
void RenderWidgetHostViewAndroid::OnSizeChanged() {
if (ime_adapter_android_)
ime_adapter_android_->UpdateAfterViewSizeChanged();
- if (tap_disambiguator_)
- tap_disambiguator_->HidePopup();
}
void RenderWidgetHostViewAndroid::OnPhysicalBackingSizeChanged() {
@@ -2329,8 +2329,6 @@ void RenderWidgetHostViewAndroid::CreateOverscrollControllerIfPossible() {
// If window_android is null here, this is bad because we don't listen for it
// being set, so we won't be able to construct the OverscrollController at the
// proper time.
- // TODO(rlanday): once we get WindowAndroid from ViewAndroid instead of
- // ContentViewCore, listen for WindowAndroid being set and create the
ui::WindowAndroid* window_android = view_.GetWindowAndroid();
if (!window_android)
return;
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_android.h b/chromium/content/browser/renderer_host/render_widget_host_view_android.h
index ae59220401e..6d3920e20e8 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_android.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_android.h
@@ -53,7 +53,6 @@ class OverscrollControllerAndroid;
class SelectionPopupController;
class SynchronousCompositorHost;
class SynchronousCompositorClient;
-class TapDisambiguator;
class TextSuggestionHostAndroid;
class TouchSelectionControllerClientManagerAndroid;
class WebContentsAccessibilityAndroid;
@@ -67,7 +66,6 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
: public RenderWidgetHostViewBase,
public StylusTextSelectorClient,
public content::TextInputManager::Observer,
- public ui::DelegatedFrameHostAndroid::Client,
public ui::EventHandlerAndroid,
public ui::GestureProviderClient,
public ui::TouchSelectionControllerClient,
@@ -156,13 +154,13 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
base::Optional<viz::HitTestRegionList> hit_test_region_list) override;
void OnDidNotProduceFrame(const viz::BeginFrameAck& ack) override;
void ClearCompositorFrame() override;
+ void ResetFallbackToFirstNavigationSurface() override;
bool RequestRepaintForTesting() override;
void SetIsInVR(bool is_in_vr) override;
bool IsInVR() const override;
void DidOverscroll(const ui::DidOverscrollParams& params) override;
void DidStopFlinging() override;
- void ShowDisambiguationPopup(const gfx::Rect& rect_pixels,
- const SkBitmap& zoomed_bitmap) override;
+ void OnInterstitialPageAttached() override;
void OnInterstitialPageGoingAway() override;
std::unique_ptr<SyntheticGestureTarget> CreateSyntheticGestureTarget()
override;
@@ -235,17 +233,13 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
std::unique_ptr<ui::TouchHandleDrawable> CreateDrawable() override;
void DidScroll() override;
- // DelegatedFrameHostAndroid::Client implementation.
- void SetBeginFrameSource(viz::BeginFrameSource* begin_frame_source) override;
- void DidPresentCompositorFrame(
- uint32_t presentation_token,
- const gfx::PresentationFeedback& feedback) override;
+ // Used by DelegatedFrameHostClientAndroid.
+ void SetBeginFrameSource(viz::BeginFrameSource* begin_frame_source);
+ void DidPresentCompositorFrame(uint32_t presentation_token,
+ const gfx::PresentationFeedback& feedback);
void DidReceiveCompositorFrameAck(
- const std::vector<viz::ReturnedResource>& resources) override;
- void ReclaimResources(
- const std::vector<viz::ReturnedResource>& resources) override;
- void OnFrameTokenChanged(uint32_t frame_token) override;
- void DidReceiveFirstFrameAfterNavigation() override;
+ const std::vector<viz::ReturnedResource>& resources);
+ void ReclaimResources(const std::vector<viz::ReturnedResource>& resources);
// viz::BeginFrameObserver implementation.
void OnBeginFrame(const viz::BeginFrameArgs& args) override;
@@ -264,15 +258,9 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
void SendMouseWheelEvent(const blink::WebMouseWheelEvent& event);
void SendGestureEvent(const blink::WebGestureEvent& event);
bool ShowSelectionMenu(const ContextMenuParams& params);
- void ResolveTapDisambiguation(double timestamp_seconds,
- gfx::Point tap_viewport_offset,
- bool is_long_press);
void set_ime_adapter(ImeAdapterAndroid* ime_adapter) {
ime_adapter_android_ = ime_adapter;
}
- void set_tap_disambiguator(TapDisambiguator* tap_disambiguator) {
- tap_disambiguator_ = tap_disambiguator;
- }
void set_selection_popup_controller(SelectionPopupController* controller) {
selection_popup_controller_ = controller;
}
@@ -348,6 +336,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
protected:
// RenderWidgetHostViewBase:
void UpdateBackgroundColor() override;
+ bool HasFallbackSurface() const override;
private:
MouseWheelPhaseHandler* GetMouseWheelPhaseHandler() override;
@@ -449,13 +438,15 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
bool handles_hidden_by_selection_ui_ = false;
ImeAdapterAndroid* ime_adapter_android_;
- TapDisambiguator* tap_disambiguator_;
SelectionPopupController* selection_popup_controller_;
TextSuggestionHostAndroid* text_suggestion_host_;
GestureListenerManager* gesture_listener_manager_;
mutable ui::ViewAndroid view_;
+ std::unique_ptr<ui::DelegatedFrameHostAndroid::Client>
+ delegated_frame_host_client_;
+
// Manages the Compositor Frames received from the renderer.
std::unique_ptr<ui::DelegatedFrameHostAndroid> delegated_frame_host_;
@@ -482,7 +473,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
std::unique_ptr<TouchSelectionControllerClientManagerAndroid>
touch_selection_controller_client_manager_;
- // Bounds to use if we have no backing ContentViewCore
+ // Bounds to use if we have no backing WebContents.
gfx::Rect default_bounds_;
const bool using_browser_compositor_;
@@ -508,7 +499,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
viz::mojom::CompositorFrameSinkClient* renderer_compositor_frame_sink_ =
nullptr;
- base::ObserverList<DestructionObserver> destruction_observers_;
+ base::ObserverList<DestructionObserver>::Unchecked destruction_observers_;
MouseWheelPhaseHandler mouse_wheel_phase_handler_;
uint32_t latest_capture_sequence_number_ = 0u;
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_aura.cc b/chromium/content/browser/renderer_host/render_widget_host_view_aura.cc
index 09168578786..b01698c8111 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -22,7 +22,6 @@
#include "components/viz/common/features.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
-#include "components/viz/common/gl_helper.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/accessibility/browser_accessibility_state_impl.h"
#include "content/browser/bad_message.h"
@@ -55,8 +54,8 @@
#include "content/public/common/use_zoom_for_dsf_policy.h"
#include "gpu/ipc/common/gpu_messages.h"
#include "services/service_manager/public/cpp/interface_provider.h"
-#include "services/ui/common/switches.h"
-#include "services/ui/public/interfaces/window_tree_constants.mojom.h"
+#include "services/ws/common/switches.h"
+#include "services/ws/public/mojom/window_tree_constants.mojom.h"
#include "third_party/blink/public/platform/web_input_event.h"
#include "third_party/blink/public/web/web_ime_text_span.h"
#include "ui/accessibility/platform/aura_window_properties.h"
@@ -365,7 +364,7 @@ RenderWidgetHostViewAura::RenderWidgetHostViewAura(
is_guest_view_hack_(is_guest_view_hack),
device_scale_factor_(0.0f),
event_handler_(new RenderWidgetHostViewEventHandler(host(), this, this)),
- frame_sink_id_(!features::IsAshInBrowserProcess()
+ frame_sink_id_(features::IsUsingWindowService()
? viz::FrameSinkId()
: is_guest_view_hack_
? AllocateFrameSinkIdForGuestViewHack()
@@ -756,9 +755,13 @@ void RenderWidgetHostViewAura::FocusedNodeTouched(bool editable) {
return;
auto* controller = input_method->GetInputMethodKeyboardController();
if (editable && host()->GetView() && host()->delegate()) {
- keyboard_observer_.reset(new WinScreenKeyboardObserver(this));
- if (!controller->DisplayVirtualKeyboard())
+ if (last_pointer_type_ == ui::EventPointerType::POINTER_TYPE_TOUCH) {
+ keyboard_observer_.reset(new WinScreenKeyboardObserver(this));
+ if (!controller->DisplayVirtualKeyboard())
+ keyboard_observer_.reset(nullptr);
+ } else {
keyboard_observer_.reset(nullptr);
+ }
virtual_keyboard_requested_ = keyboard_observer_.get();
} else {
virtual_keyboard_requested_ = false;
@@ -886,6 +889,11 @@ void RenderWidgetHostViewAura::ClearCompositorFrame() {
delegated_frame_host_->ClearDelegatedFrame();
}
+void RenderWidgetHostViewAura::ResetFallbackToFirstNavigationSurface() {
+ if (delegated_frame_host_)
+ delegated_frame_host_->ResetFallbackToFirstNavigationSurface();
+}
+
bool RenderWidgetHostViewAura::RequestRepaintForTesting() {
return SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(),
base::nullopt);
@@ -1643,6 +1651,10 @@ bool RenderWidgetHostViewAura::TransformPointToLocalCoordSpaceLegacy(
return true;
}
+bool RenderWidgetHostViewAura::HasFallbackSurface() const {
+ return delegated_frame_host_ && delegated_frame_host_->HasFallbackSurface();
+}
+
bool RenderWidgetHostViewAura::TransformPointToCoordSpaceForView(
const gfx::PointF& point,
RenderWidgetHostViewBase* target_view,
@@ -1656,8 +1668,10 @@ bool RenderWidgetHostViewAura::TransformPointToCoordSpaceForView(
// In TransformPointToLocalCoordSpace() there is a Point-to-Pixel conversion,
// but it is not necessary here because the final target view is responsible
// for converting before computing the final transform.
- return delegated_frame_host_->TransformPointToCoordSpaceForView(
- point, target_view, transformed_point, source);
+ if (!HasFallbackSurface())
+ return false;
+ return target_view->TransformPointToLocalCoordSpace(
+ point, GetCurrentSurfaceId(), transformed_point, source);
}
viz::FrameSinkId RenderWidgetHostViewAura::GetRootFrameSinkId() {
@@ -1698,9 +1712,9 @@ void RenderWidgetHostViewAura::FocusedNodeChanged(
}
void RenderWidgetHostViewAura::ScheduleEmbed(
- ui::mojom::WindowTreeClientPtr client,
+ ws::mojom::WindowTreeClientPtr client,
base::OnceCallback<void(const base::UnguessableToken&)> callback) {
- DCHECK(!features::IsAshInBrowserProcess());
+ DCHECK(features::IsUsingWindowService());
aura::Env::GetInstance()->ScheduleEmbed(std::move(client),
std::move(callback));
}
@@ -1749,7 +1763,7 @@ void RenderWidgetHostViewAura::OnWindowFocused(aura::Window* gained_focus,
// We need to honor input bypass if the associated tab is does not want
// input. This gives the current focused window a chance to be the text
// input client and handle events.
- if (host()->ignore_input_events())
+ if (host()->IsIgnoringInputEvents())
return;
host()->GotFocus();
@@ -1922,7 +1936,7 @@ void RenderWidgetHostViewAura::CreateAuraWindow(aura::client::WindowType type) {
if (frame_sink_id_.is_valid())
window_->SetEmbedFrameSinkId(frame_sink_id_);
- if (features::IsAshInBrowserProcess())
+ if (!features::IsUsingWindowService())
return;
// Embed the renderer into the Window.
@@ -1930,8 +1944,8 @@ void RenderWidgetHostViewAura::CreateAuraWindow(aura::client::WindowType type) {
// the visibility of |window_|.
aura::WindowPortMus::Get(window_)->Embed(
GetWindowTreeClientFromRenderer(),
- ui::mojom::kEmbedFlagEmbedderInterceptsEvents |
- ui::mojom::kEmbedFlagEmbedderControlsVisibility,
+ ws::mojom::kEmbedFlagEmbedderInterceptsEvents |
+ ws::mojom::kEmbedFlagEmbedderControlsVisibility,
base::BindOnce(&EmbedCallback));
}
@@ -1941,10 +1955,8 @@ void RenderWidgetHostViewAura::CreateDelegatedFrameHostClient() {
delegated_frame_host_client_ =
std::make_unique<DelegatedFrameHostClientAura>(this);
- const bool enable_viz =
- base::FeatureList::IsEnabled(features::kVizDisplayCompositor);
delegated_frame_host_ = std::make_unique<DelegatedFrameHost>(
- frame_sink_id_, delegated_frame_host_client_.get(), enable_viz,
+ frame_sink_id_, delegated_frame_host_client_.get(),
false /* should_register_frame_sink_id */);
// Let the page-level input event router know about our surface ID
@@ -2226,7 +2238,7 @@ void RenderWidgetHostViewAura::AddedToRootWindow() {
#endif
if (delegated_frame_host_)
- delegated_frame_host_->SetCompositor(window_->GetHost()->compositor());
+ delegated_frame_host_->AttachToCompositor(window_->GetHost()->compositor());
}
void RenderWidgetHostViewAura::RemovingFromRootWindow() {
@@ -2239,7 +2251,7 @@ void RenderWidgetHostViewAura::RemovingFromRootWindow() {
window_->GetHost()->RemoveObserver(this);
if (delegated_frame_host_)
- delegated_frame_host_->ResetCompositor();
+ delegated_frame_host_->DetachFromCompositor();
#if defined(OS_WIN)
// Update the legacy window's parent temporarily to the hidden window. It
@@ -2315,7 +2327,7 @@ void RenderWidgetHostViewAura::CreateSelectionController() {
}
void RenderWidgetHostViewAura::OnDidNavigateMainFrameToNewPage() {
- ui::GestureRecognizer::Get()->CancelActiveTouches(window_);
+ window_->env()->gesture_recognizer()->CancelActiveTouches(window_);
}
const viz::FrameSinkId& RenderWidgetHostViewAura::GetFrameSinkId() const {
@@ -2339,11 +2351,21 @@ void RenderWidgetHostViewAura::OnUpdateTextInputStateCalled(
GetInputMethod()->OnTextInputTypeChanged(this);
const TextInputState* state = text_input_manager_->GetTextInputState();
- if (state && state->show_ime_if_needed &&
- state->type != ui::TEXT_INPUT_TYPE_NONE &&
- state->mode != ui::TEXT_INPUT_MODE_NONE &&
- GetInputMethod()->GetTextInputClient() == this) {
- GetInputMethod()->ShowVirtualKeyboardIfEnabled();
+ if (state && state->type != ui::TEXT_INPUT_TYPE_NONE &&
+ state->mode != ui::TEXT_INPUT_MODE_NONE) {
+ bool show_virtual_keyboard = true;
+#if defined(OS_WIN)
+ show_virtual_keyboard =
+ last_pointer_type_ == ui::EventPointerType::POINTER_TYPE_TOUCH;
+#endif
+ if (state->show_ime_if_needed &&
+ GetInputMethod()->GetTextInputClient() == this &&
+ show_virtual_keyboard) {
+ GetInputMethod()->ShowVirtualKeyboardIfEnabled();
+ }
+ // Ensure that accessibility events are fired when the selection location
+ // moves from UI back to content.
+ text_input_manager->NotifySelectionBoundsChanged(updated_view);
}
if (auto* render_widget_host = updated_view->host()) {
@@ -2370,33 +2392,11 @@ void RenderWidgetHostViewAura::OnImeCancelComposition(
void RenderWidgetHostViewAura::OnSelectionBoundsChanged(
TextInputManager* text_input_manager,
RenderWidgetHostViewBase* updated_view) {
+ // Note: accessibility caret move events are no longer fired directly here,
+ // because they were redundant with the events fired by the top level window
+ // by HWNDMessageHandler::OnCaretBoundsChanged().
if (GetInputMethod())
GetInputMethod()->OnCaretBoundsChanged(this);
-
-#if defined(OS_WIN)
- RenderWidgetHostViewBase* focused_view = GetFocusedViewForTextSelection();
- if (!focused_view || !GetTextInputManager()->IsRegistered(focused_view))
- return;
-
- // Some assistive software need to track the location of the caret.
- if (!GetRenderWidgetHost() || !legacy_render_widget_host_HWND_)
- return;
-
- // Not using |GetCaretBounds| because it includes the whole of the selection,
- // not just the focus.
- const TextInputManager::SelectionRegion* region =
- GetTextInputManager()->GetSelectionRegion(focused_view);
- if (!region)
- return;
-
- const gfx::Rect caret_rect = ConvertRectToScreen(gfx::Rect(
- region->focus.edge_top_rounded().x(),
- region->focus.edge_top_rounded().y(), 1, region->focus.GetHeight()));
- gfx::Rect dip_caret_rect = display::win::ScreenWin::DIPToScreenRect(
- legacy_render_widget_host_HWND_->hwnd(), caret_rect);
- dip_caret_rect.set_width(1); // Collapse any selection.
- legacy_render_widget_host_HWND_->MoveCaretTo(dip_caret_rect);
-#endif // defined(OS_WIN)
}
void RenderWidgetHostViewAura::OnTextSelectionChanged(
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_aura.h b/chromium/content/browser/renderer_host/render_widget_host_view_aura.h
index 5f75e19c4a9..f237a3d5651 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -178,6 +178,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
base::Optional<viz::HitTestRegionList> hit_test_region_list) override;
void OnDidNotProduceFrame(const viz::BeginFrameAck& ack) override;
void ClearCompositorFrame() override;
+ void ResetFallbackToFirstNavigationSurface() override;
bool RequestRepaintForTesting() override;
void DidStopFlinging() override;
void OnDidNavigateMainFrameToNewPage() override;
@@ -197,7 +198,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
void FocusedNodeChanged(bool is_editable_node,
const gfx::Rect& node_bounds_in_screen) override;
- void ScheduleEmbed(ui::mojom::WindowTreeClientPtr client,
+ void ScheduleEmbed(ws::mojom::WindowTreeClientPtr client,
base::OnceCallback<void(const base::UnguessableToken&)>
callback) override;
void OnSynchronizedDisplayPropertiesChanged() override;
@@ -342,6 +343,12 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
void ScrollFocusedEditableNodeIntoRect(const gfx::Rect& rect);
+ // TODO(lanwei): Use TestApi interface to write functions that are used in
+ // tests and remove FRIEND_TEST_ALL_PREFIXES.
+ void SetLastPointerType(ui::EventPointerType last_pointer_type) {
+ last_pointer_type_ = last_pointer_type;
+ }
+
protected:
~RenderWidgetHostViewAura() override;
@@ -354,6 +361,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
// RenderWidgetHostViewBase:
void UpdateBackgroundColor() override;
+ bool HasFallbackSurface() const override;
private:
friend class DelegatedFrameHostClientAura;
@@ -408,6 +416,8 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
DiscardDelegatedFramesWithMemoryPressure);
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraKeyboardTest,
KeyboardObserverDestroyed);
+ FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraKeyboardTest,
+ KeyboardObserverForOnlyTouchInput);
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraSurfaceSynchronizationTest,
DropFallbackWhenHidden);
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraSurfaceSynchronizationTest,
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/chromium/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 9aac9b4c740..dba7c7d3e47 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -296,7 +296,7 @@ class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura {
return GetDelegatedFrameHost()->HasPrimarySurface();
}
- bool HasFallbackSurface() const {
+ bool HasFallbackSurface() const override {
return GetDelegatedFrameHost()->HasFallbackSurface();
}
@@ -304,8 +304,6 @@ class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura {
GetDelegatedFrameHost()->ReclaimResources(resources);
}
- void ResetCompositor() { GetDelegatedFrameHost()->ResetCompositor(); }
-
const ui::MotionEventAura& pointer_state() {
return event_handler()->pointer_state();
}
@@ -498,13 +496,16 @@ class RenderWidgetHostViewAuraTest : public testing::Test {
static void InstallDelegatedFrameHostClient(
RenderWidgetHostViewAura* view,
std::unique_ptr<DelegatedFrameHostClient> delegated_frame_host_client) {
+ // Follow RWHVAura code that does not create DelegateFrameHost when there is
+ // no valid frame sink id.
+ if (!view->frame_sink_id_.is_valid())
+ return;
+
view->delegated_frame_host_client_ = std::move(delegated_frame_host_client);
- const bool enable_viz =
- base::FeatureList::IsEnabled(features::kVizDisplayCompositor);
view->delegated_frame_host_ = nullptr;
view->delegated_frame_host_ = std::make_unique<DelegatedFrameHost>(
view->frame_sink_id_, view->delegated_frame_host_client_.get(),
- enable_viz, false /* should_register_frame_sink_id */);
+ false /* should_register_frame_sink_id */);
}
FakeRenderWidgetHostViewAura* CreateView(bool is_guest_view_hack) {
@@ -2230,15 +2231,22 @@ TEST_F(RenderWidgetHostViewAuraTest, TouchpadFlingStartResetsWheelPhaseState) {
EXPECT_EQ(15U, gesture_event->data.scroll_update.delta_y);
// A GFS is received showing that the user has lifted their fingers. This will
- // reset the scroll state of the wheel phase handler.
+ // reset the scroll state of the wheel phase handler. The velocity should be
+ // big enough to make sure that fling is still active while sending the scroll
+ // event.
ui::ScrollEvent fling_start(ui::ET_SCROLL_FLING_START, gfx::Point(2, 2),
- ui::EventTimeForNow(), 0, 0, 10, 0, 10, 2);
+ ui::EventTimeForNow(), 0, 0, 1000, 0, 1000, 2);
view_->OnScrollEvent(&fling_start);
base::RunLoop().RunUntilIdle();
events = GetAndResetDispatchedMessages();
- // A GFS with touchpad source won't get dispatched to the renderer.
- EXPECT_EQ(0U, events.size());
+ // A GFS with touchpad source won't get dispatched to the renderer. However,
+ // since progressFling is called right away after processing the GFS, it is
+ // possible that a progress event is sent if the time delta between GFS
+ // timestamp and the time that it gets processed is large enough.
+ bool progress_event_sent = events.size();
+ if (progress_event_sent)
+ EXPECT_EQ("MouseWheel GestureScrollUpdate", GetMessageNames(events));
// Handling the next ui::ET_SCROLL event will generate a GFC which resets the
// phase state. The fling controller processes GFC and generates a wheel event
@@ -2248,13 +2256,12 @@ TEST_F(RenderWidgetHostViewAuraTest, TouchpadFlingStartResetsWheelPhaseState) {
ui::EventTimeForNow(), 0, 0, 15, 0, 15, 2);
view_->OnScrollEvent(&scroll2);
base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(widget_host_->FlingCancellationIsDeferred());
events = GetAndResetDispatchedMessages();
- EXPECT_EQ("MouseWheel GestureScrollEnd MouseWheel", GetMessageNames(events));
+ EXPECT_EQ("MouseWheel", GetMessageNames(events));
wheel_event = static_cast<const WebMouseWheelEvent*>(
events[0]->ToEvent()->Event()->web_event.get());
- EXPECT_EQ(WebMouseWheelEvent::kPhaseEnded, wheel_event->momentum_phase);
- wheel_event = static_cast<const WebMouseWheelEvent*>(
- events[2]->ToEvent()->Event()->web_event.get());
EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, wheel_event->phase);
}
@@ -3035,7 +3042,7 @@ viz::CompositorFrame MakeDelegatedFrame(float scale_factor,
// This test verifies that returned resources do not require a pending ack.
TEST_F(RenderWidgetHostViewAuraTest, ReturnedResources) {
// TODO: fix for mash.
- if (!features::IsAshInBrowserProcess())
+ if (features::IsUsingWindowService())
return;
gfx::Size view_size(100, 100);
@@ -3069,7 +3076,7 @@ TEST_F(RenderWidgetHostViewAuraTest, TwoOutputSurfaces) {
// TODO(jonross): Delete this test once Viz launches as it will be obsolete.
// https://crbug.com/844469
if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor) ||
- !features::IsAshInBrowserProcess()) {
+ features::IsUsingWindowService()) {
return;
}
@@ -3211,7 +3218,7 @@ TEST_F(RenderWidgetHostViewAuraTest, ZeroSizeStillGetsLocalSurfaceId) {
TEST_F(RenderWidgetHostViewAuraTest, BackgroundColorMatchesCompositorFrame) {
// TODO: fix for mash.
- if (!features::IsAshInBrowserProcess())
+ if (features::IsUsingWindowService())
return;
gfx::Size frame_size(100, 100);
@@ -3376,7 +3383,7 @@ TEST_F(RenderWidgetHostViewAuraTest, OutputSurfaceIdChange) {
// TODO(jonross): Delete this test once Viz launches as it will be obsolete.
// https://crbug.com/844469
if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor) ||
- !features::IsAshInBrowserProcess()) {
+ features::IsUsingWindowService()) {
return;
}
@@ -3436,6 +3443,10 @@ TEST_F(RenderWidgetHostViewAuraTest, OutputSurfaceIdChange) {
// then the fallback is dropped.
TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest,
DropFallbackWhenHidden) {
+ // Early out because DelegatedFrameHost is not used in mash.
+ if (features::IsUsingWindowService())
+ return;
+
view_->InitAsChild(nullptr);
aura::client::ParentWindowWithContext(
view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(),
@@ -3460,6 +3471,10 @@ TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest,
// This test verifies that the primary SurfaceId is populated on resize and
// the fallback SurfaceId is populated in OnFirstSurfaceActivation.
TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest, SurfaceChanges) {
+ // Early out because DelegatedFrameHost is not used in mash.
+ if (features::IsUsingWindowService())
+ return;
+
view_->InitAsChild(nullptr);
aura::client::ParentWindowWithContext(
view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(),
@@ -3477,7 +3492,7 @@ TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest, SurfaceChanges) {
// Resizing should update the primary SurfaceId.
view_->SetSize(gfx::Size(400, 400));
EXPECT_EQ(gfx::Size(400, 400), view_->window_->layer()->size());
- EXPECT_FALSE(view_->window_->layer()->GetFallbackSurfaceId()->is_valid());
+ EXPECT_EQ(nullptr, view_->window_->layer()->GetFallbackSurfaceId());
EXPECT_EQ(gfx::Size(400, 400),
view_->delegated_frame_host_->CurrentFrameSizeInDipForTesting());
@@ -3496,7 +3511,7 @@ TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest, SurfaceChanges) {
TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest,
DeviceScaleFactorChanges) {
// TODO: fix for mash.
- if (!features::IsAshInBrowserProcess())
+ if (features::IsUsingWindowService())
return;
view_->InitAsChild(nullptr);
@@ -3509,7 +3524,7 @@ TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest,
EXPECT_EQ(gfx::Size(300, 300), view_->window_->layer()->size());
viz::SurfaceId initial_surface_id =
*view_->window_->layer()->GetPrimarySurfaceId();
- EXPECT_FALSE(view_->window_->layer()->GetFallbackSurfaceId()->is_valid());
+ EXPECT_EQ(nullptr, view_->window_->layer()->GetFallbackSurfaceId());
// Resizing should update the primary SurfaceId.
aura_test_helper_->test_screen()->SetDeviceScaleFactor(2.0f);
@@ -3526,7 +3541,7 @@ TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest,
// TODO(jonross): Delete this test once Viz launches as it will be obsolete.
// https://crbug.com/844469
if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor) ||
- !features::IsAshInBrowserProcess()) {
+ features::IsUsingWindowService()) {
return;
}
@@ -3560,6 +3575,10 @@ TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest,
// RenderWidgetHostViewAuraTest.DiscardDelegatedFrame.
TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest,
DiscardDelegatedFrames) {
+ // Early out because DelegatedFrameHost is not used in mash.
+ if (features::IsUsingWindowService())
+ return;
+
view_->InitAsChild(nullptr);
size_t max_renderer_frames =
@@ -3696,6 +3715,10 @@ TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest,
}
TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFramesWithLocking) {
+ // Early out because DelegatedFrameHost is not used in mash.
+ if (features::IsUsingWindowService())
+ return;
+
view_->InitAsChild(nullptr);
size_t max_renderer_frames =
@@ -3766,6 +3789,10 @@ TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFramesWithLocking) {
// Test that changing the memory pressure should delete saved frames. This test
// only applies to ChromeOS.
TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFramesWithMemoryPressure) {
+ // Early out because DelegatedFrameHost is not used in mash.
+ if (features::IsUsingWindowService())
+ return;
+
view_->InitAsChild(nullptr);
// The test logic below relies on having max_renderer_frames > 2. By default,
@@ -3870,7 +3897,7 @@ TEST_F(RenderWidgetHostViewAuraTest, ForwardsBeginFrameAcks) {
// TODO(jonross): Delete this test once Viz launches as it will be obsolete.
// https://crbug.com/844469
if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor) ||
- !features::IsAshInBrowserProcess()) {
+ features::IsUsingWindowService()) {
return;
}
@@ -4244,13 +4271,19 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest,
// Send a fling start, but with a small velocity, the fling controller handles
// GFS with touchpad source and the event doesn't get queued in gesture event
- // queue. The overscroll state doesn't get reset till the first ProgressFling
- // call.
+ // queue. The overscroll state doesn't get reset till the fling progress sends
+ // the fling end event.
SimulateGestureFlingStartEvent(0.f, 0.1f, blink::kWebGestureDeviceTouchpad);
events = GetAndResetDispatchedMessages();
- EXPECT_EQ(0U, events.size());
- EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode());
- EXPECT_EQ(OverscrollSource::TOUCHPAD, overscroll_source());
+ bool fling_end_event_sent_ = events.size();
+ if (fling_end_event_sent_) {
+ EXPECT_EQ("MouseWheel GestureScrollEnd", GetMessageNames(events));
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+ EXPECT_EQ(OverscrollSource::NONE, overscroll_source());
+ } else {
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode());
+ EXPECT_EQ(OverscrollSource::TOUCHPAD, overscroll_source());
+ }
base::TimeTicks progress_time =
base::TimeTicks::Now() + base::TimeDelta::FromMilliseconds(17);
@@ -5699,9 +5732,33 @@ TEST_F(RenderWidgetHostViewAuraTest, ForwardMouseEvent) {
view_ = nullptr;
}
+class TouchpadRenderWidgetHostViewAuraTest
+ : public RenderWidgetHostViewAuraTest,
+ public testing::WithParamInterface<bool> {
+ public:
+ TouchpadRenderWidgetHostViewAuraTest() {
+ if (GetParam()) {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kTouchpadAsyncPinchEvents);
+ } else {
+ scoped_feature_list_.InitAndDisableFeature(
+ features::kTouchpadAsyncPinchEvents);
+ }
+ }
+ ~TouchpadRenderWidgetHostViewAuraTest() override = default;
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+ DISALLOW_COPY_AND_ASSIGN(TouchpadRenderWidgetHostViewAuraTest);
+};
+
+INSTANTIATE_TEST_CASE_P(,
+ TouchpadRenderWidgetHostViewAuraTest,
+ testing::Bool());
+
// Test that we elide touchpad pinch gesture steams consisting of only begin
// and end events.
-TEST_F(RenderWidgetHostViewAuraTest, ElideEmptyTouchpadPinchSequence) {
+TEST_P(TouchpadRenderWidgetHostViewAuraTest, ElideEmptyTouchpadPinchSequence) {
ui::GestureEventDetails begin_details(ui::ET_GESTURE_PINCH_BEGIN);
begin_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHPAD);
ui::GestureEvent begin_event(0, 0, 0, ui::EventTimeForNow(), begin_details);
@@ -5740,7 +5797,7 @@ TEST_F(RenderWidgetHostViewAuraTest, ElideEmptyTouchpadPinchSequence) {
// Since we have not sent any GesturePinchUpdates by the time we get to the
// end of the pinch, the GesturePinchBegin and GesturePinchEnd events should
// be elided.
- EXPECT_EQ(0U, events.size());
+ EXPECT_EQ("MouseWheel", GetMessageNames(events));
}
TEST_F(RenderWidgetHostViewAuraTest, GestureTapFromStylusHasPointerType) {
@@ -5781,7 +5838,7 @@ TEST_F(RenderWidgetHostViewAuraTest, HitTestRegionListSubmitted) {
// TODO(jonross): Delete this test once Viz launches as it will be obsolete.
// https://crbug.com/844469
if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor) ||
- !features::IsAshInBrowserProcess()) {
+ features::IsUsingWindowService()) {
return;
}
@@ -5823,7 +5880,7 @@ TEST_F(RenderWidgetHostViewAuraTest, HitTestRegionListSubmitted) {
TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest,
NewContentRenderingTimeout) {
// TODO: fix for mash.
- if (!features::IsAshInBrowserProcess())
+ if (features::IsUsingWindowService())
return;
constexpr base::TimeDelta kTimeout = base::TimeDelta::FromMicroseconds(10);
@@ -5849,15 +5906,8 @@ TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest,
FROM_HERE, run_loop.QuitClosure(), 2 * kTimeout);
run_loop.Run();
}
- if (base::FeatureList::IsEnabled(features::kEnableSurfaceSynchronization)) {
- // When using surface sync, the timer should not fire, because the surface
- // id did not change.
- EXPECT_FALSE(widget_host_->new_content_rendering_timeout_fired());
- } else {
- // When not using surface sync, the timer will fire because the source id
- // changed.
- EXPECT_TRUE(widget_host_->new_content_rendering_timeout_fired());
- }
+
+ EXPECT_TRUE(widget_host_->new_content_rendering_timeout_fired());
widget_host_->reset_new_content_rendering_timeout_fired();
// Start the timer. Verify that a new LocalSurfaceId is allocated.
@@ -5879,29 +5929,13 @@ TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest,
}
EXPECT_TRUE(widget_host_->new_content_rendering_timeout_fired());
widget_host_->reset_new_content_rendering_timeout_fired();
-
- // Start the timer again. A new LocalSurfaceId should be allocated.
- widget_host_->DidNavigate(10);
- viz::LocalSurfaceId id3 = view_->GetLocalSurfaceId();
- EXPECT_LT(id2.parent_sequence_number(), id3.parent_sequence_number());
-
- // Submit to |id3|. Timer should not fire.
- view_->delegated_frame_host_->OnFirstSurfaceActivation(viz::SurfaceInfo(
- viz::SurfaceId(view_->GetFrameSinkId(), id3), 1, gfx::Size(20, 20)));
- {
- base::RunLoop run_loop;
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, run_loop.QuitClosure(), 2 * kTimeout);
- run_loop.Run();
- }
- EXPECT_FALSE(widget_host_->new_content_rendering_timeout_fired());
}
// If a tab is evicted, allocate a new LocalSurfaceId next time it's shown.
TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest,
AllocateLocalSurfaceIdOnEviction) {
// TODO: fix for mash.
- if (!features::IsAshInBrowserProcess())
+ if (features::IsUsingWindowService())
return;
view_->InitAsChild(nullptr);
@@ -5923,6 +5957,10 @@ TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest,
// visible we show blank.
TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest,
DropFallbackIfResizedWhileHidden) {
+ // Early out because DelegatedFrameHost is not used in mash.
+ if (features::IsUsingWindowService())
+ return;
+
view_->InitAsChild(nullptr);
aura::client::ParentWindowWithContext(
view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(),
@@ -5935,13 +5973,17 @@ TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest,
view_->Hide();
view_->SetSize(gfx::Size(54, 32));
view_->Show();
- EXPECT_FALSE(view_->window_->layer()->GetFallbackSurfaceId()->is_valid());
+ EXPECT_EQ(nullptr, view_->window_->layer()->GetFallbackSurfaceId());
}
// If a tab is hidden and shown without being resized in the meantime, the
// fallback SurfaceId has to be preserved.
TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest,
DontDropFallbackIfNotResizedWhileHidden) {
+ // Early out because DelegatedFrameHost is not used in mash.
+ if (features::IsUsingWindowService())
+ return;
+
view_->InitAsChild(nullptr);
aura::client::ParentWindowWithContext(
view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(),
@@ -5960,6 +6002,10 @@ TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest,
// background color from the previous view to the new view.
TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest,
TakeFallbackContent) {
+ // Early out because DelegatedFrameHost is not used in mash.
+ if (features::IsUsingWindowService())
+ return;
+
// Initialize the first view.
view_->InitAsChild(nullptr);
aura::client::ParentWindowWithContext(
@@ -6735,6 +6781,7 @@ class RenderWidgetHostViewAuraKeyboardTest
};
TEST_F(RenderWidgetHostViewAuraKeyboardTest, KeyboardObserverDestroyed) {
+ parent_view_->SetLastPointerType(ui::EventPointerType::POINTER_TYPE_TOUCH);
parent_view_->FocusedNodeTouched(true);
EXPECT_NE(parent_view_->keyboard_observer_.get(), nullptr);
EXPECT_EQ(keyboard_controller_observer_count(), 1u);
@@ -6744,6 +6791,20 @@ TEST_F(RenderWidgetHostViewAuraKeyboardTest, KeyboardObserverDestroyed) {
EXPECT_EQ(keyboard_controller_observer_count(), 0u);
}
+TEST_F(RenderWidgetHostViewAuraKeyboardTest,
+ KeyboardObserverForOnlyTouchInput) {
+ // Show virtual keyboard for touch inputs.
+ parent_view_->SetLastPointerType(ui::EventPointerType::POINTER_TYPE_TOUCH);
+ parent_view_->FocusedNodeTouched(true);
+ EXPECT_NE(parent_view_->keyboard_observer_.get(), nullptr);
+ EXPECT_EQ(keyboard_controller_observer_count(), 1u);
+ // Do not show virtual keyboard for mouse inputs.
+ parent_view_->SetLastPointerType(ui::EventPointerType::POINTER_TYPE_MOUSE);
+ parent_view_->FocusedNodeTouched(true);
+ EXPECT_EQ(parent_view_->keyboard_observer_.get(), nullptr);
+ EXPECT_EQ(keyboard_controller_observer_count(), 0u);
+}
+
#endif // defined(OS_WIN)
} // namespace content
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_base.cc b/chromium/content/browser/renderer_host/render_widget_host_view_base.cc
index 5561b7a1f38..fae4c74c977 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_base.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -161,6 +161,10 @@ int RenderWidgetHostViewBase::GetMouseWheelMinimumGranularity() const {
return 0;
}
+RenderWidgetHostViewBase* RenderWidgetHostViewBase::GetRootView() {
+ return this;
+}
+
void RenderWidgetHostViewBase::SelectionChanged(const base::string16& text,
size_t offset,
const gfx::Range& range) {
@@ -233,6 +237,12 @@ gfx::Range RenderWidgetHostViewBase::GetSelectedRange() {
return GetTextInputManager()->GetTextSelection(this)->range();
}
+size_t RenderWidgetHostViewBase::GetOffsetForSurroundingText() {
+ if (!GetTextInputManager())
+ return 0;
+ return GetTextInputManager()->GetTextSelection(this)->offset();
+}
+
void RenderWidgetHostViewBase::SetBackgroundColor(SkColor color) {
DCHECK(SkColorGetA(color) == SK_AlphaOPAQUE ||
SkColorGetA(color) == SK_AlphaTRANSPARENT);
@@ -346,6 +356,11 @@ void RenderWidgetHostViewBase::ForwardTouchpadPinchIfNecessary(
}
}
+bool RenderWidgetHostViewBase::HasFallbackSurface() const {
+ NOTREACHED();
+ return false;
+}
+
void RenderWidgetHostViewBase::SetPopupType(blink::WebPopupType popup_type) {
popup_type_ = popup_type;
}
@@ -385,6 +400,12 @@ bool RenderWidgetHostViewBase::RequestRepaintForTesting() {
return false;
}
+void RenderWidgetHostViewBase::ProcessAckedTouchEvent(
+ const TouchEventWithLatencyInfo& touch,
+ InputEventAckState ack_result) {
+ NOTREACHED();
+}
+
void RenderWidgetHostViewBase::UpdateScreenInfo(gfx::NativeView view) {
if (host() && host()->delegate())
host()->delegate()->SendScreenRects();
@@ -488,12 +509,6 @@ void RenderWidgetHostViewBase::DidReceiveRendererFrame() {
++renderer_frame_number_;
}
-void RenderWidgetHostViewBase::ShowDisambiguationPopup(
- const gfx::Rect& rect_pixels,
- const SkBitmap& zoomed_bitmap) {
- NOTIMPLEMENTED_LOG_ONCE();
-}
-
void RenderWidgetHostViewBase::OnAutoscrollStart() {
if (!GetMouseWheelPhaseHandler())
return;
@@ -719,7 +734,7 @@ RenderWidgetHostViewBase::GetTouchSelectionControllerClientManager() {
void RenderWidgetHostViewBase::EmbedChildFrameRendererWindowTreeClient(
RenderWidgetHostViewBase* root_view,
int routing_id,
- ui::mojom::WindowTreeClientPtr renderer_window_tree_client) {
+ ws::mojom::WindowTreeClientPtr renderer_window_tree_client) {
RenderWidgetHost* render_widget_host = GetRenderWidgetHost();
if (!render_widget_host)
return;
@@ -761,19 +776,19 @@ void RenderWidgetHostViewBase::OnDidScheduleEmbed(
}
void RenderWidgetHostViewBase::ScheduleEmbed(
- ui::mojom::WindowTreeClientPtr client,
+ ws::mojom::WindowTreeClientPtr client,
base::OnceCallback<void(const base::UnguessableToken&)> callback) {
NOTREACHED();
}
-ui::mojom::WindowTreeClientPtr
+ws::mojom::WindowTreeClientPtr
RenderWidgetHostViewBase::GetWindowTreeClientFromRenderer() {
// NOTE: this function may be called multiple times.
RenderWidgetHost* render_widget_host = GetRenderWidgetHost();
mojom::RenderWidgetWindowTreeClientFactoryPtr factory;
BindInterface(render_widget_host->GetProcess(), &factory);
- ui::mojom::WindowTreeClientPtr window_tree_client;
+ ws::mojom::WindowTreeClientPtr window_tree_client;
factory->CreateWindowTreeClientForRenderWidget(
render_widget_host->GetRoutingID(),
mojo::MakeRequest(&window_tree_client),
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_base.h b/chromium/content/browser/renderer_host/render_widget_host_view_base.h
index 8ed6ffd3a28..08454f68a01 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_base.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_base.h
@@ -46,9 +46,8 @@
#if defined(USE_AURA)
#include "base/containers/flat_map.h"
#include "content/common/render_widget_window_tree_client_factory.mojom.h"
-#include "services/ui/public/interfaces/window_tree.mojom.h"
+#include "services/ws/public/mojom/window_tree.mojom.h"
#endif
-class SkBitmap;
struct ViewHostMsg_SelectionBounds_Params;
@@ -118,6 +117,7 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
base::string16 GetSelectedText() override;
base::string16 GetSurroundingText() override;
gfx::Range GetSelectedRange() override;
+ size_t GetOffsetForSurroundingText() override;
bool IsMouseLocked() override;
bool LockKeyboard(base::Optional<base::flat_set<ui::DomCode>> codes) override;
void SetBackgroundColor(SkColor color) override;
@@ -199,6 +199,10 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
//----------------------------------------------------------------------------
// The following methods can be overridden by derived classes.
+ // Returns the root-view associated with this view. Always returns |this| for
+ // non-embeddable derived views.
+ virtual RenderWidgetHostViewBase* GetRootView();
+
// Notifies the View that the renderer text selection has changed.
virtual void SelectionChanged(const base::string16& text,
size_t offset,
@@ -296,6 +300,9 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
// with what is visible on screen.
virtual void ClearCompositorFrame() = 0;
+ // This method will reset the fallback to the first surface after navigation.
+ virtual void ResetFallbackToFirstNavigationSurface() = 0;
+
// Requests a new CompositorFrame from the renderer. This is done by
// allocating a new viz::LocalSurfaceId which forces a commit and draw.
virtual bool RequestRepaintForTesting();
@@ -308,7 +315,7 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
// |touch|'s coordinates are in the coordinate space of the view to which it
// was targeted.
virtual void ProcessAckedTouchEvent(const TouchEventWithLatencyInfo& touch,
- InputEventAckState ack_result) {}
+ InputEventAckState ack_result);
virtual void DidOverscroll(const ui::DidOverscrollParams& params) {}
@@ -373,9 +380,11 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
const gfx::PointF& point,
const viz::SurfaceId& original_surface,
gfx::PointF* transformed_point);
-
- // Transform a point that is in the coordinate space for the current
- // RenderWidgetHostView to the coordinate space of the target_view.
+ // Given a RenderWidgetHostViewBase that renders to a Surface that is
+ // contained within this class' Surface, find the relative transform between
+ // the Surfaces and apply it to a point. Returns false if a Surface has not
+ // yet been created or if |target_view| is not a descendant RWHV from our
+ // client.
virtual bool TransformPointToCoordSpaceForView(
const gfx::PointF& point,
RenderWidgetHostViewBase* target_view,
@@ -413,6 +422,9 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
// Returns true if this view's size have been initialized.
virtual bool HasSize() const;
+ // Informs the view that the assocaited InterstitialPage was attached.
+ virtual void OnInterstitialPageAttached() {}
+
// Tells the view that the assocaited InterstitialPage will going away (but is
// not yet destroyed, as InterstitialPage destruction is asynchronous). The
// view may use this notification to clean up associated resources. This
@@ -495,11 +507,6 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
// Gets the bounds of the top-level window, in screen coordinates.
virtual gfx::Rect GetBoundsInRootWindow() = 0;
- // Called by the RenderWidgetHost when an ambiguous gesture is detected to
- // show the disambiguation popup bubble.
- virtual void ShowDisambiguationPopup(const gfx::Rect& rect_pixels,
- const SkBitmap& zoomed_bitmap);
-
// Called by the WebContentsImpl when a user tries to navigate a new page on
// main frame.
virtual void OnDidNavigateMainFrameToNewPage();
@@ -553,7 +560,7 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
void EmbedChildFrameRendererWindowTreeClient(
RenderWidgetHostViewBase* root_view,
int routing_id,
- ui::mojom::WindowTreeClientPtr renderer_window_tree_client);
+ ws::mojom::WindowTreeClientPtr renderer_window_tree_client);
void OnChildFrameDestroyed(int routing_id);
#endif
@@ -591,10 +598,10 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
#if defined(USE_AURA)
virtual void ScheduleEmbed(
- ui::mojom::WindowTreeClientPtr client,
+ ws::mojom::WindowTreeClientPtr client,
base::OnceCallback<void(const base::UnguessableToken&)> callback);
- ui::mojom::WindowTreeClientPtr GetWindowTreeClientFromRenderer();
+ ws::mojom::WindowTreeClientPtr GetWindowTreeClientFromRenderer();
#endif
// If |event| is a touchpad pinch event for which we've sent a synthetic
@@ -604,6 +611,8 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
const blink::WebGestureEvent& event,
InputEventAckState ack_result);
+ virtual bool HasFallbackSurface() const;
+
// The model object. Members will become private when
// RenderWidgetHostViewGuest is removed.
RenderWidgetHostImpl* host_;
@@ -686,7 +695,7 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
uint32_t renderer_frame_number_;
- base::ObserverList<RenderWidgetHostViewBaseObserver> observers_;
+ base::ObserverList<RenderWidgetHostViewBaseObserver>::Unchecked observers_;
#if defined(USE_AURA)
mojom::RenderWidgetWindowTreeClientPtr render_widget_window_tree_client_;
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/chromium/content/browser/renderer_host/render_widget_host_view_child_frame.cc
index 08e68296f2a..ef607a087cd 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_child_frame.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_child_frame.cc
@@ -49,7 +49,7 @@
#include "ui/touch_selection/touch_selection_controller.h"
#if defined(USE_AURA)
-#include "services/ui/public/interfaces/window_tree.mojom.h"
+#include "services/ws/public/mojom/window_tree.mojom.h"
#include "ui/aura/env.h"
#endif
@@ -74,7 +74,7 @@ RenderWidgetHostViewChildFrame::RenderWidgetHostViewChildFrame(
enable_viz_(
base::FeatureList::IsEnabled(features::kVizDisplayCompositor)),
weak_factory_(this) {
- if (!features::IsAshInBrowserProcess()) {
+ if (features::IsUsingWindowService()) {
// In Mus the RenderFrameProxy will eventually assign a viz::FrameSinkId
// until then set ours invalid, as operations using it will be disregarded.
frame_sink_id_ = viz::FrameSinkId();
@@ -93,7 +93,7 @@ RenderWidgetHostViewChildFrame::~RenderWidgetHostViewChildFrame() {
if (frame_connector_)
DetachFromTouchSelectionClientManagerIfNecessary();
- if (features::IsAshInBrowserProcess()) {
+ if (!features::IsUsingWindowService()) {
ResetCompositorFrameSinkSupport();
if (GetHostFrameSinkManager())
GetHostFrameSinkManager()->InvalidateFrameSinkId(frame_sink_id_);
@@ -147,7 +147,7 @@ void RenderWidgetHostViewChildFrame::SetFrameConnectorDelegate(
if (parent_view) {
DCHECK(parent_view->GetFrameSinkId().is_valid() ||
- !features::IsAshInBrowserProcess());
+ features::IsUsingWindowService());
SetParentFrameSinkId(parent_view->GetFrameSinkId());
}
@@ -168,7 +168,7 @@ void RenderWidgetHostViewChildFrame::SetFrameConnectorDelegate(
}
#if defined(USE_AURA)
- if (!features::IsAshInBrowserProcess()) {
+ if (features::IsUsingWindowService()) {
frame_connector_->EmbedRendererWindowTreeClientInParent(
GetWindowTreeClientFromRenderer());
}
@@ -180,7 +180,7 @@ void RenderWidgetHostViewChildFrame::SetFrameConnectorDelegate(
#if defined(USE_AURA)
void RenderWidgetHostViewChildFrame::SetFrameSinkId(
const viz::FrameSinkId& frame_sink_id) {
- if (!features::IsAshInBrowserProcess())
+ if (features::IsUsingWindowService())
frame_sink_id_ = frame_sink_id;
}
#endif // defined(USE_AURA)
@@ -375,6 +375,11 @@ gfx::Size RenderWidgetHostViewChildFrame::GetCompositorViewportPixelSize()
return gfx::Size();
}
+RenderWidgetHostViewBase* RenderWidgetHostViewChildFrame::GetRootView() {
+ return frame_connector_ ? frame_connector_->GetRootRenderWidgetHostView()
+ : nullptr;
+}
+
void RenderWidgetHostViewChildFrame::InitAsPopup(
RenderWidgetHostView* parent_host_view,
const gfx::Rect& bounds) {
@@ -472,11 +477,13 @@ void RenderWidgetHostViewChildFrame::UnregisterFrameSinkId() {
void RenderWidgetHostViewChildFrame::UpdateViewportIntersection(
const gfx::Rect& viewport_intersection,
- const gfx::Rect& compositor_visible_rect) {
+ const gfx::Rect& compositor_visible_rect,
+ bool occluded_or_obscured) {
if (host()) {
- host()->Send(new ViewMsg_SetViewportIntersection(host()->GetRoutingID(),
- viewport_intersection,
- compositor_visible_rect));
+ host()->SetIntersectsViewport(!viewport_intersection.IsEmpty());
+ host()->Send(new ViewMsg_SetViewportIntersection(
+ host()->GetRoutingID(), viewport_intersection, compositor_visible_rect,
+ occluded_or_obscured));
}
}
@@ -517,6 +524,37 @@ void RenderWidgetHostViewChildFrame::GestureEventAck(
ack_result == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS ||
ack_result == INPUT_EVENT_ACK_STATE_CONSUMED_SHOULD_BUBBLE;
+ bool touchpad_fling_start_bubbles = false;
+// GSU events with inertial phase are generated from touchpad fling only on
+// ChromeOS. Other platforms either don't have touchpad-based GSUs with inertial
+// phase (e.g., Linux/Android, or Windows with low precision touchpads) or
+// generate them from the OS rather than the fling controller (e.g., Mac, or
+// Windows with high precision touchpads). |touchpad_fling_start_bubbles| is
+// true on ChromeOS to show that on this platform we do not need to bubble
+// touchpad-based GSU events with inertial phase, since touchpad-based fling
+// start gets bubbled instead and the fling controller of the parent will take
+// care of touchpad-based inertial GSUs event creation from the bubbled touchpad
+// fling.
+#if defined(CHROMEOS)
+ touchpad_fling_start_bubbles = true;
+#endif // defined(CHROMEOS)
+
+ // When a GFS is bubbled, we still send it to the fling controller of the
+ // child view to finish the scroll sequence. However the GSU and GSE events
+ // that are generated by the child view's fling controller do not need to get
+ // bubbled since the GFS event itself is bubbled and the target's fling
+ // controller will take care of flinging.
+ if (((event.GetType() == blink::WebInputEvent::kGestureScrollEnd &&
+ event.data.scroll_end.inertial_phase ==
+ blink::WebGestureEvent::kMomentumPhase) ||
+ (event.GetType() == blink::WebInputEvent::kGestureScrollUpdate &&
+ event.data.scroll_update.inertial_phase ==
+ blink::WebGestureEvent::kMomentumPhase)) &&
+ (event.SourceDevice() != blink::kWebGestureDeviceTouchpad ||
+ touchpad_fling_start_bubbles)) {
+ return;
+ }
+
if ((event.GetType() == blink::WebInputEvent::kGestureScrollBegin) &&
should_bubble) {
DCHECK(!is_scroll_sequence_bubbling_);
@@ -535,7 +573,8 @@ void RenderWidgetHostViewChildFrame::GestureEventAck(
should_bubble) ||
event.GetType() == blink::WebInputEvent::kGestureScrollUpdate ||
event.GetType() == blink::WebInputEvent::kGestureScrollEnd ||
- event.GetType() == blink::WebInputEvent::kGestureFlingStart) {
+ event.GetType() == blink::WebInputEvent::kGestureFlingStart ||
+ event.GetType() == blink::WebInputEvent::kGestureFlingCancel) {
frame_connector_->BubbleScrollEvent(event);
}
}
@@ -580,7 +619,7 @@ void RenderWidgetHostViewChildFrame::DidCreateNewRendererCompositorFrameSink(
void RenderWidgetHostViewChildFrame::SetParentFrameSinkId(
const viz::FrameSinkId& parent_frame_sink_id) {
if (parent_frame_sink_id_ == parent_frame_sink_id ||
- !features::IsAshInBrowserProcess())
+ features::IsUsingWindowService())
return;
auto* host_frame_sink_manager = GetHostFrameSinkManager();
@@ -601,7 +640,7 @@ void RenderWidgetHostViewChildFrame::SetParentFrameSinkId(
}
void RenderWidgetHostViewChildFrame::SendSurfaceInfoToEmbedder() {
- if (!features::IsAshInBrowserProcess())
+ if (features::IsUsingWindowService())
return;
if (!last_activated_surface_info_.is_valid())
return;
@@ -661,15 +700,6 @@ gfx::Rect RenderWidgetHostViewChildFrame::GetBoundsInRootWindow() {
return rect;
}
-void RenderWidgetHostViewChildFrame::ProcessAckedTouchEvent(
- const TouchEventWithLatencyInfo& touch,
- InputEventAckState ack_result) {
- if (!frame_connector_)
- return;
-
- frame_connector_->ForwardProcessAckedTouchEvent(touch, ack_result);
-}
-
void RenderWidgetHostViewChildFrame::DidStopFlinging() {
if (selection_controller_client_)
selection_controller_client_->DidStopFlinging();
@@ -812,7 +842,8 @@ void RenderWidgetHostViewChildFrame::WillSendScreenRects() {
// until somebody figures that out. RWHVCF::Init() is too early.
if (frame_connector_) {
UpdateViewportIntersection(frame_connector_->viewport_intersection_rect(),
- frame_connector_->compositor_visible_rect());
+ frame_connector_->compositor_visible_rect(),
+ frame_connector_->occluded_or_obscured());
SetIsInert();
UpdateInheritedEffectiveTouchAction();
UpdateRenderThrottlingStatus();
@@ -1067,7 +1098,7 @@ RenderWidgetHostViewChildFrame::DidUpdateVisualProperties(
}
void RenderWidgetHostViewChildFrame::CreateCompositorFrameSinkSupport() {
- if (!features::IsAshInBrowserProcess() || enable_viz_)
+ if (features::IsUsingWindowService() || enable_viz_)
return;
DCHECK(!support_);
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_child_frame.h b/chromium/content/browser/renderer_host/render_widget_host_view_child_frame.h
index f5a326cdc98..ba8c25a4021 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_child_frame.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_child_frame.h
@@ -114,6 +114,7 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame
void TakeFallbackContentFrom(RenderWidgetHostView* view) override;
// RenderWidgetHostViewBase implementation.
+ RenderWidgetHostViewBase* GetRootView() override;
void InitAsPopup(RenderWidgetHostView* parent_host_view,
const gfx::Rect& bounds) override;
void InitAsFullscreen(RenderWidgetHostView* reference_host_view) override;
@@ -136,10 +137,10 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame
// Since the URL of content rendered by this class is not displayed in
// the URL bar, this method does not need an implementation.
void ClearCompositorFrame() override {}
+ void ResetFallbackToFirstNavigationSurface() override{};
+
void TransformPointToRootSurface(gfx::PointF* point) override;
gfx::Rect GetBoundsInRootWindow() override;
- void ProcessAckedTouchEvent(const TouchEventWithLatencyInfo& touch,
- InputEventAckState ack_result) override;
void DidStopFlinging() override;
bool LockMouse() override;
void UnlockMouse() override;
@@ -225,7 +226,8 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame
void UnregisterFrameSinkId();
void UpdateViewportIntersection(const gfx::Rect& viewport_intersection,
- const gfx::Rect& compositor_visible_rect);
+ const gfx::Rect& compositor_visible_rect,
+ bool occluded_or_obscured);
// TODO(sunxd): Rename SetIsInert to UpdateIsInert.
void SetIsInert();
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc b/chromium/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
index 6c9a0a1bc04..96d0d44860b 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
@@ -160,7 +160,7 @@ IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewChildFrameTest,
IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewChildFrameTest, ChildFrameSinkId) {
// Only when mus hosts viz do we expect a RenderFrameProxy to provide the
// FrameSinkId.
- if (features::IsAshInBrowserProcess())
+ if (!features::IsUsingWindowService())
return;
GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc b/chromium/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc
index d888709145d..4eff713dfc4 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc
@@ -230,7 +230,7 @@ TEST_F(RenderWidgetHostViewChildFrameTest, ViewportIntersectionUpdated) {
process->sink().GetUniqueMessageMatching(
ViewMsg_SetViewportIntersection::ID);
ASSERT_TRUE(intersection_update);
- std::tuple<gfx::Rect, gfx::Rect> sent_rects;
+ std::tuple<gfx::Rect, gfx::Rect, bool> sent_rects;
ViewMsg_SetViewportIntersection::Read(intersection_update, &sent_rects);
EXPECT_EQ(intersection_rect, std::get<0>(sent_rects));
@@ -282,7 +282,7 @@ TEST_F(RenderWidgetHostViewChildFrameTest, WasResizedOncePerChange) {
constexpr gfx::Size compositor_viewport_pixel_size(100, 100);
constexpr gfx::Rect screen_space_rect(compositor_viewport_pixel_size);
viz::ParentLocalSurfaceIdAllocator allocator;
- viz::LocalSurfaceId local_surface_id = allocator.GenerateId();
+ viz::LocalSurfaceId local_surface_id = allocator.GetCurrentLocalSurfaceId();
constexpr viz::FrameSinkId frame_sink_id(1, 1);
const viz::SurfaceId surface_id(frame_sink_id, local_surface_id);
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_cocoa.h b/chromium/content/browser/renderer_host/render_widget_host_view_cocoa.h
index b2d9cecb8e2..83af25a5814 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_cocoa.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_cocoa.h
@@ -189,6 +189,12 @@ struct DidOverscrollParams;
// The filter used to guide touch events towards a horizontal or vertical
// orientation.
content::MouseWheelRailsFilterMac mouseWheelFilter_;
+
+ // Whether the direct manipulation feature is enabled.
+ bool direct_manipulation_enabled_;
+
+ // Whether the pen's tip is in contact with the stylus digital tablet.
+ bool has_pen_contact_;
}
@property(nonatomic, assign) NSRange markedRange;
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_cocoa.mm b/chromium/content/browser/renderer_host/render_widget_host_view_cocoa.mm
index 8b84322baa8..92f940ef023 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_cocoa.mm
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_cocoa.mm
@@ -24,6 +24,7 @@
#import "ui/base/clipboard/clipboard_util_mac.h"
#import "ui/base/cocoa/appkit_utils.h"
#include "ui/base/cocoa/cocoa_base_utils.h"
+#include "ui/base/ui_base_features.h"
#include "ui/display/screen.h"
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/dom/dom_code.h"
@@ -41,10 +42,12 @@ using content::RenderWidgetHostViewMacEditCommandHelper;
using content::WebGestureEventBuilder;
using content::WebMouseEventBuilder;
using content::WebMouseWheelEventBuilder;
+using content::WebTouchEventBuilder;
using blink::WebInputEvent;
using blink::WebMouseEvent;
using blink::WebMouseWheelEvent;
using blink::WebGestureEvent;
+using blink::WebTouchEvent;
namespace {
@@ -87,6 +90,10 @@ class ForwardingLocalClient : public RenderWidgetHostNSViewLocalClient {
const blink::WebMouseEvent& web_event) override {
client_->RouteOrProcessMouseEvent(TranslateEvent(web_event));
}
+ void RouteOrProcessTouchEvent(
+ const blink::WebTouchEvent& web_event) override {
+ client_->RouteOrProcessTouchEvent(TranslateEvent(web_event));
+ }
void RouteOrProcessWheelEvent(
const blink::WebMouseWheelEvent& web_event) override {
client_->RouteOrProcessWheelEvent(TranslateEvent(web_event));
@@ -223,6 +230,9 @@ void ExtractUnderlines(NSAttributedString* string,
isStylusEnteringProximity_ = false;
keyboardLockActive_ = false;
textInputType_ = ui::TEXT_INPUT_TYPE_NONE;
+ direct_manipulation_enabled_ =
+ base::FeatureList::IsEnabled(features::kDirectManipulationStylus);
+ has_pen_contact_ = false;
}
return self;
}
@@ -542,9 +552,37 @@ void ExtractUnderlines(NSAttributedString* string,
if (type == NSMouseMoved)
cursorHidden_ = NO;
- WebMouseEvent event =
- WebMouseEventBuilder::Build(theEvent, self, pointerType_);
- localClient_->RouteOrProcessMouseEvent(event);
+ bool send_touch =
+ direct_manipulation_enabled_ &&
+ pointerType_ == blink::WebPointerProperties::PointerType::kPen;
+
+ // Send touch events when the pen is in contact with the tablet.
+ if (send_touch) {
+ // Because the NSLeftMouseUp event's buttonMask is not
+ // NSEventButtonMaskPenTip, we read |has_pen_contact_| to ensure a
+ // TouchRelease is sent appropriately at the end when the stylus is
+ // no longer in contact with the digitizer.
+ send_touch = has_pen_contact_;
+ if (type == NSLeftMouseDown || type == NSLeftMouseUp ||
+ type == NSLeftMouseDragged) {
+ NSEventButtonMask buttonMask = [theEvent buttonMask];
+ if (buttonMask == NSEventButtonMaskPenTip) {
+ DCHECK(type != NSLeftMouseUp);
+ send_touch = has_pen_contact_ = true;
+ } else {
+ has_pen_contact_ = false;
+ }
+ }
+ }
+
+ if (!send_touch) {
+ WebMouseEvent event =
+ WebMouseEventBuilder::Build(theEvent, self, pointerType_);
+ localClient_->RouteOrProcessMouseEvent(event);
+ } else {
+ WebTouchEvent event = WebTouchEventBuilder::Build(theEvent, self);
+ localClient_->RouteOrProcessTouchEvent(event);
+ }
}
- (void)tabletEvent:(NSEvent*)theEvent {
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_mac.h b/chromium/content/browser/renderer_host/render_widget_host_view_mac.h
index 052bcb2791c..e25f39d32e7 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_mac.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -149,6 +149,7 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
base::Optional<viz::HitTestRegionList> hit_test_region_list) override;
void OnDidNotProduceFrame(const viz::BeginFrameAck& ack) override;
void ClearCompositorFrame() override;
+ void ResetFallbackToFirstNavigationSurface() override;
bool RequestRepaintForTesting() override;
BrowserAccessibilityManager* CreateBrowserAccessibilityManager(
BrowserAccessibilityDelegate* delegate, bool for_root_frame) override;
@@ -308,6 +309,7 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
const ui::LatencyInfo& latency_info,
const std::vector<EditCommand>& commands) override;
void RouteOrProcessMouseEvent(const blink::WebMouseEvent& web_event) override;
+ void RouteOrProcessTouchEvent(const blink::WebTouchEvent& web_event) override;
void RouteOrProcessWheelEvent(
const blink::WebMouseWheelEvent& web_event) override;
void ForwardMouseEvent(const blink::WebMouseEvent& web_event) override;
@@ -339,6 +341,7 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
bool skip_in_browser,
const std::vector<EditCommand>& commands) override;
void RouteOrProcessMouseEvent(std::unique_ptr<InputEvent> event) override;
+ void RouteOrProcessTouchEvent(std::unique_ptr<InputEvent> event) override;
void RouteOrProcessWheelEvent(std::unique_ptr<InputEvent> event) override;
void ForwardMouseEvent(std::unique_ptr<InputEvent> event) override;
void ForwardWheelEvent(std::unique_ptr<InputEvent> event) override;
@@ -392,7 +395,6 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
SkColor BrowserCompositorMacGetGutterColor() const override;
void BrowserCompositorMacOnBeginFrame(base::TimeTicks frame_time) override;
void OnFrameTokenChanged(uint32_t frame_token) override;
- void DidReceiveFirstFrameAfterNavigation() override;
void DestroyCompositorForShutdown() override;
bool SynchronizeVisualProperties(
const base::Optional<viz::LocalSurfaceId>&
@@ -488,6 +490,7 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
// RenderWidgetHostViewBase:
void UpdateBackgroundColor() override;
+ bool HasFallbackSurface() const override;
// Gets a textual view of the page's contents, and passes it to the callback
// provided.
@@ -535,11 +538,6 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
// Display link for getting vsync info.
scoped_refptr<ui::DisplayLinkMac> display_link_;
- // The current VSync timebase and interval. This is zero until the first call
- // to SendVSyncParametersToRenderer(), and refreshed regularly thereafter.
- base::TimeTicks vsync_timebase_;
- base::TimeDelta vsync_interval_;
-
// Whether a request for begin frames has been issued.
bool needs_begin_frames_;
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_mac.mm b/chromium/content/browser/renderer_host/render_widget_host_view_mac.mm
index 0703dd02c90..7e3a9aa6adc 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -91,10 +91,6 @@ void RenderWidgetHostViewMac::OnFrameTokenChanged(uint32_t frame_token) {
OnFrameTokenChangedForView(frame_token);
}
-void RenderWidgetHostViewMac::DidReceiveFirstFrameAfterNavigation() {
- host()->DidReceiveFirstFrameAfterNavigation();
-}
-
void RenderWidgetHostViewMac::DestroyCompositorForShutdown() {
// When RenderWidgetHostViewMac was owned by an NSView, this function was
// necessary to ensure that the ui::Compositor did not outlive the
@@ -138,8 +134,13 @@ void RenderWidgetHostViewMac::AcceleratedWidgetCALayerParamsUpdated() {
if (ca_layer_params)
ns_view_bridge_->SetCALayerParams(*ca_layer_params);
- if (display_link_)
- display_link_->NotifyCurrentTime(base::TimeTicks::Now());
+ // Take this opportunity to update the VSync parameters, if needed.
+ if (display_link_) {
+ base::TimeTicks timebase;
+ base::TimeDelta interval;
+ if (display_link_->GetVSyncParameters(&timebase, &interval))
+ browser_compositor_->UpdateVSyncParameters(timebase, interval);
+ }
}
///////////////////////////////////////////////////////////////////////////////
@@ -293,19 +294,6 @@ void RenderWidgetHostViewMac::InitAsFullscreen(
NOTREACHED();
}
-void RenderWidgetHostViewMac::UpdateDisplayVSyncParameters() {
- if (!host() || !display_link_.get())
- return;
-
- if (!display_link_->GetVSyncParameters(&vsync_timebase_, &vsync_interval_)) {
- vsync_timebase_ = base::TimeTicks();
- vsync_interval_ = base::TimeDelta();
- return;
- }
-
- browser_compositor_->UpdateVSyncParameters(vsync_timebase_, vsync_interval_);
-}
-
RenderWidgetHostViewBase*
RenderWidgetHostViewMac::GetFocusedViewForTextSelection() {
// We obtain the TextSelection from focused RWH which is obtained from the
@@ -338,16 +326,11 @@ RenderWidgetHostImpl* RenderWidgetHostViewMac::GetWidgetForIme() {
}
void RenderWidgetHostViewMac::UpdateNSViewAndDisplayProperties() {
- static bool is_frame_rate_limit_disabled =
- base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableFrameRateLimit);
- if (!is_frame_rate_limit_disabled) {
- display_link_ = ui::DisplayLinkMac::GetForDisplay(display_.id());
- if (!display_link_.get()) {
- // Note that on some headless systems, the display link will fail to be
- // created, so this should not be a fatal error.
- LOG(ERROR) << "Failed to create display link.";
- }
+ display_link_ = ui::DisplayLinkMac::GetForDisplay(display_.id());
+ if (!display_link_) {
+ // Note that on some headless systems, the display link will fail to be
+ // created, so this should not be a fatal error.
+ LOG(ERROR) << "Failed to create display link.";
}
if (features::IsViewsBrowserCocoa())
@@ -592,8 +575,8 @@ void RenderWidgetHostViewMac::OnTextSelectionChanged(
ns_view_bridge_->SetTextSelection(selection->text(), selection->offset(),
selection->range());
if (host() && host()->delegate())
- host()->delegate()->DidChangeTextSelection(selection->text(),
- selection->range());
+ host()->delegate()->DidChangeTextSelection(
+ selection->text(), selection->range(), selection->offset());
}
bool RenderWidgetHostViewMac::ShouldWaitInPreCommit() {
@@ -1027,8 +1010,6 @@ void RenderWidgetHostViewMac::SubmitCompositorFrame(
browser_compositor_->GetDelegatedFrameHost()->SubmitCompositorFrame(
local_surface_id, std::move(frame), std::move(hit_test_region_list));
-
- UpdateDisplayVSyncParameters();
}
void RenderWidgetHostViewMac::OnDidNotProduceFrame(
@@ -1040,6 +1021,11 @@ void RenderWidgetHostViewMac::ClearCompositorFrame() {
browser_compositor_->ClearCompositorFrame();
}
+void RenderWidgetHostViewMac::ResetFallbackToFirstNavigationSurface() {
+ browser_compositor_->GetDelegatedFrameHost()
+ ->ResetFallbackToFirstNavigationSurface();
+}
+
bool RenderWidgetHostViewMac::RequestRepaintForTesting() {
return browser_compositor_->RequestRepaintForTesting();
}
@@ -1183,7 +1169,7 @@ void RenderWidgetHostViewMac::SendGesturePinchEvent(WebGestureEvent* event) {
DCHECK(event->SourceDevice() ==
blink::WebGestureDevice::kWebGestureDeviceTouchpad);
host()->delegate()->GetInputEventRouter()->RouteGestureEvent(
- this, event, ui::LatencyInfo(ui::SourceEventType::WHEEL));
+ this, event, ui::LatencyInfo(ui::SourceEventType::TOUCHPAD));
return;
}
host()->ForwardGestureEvent(*event);
@@ -1222,6 +1208,10 @@ bool RenderWidgetHostViewMac::TransformPointToLocalCoordSpaceLegacy(
return true;
}
+bool RenderWidgetHostViewMac::HasFallbackSurface() const {
+ return browser_compositor_->GetDelegatedFrameHost()->HasFallbackSurface();
+}
+
bool RenderWidgetHostViewMac::TransformPointToCoordSpaceForView(
const gfx::PointF& point,
RenderWidgetHostViewBase* target_view,
@@ -1232,9 +1222,10 @@ bool RenderWidgetHostViewMac::TransformPointToCoordSpaceForView(
return true;
}
- return browser_compositor_->GetDelegatedFrameHost()
- ->TransformPointToCoordSpaceForView(point, target_view, transformed_point,
- source);
+ if (!HasFallbackSurface())
+ return false;
+ return target_view->TransformPointToLocalCoordSpace(
+ point, GetCurrentSurfaceId(), transformed_point, source);
}
viz::FrameSinkId RenderWidgetHostViewMac::GetRootFrameSinkId() {
@@ -1488,6 +1479,24 @@ void RenderWidgetHostViewMac::RouteOrProcessMouseEvent(
}
}
+void RenderWidgetHostViewMac::RouteOrProcessTouchEvent(
+ const blink::WebTouchEvent& const_web_event) {
+ blink::WebTouchEvent web_event = const_web_event;
+ ui::FilteredGestureProvider::TouchHandlingResult result =
+ gesture_provider_.OnTouchEvent(MotionEventWeb(web_event));
+ if (!result.succeeded)
+ return;
+
+ ui::LatencyInfo latency_info(ui::SourceEventType::OTHER);
+ latency_info.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_UI_COMPONENT);
+ if (ShouldRouteEvent(web_event)) {
+ host()->delegate()->GetInputEventRouter()->RouteTouchEvent(this, &web_event,
+ latency_info);
+ } else {
+ ProcessTouchEvent(web_event, latency_info);
+ }
+}
+
void RenderWidgetHostViewMac::RouteOrProcessWheelEvent(
const blink::WebMouseWheelEvent& const_web_event) {
blink::WebMouseWheelEvent web_event = const_web_event;
@@ -1850,6 +1859,7 @@ void RenderWidgetHostViewMac::ForwardKeyboardEventWithCommands(
ForwardKeyboardEventWithCommands(native_event, input_event->latency_info,
commands);
}
+
void RenderWidgetHostViewMac::RouteOrProcessMouseEvent(
std::unique_ptr<InputEvent> input_event) {
if (!input_event || !input_event->web_event ||
@@ -1863,6 +1873,19 @@ void RenderWidgetHostViewMac::RouteOrProcessMouseEvent(
RouteOrProcessMouseEvent(mouse_event);
}
+void RenderWidgetHostViewMac::RouteOrProcessTouchEvent(
+ std::unique_ptr<InputEvent> input_event) {
+ if (!input_event || !input_event->web_event ||
+ !blink::WebInputEvent::IsTouchEventType(
+ input_event->web_event->GetType())) {
+ DLOG(ERROR) << "Absent or non-TouchEventType event.";
+ return;
+ }
+ const blink::WebTouchEvent& touch_event =
+ static_cast<const blink::WebTouchEvent&>(*input_event->web_event);
+ RouteOrProcessTouchEvent(touch_event);
+}
+
void RenderWidgetHostViewMac::RouteOrProcessWheelEvent(
std::unique_ptr<InputEvent> input_event) {
if (!input_event || !input_event->web_event ||
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm b/chromium/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
index 4fceb1ab71c..8e31dddeb00 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
@@ -22,6 +22,7 @@
#include "base/test/simple_test_tick_clock.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/viz/common/surfaces/child_local_surface_id_allocator.h"
+#include "content/browser/compositor/image_transport_factory.h"
#include "content/browser/frame_host/render_widget_host_view_guest.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
@@ -51,6 +52,8 @@
#include "ui/base/cocoa/secure_password_input.h"
#import "ui/base/test/cocoa_helper.h"
#import "ui/base/test/scoped_fake_nswindow_focus.h"
+#include "ui/base/ui_base_features.h"
+#include "ui/compositor/recyclable_compositor_mac.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/blink/blink_features.h"
#include "ui/events/blink/web_input_event_traits.h"
@@ -132,20 +135,30 @@ std::string GetMessageNames(
for (auto& event : events)
result.push_back(event->name());
return base::JoinString(result, " ");
- }
+}
+
+blink::WebPointerProperties::PointerType GetPointerType(
+ const MockWidgetInputHandler::MessageVector& events) {
+ EXPECT_EQ(events.size(), 1U);
+ MockWidgetInputHandler::DispatchedEventMessage* event = events[0]->ToEvent();
+ if (!event)
+ return blink::WebPointerProperties::PointerType::kUnknown;
+
+ if (blink::WebInputEvent::IsMouseEventType(
+ event->Event()->web_event->GetType())) {
+ return static_cast<const blink::WebMouseEvent*>(
+ event->Event()->web_event.get())
+ ->pointer_type;
+ }
- blink::WebPointerProperties::PointerType GetPointerType(
- const MockWidgetInputHandler::MessageVector& events) {
- EXPECT_EQ(events.size(), 1U);
- MockWidgetInputHandler::DispatchedEventMessage* event =
- events[0]->ToEvent();
- if (event && blink::WebInputEvent::IsMouseEventType(
- event->Event()->web_event->GetType())) {
- return static_cast<const blink::WebMouseEvent*>(
- event->Event()->web_event.get())
- ->pointer_type;
- }
- return blink::WebPointerProperties::PointerType::kUnknown;
+ if (blink::WebInputEvent::IsTouchEventType(
+ event->Event()->web_event->GetType())) {
+ return static_cast<const blink::WebTouchEvent*>(
+ event->Event()->web_event.get())
+ ->touches[0]
+ .pointer_type;
+ }
+ return blink::WebPointerProperties::PointerType::kUnknown;
}
NSEvent* MockTabletEventWithParams(CGEventType type,
@@ -166,12 +179,20 @@ NSEvent* MockMouseEventWithParams(CGEventType mouse_type,
CGPoint location,
CGMouseButton button,
CGEventMouseSubtype subtype,
- bool is_entering_proximity = false) {
+ bool is_entering_proximity = false,
+ bool is_pen_tip = false) {
CGEventRef cg_event =
CGEventCreateMouseEvent(NULL, mouse_type, location, button);
CGEventSetIntegerValueField(cg_event, kCGMouseEventSubtype, subtype);
CGEventSetIntegerValueField(cg_event, kCGTabletProximityEventEnterProximity,
is_entering_proximity);
+ CGEventSetIntegerValueField(cg_event, kCGTabletEventRotation, 300);
+ if (is_pen_tip)
+ CGEventSetIntegerValueField(cg_event, kCGTabletEventPointButtons, 1);
+ CGEventTimestamp timestamp =
+ (ui::EventTimeForNow() - base::TimeTicks()).InMicroseconds() *
+ base::Time::kNanosecondsPerMicrosecond;
+ CGEventSetTimestamp(cg_event, timestamp);
NSEvent* event = [NSEvent eventWithCGEvent:cg_event];
CFRelease(cg_event);
return event;
@@ -358,7 +379,8 @@ class RenderWidgetHostViewMacTest : public RenderViewHostImplTestHarness {
void SetUp() override {
RenderViewHostImplTestHarness::SetUp();
- gpu::ImageTransportSurface::SetAllowOSMesaForTesting(true);
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(features::kDirectManipulationStylus);
browser_context_ = std::make_unique<TestBrowserContext>();
process_host_ =
@@ -944,6 +966,77 @@ TEST_F(RenderWidgetHostViewMacTest, PointerEventWithMouseType) {
GetPointerType(events));
}
+TEST_F(RenderWidgetHostViewMacTest, PointerEventWithPenTypeSendAsTouch) {
+ // Send a NSEvent of NSTabletProximity type which has a device type of pen.
+ NSEvent* event = MockTabletEventWithParams(kCGEventTabletProximity, true,
+ NSPenPointingDevice);
+ [rwhv_mac_->cocoa_view() tabletEvent:event];
+ // Flush and clear other messages (e.g. begin frames) the RWHVMac also sends.
+ base::RunLoop().RunUntilIdle();
+ static_cast<RenderWidgetHostImpl*>(rwhv_mac_->GetRenderWidgetHost())
+ ->input_router()
+ ->ForceSetTouchActionAuto();
+
+ event = MockMouseEventWithParams(
+ kCGEventLeftMouseDown, {6, 9}, kCGMouseButtonLeft,
+ kCGEventMouseSubtypeTabletPoint, false, true);
+ [rwhv_mac_->cocoa_view() mouseEvent:event];
+ base::RunLoop().RunUntilIdle();
+ MockWidgetInputHandler::MessageVector events =
+ host_->GetAndResetDispatchedMessages();
+ ASSERT_EQ("TouchStart", GetMessageNames(events));
+ EXPECT_EQ(blink::WebPointerProperties::PointerType::kPen,
+ GetPointerType(events));
+ events.clear();
+ base::RunLoop().RunUntilIdle();
+ events = host_->GetAndResetDispatchedMessages();
+
+ event = MockMouseEventWithParams(
+ kCGEventLeftMouseDragged, {16, 29}, kCGMouseButtonLeft,
+ kCGEventMouseSubtypeTabletPoint, false, true);
+ [rwhv_mac_->cocoa_view() mouseEvent:event];
+ base::RunLoop().RunUntilIdle();
+ events = host_->GetAndResetDispatchedMessages();
+ ASSERT_EQ("TouchMove", GetMessageNames(events));
+ EXPECT_EQ(blink::WebPointerProperties::PointerType::kPen,
+ GetPointerType(events));
+
+ events.clear();
+ base::RunLoop().RunUntilIdle();
+ events = host_->GetAndResetDispatchedMessages();
+
+ event = MockMouseEventWithParams(kCGEventLeftMouseUp, {16, 29},
+ kCGMouseButtonLeft,
+ kCGEventMouseSubtypeTabletPoint, false);
+ [rwhv_mac_->cocoa_view() mouseEvent:event];
+ base::RunLoop().RunUntilIdle();
+ events = host_->GetAndResetDispatchedMessages();
+ ASSERT_EQ("TouchEnd GestureScrollEnd", GetMessageNames(events));
+ EXPECT_EQ(blink::WebPointerProperties::PointerType::kPen,
+ static_cast<const blink::WebTouchEvent*>(
+ events[0]->ToEvent()->Event()->web_event.get())
+ ->touches[0]
+ .pointer_type);
+
+ events.clear();
+ base::RunLoop().RunUntilIdle();
+ events = host_->GetAndResetDispatchedMessages();
+
+ event =
+ MockMouseEventWithParams(kCGEventLeftMouseDown, {6, 9},
+ kCGMouseButtonLeft, kCGEventMouseSubtypeDefault);
+ [rwhv_mac_->cocoa_view() mouseEvent:event];
+ base::RunLoop().RunUntilIdle();
+ events = host_->GetAndResetDispatchedMessages();
+ ASSERT_EQ("MouseDown", GetMessageNames(events));
+ EXPECT_EQ(blink::WebPointerProperties::PointerType::kMouse,
+ GetPointerType(events));
+
+ events.clear();
+ base::RunLoop().RunUntilIdle();
+ events = host_->GetAndResetDispatchedMessages();
+}
+
TEST_F(RenderWidgetHostViewMacTest, SendMouseMoveOnShowingContextMenu) {
rwhv_mac_->SetShowingContextMenu(true);
base::RunLoop().RunUntilIdle();
@@ -1308,9 +1401,19 @@ TEST_F(RenderWidgetHostViewMacTest,
host->ShutdownAndDestroyWidget(true);
}
-class RenderWidgetHostViewMacPinchTest : public RenderWidgetHostViewMacTest {
+class RenderWidgetHostViewMacPinchTest
+ : public RenderWidgetHostViewMacTest,
+ public testing::WithParamInterface<bool> {
public:
- RenderWidgetHostViewMacPinchTest() = default;
+ RenderWidgetHostViewMacPinchTest() : async_events_enabled_(GetParam()) {
+ if (async_events_enabled_) {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kTouchpadAsyncPinchEvents);
+ } else {
+ scoped_feature_list_.InitAndDisableFeature(
+ features::kTouchpadAsyncPinchEvents);
+ }
+ }
bool ShouldSendGestureEvents() {
#if defined(MAC_OS_X_VERSION_10_11) && \
@@ -1334,11 +1437,16 @@ class RenderWidgetHostViewMacPinchTest : public RenderWidgetHostViewMacTest {
[rwhv_cocoa_ endGestureWithEvent:pinchEndEvent];
}
+ const bool async_events_enabled_;
+
private:
+ base::test::ScopedFeatureList scoped_feature_list_;
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewMacPinchTest);
};
-TEST_F(RenderWidgetHostViewMacPinchTest, PinchThresholding) {
+INSTANTIATE_TEST_CASE_P(, RenderWidgetHostViewMacPinchTest, testing::Bool());
+
+TEST_P(RenderWidgetHostViewMacPinchTest, PinchThresholding) {
// Do a gesture that crosses the threshold.
{
NSEvent* pinchUpdateEvents[3] = {
@@ -1372,28 +1480,38 @@ TEST_F(RenderWidgetHostViewMacPinchTest, PinchThresholding) {
[rwhv_cocoa_ magnifyWithEvent:pinchUpdateEvents[1]];
base::RunLoop().RunUntilIdle();
events = host_->GetAndResetDispatchedMessages();
- EXPECT_EQ("MouseWheel", GetMessageNames(events));
- // Now acking the synthetic mouse wheel does produce GesturePinch events.
- events[0]->ToEvent()->CallCallback(
- INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
- events = host_->GetAndResetDispatchedMessages();
- EXPECT_EQ("GesturePinchBegin GesturePinchUpdate", GetMessageNames(events));
+ if (async_events_enabled_) {
+ EXPECT_EQ("MouseWheel GesturePinchBegin GesturePinchUpdate",
+ GetMessageNames(events));
+ } else {
+ EXPECT_EQ("MouseWheel", GetMessageNames(events));
+ // Now acking the synthetic mouse wheel does produce GesturePinch events.
+ events[0]->ToEvent()->CallCallback(
+ INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ events = host_->GetAndResetDispatchedMessages();
+ EXPECT_EQ("GesturePinchBegin GesturePinchUpdate",
+ GetMessageNames(events));
+ }
// The third update still has zoom enabled.
[rwhv_cocoa_ magnifyWithEvent:pinchUpdateEvents[2]];
base::RunLoop().RunUntilIdle();
events = host_->GetAndResetDispatchedMessages();
- EXPECT_EQ("MouseWheel", GetMessageNames(events));
- events[0]->ToEvent()->CallCallback(
- INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
- events = host_->GetAndResetDispatchedMessages();
- EXPECT_EQ("GesturePinchUpdate", GetMessageNames(events));
+ if (async_events_enabled_) {
+ EXPECT_EQ("MouseWheel GesturePinchUpdate", GetMessageNames(events));
+ } else {
+ EXPECT_EQ("MouseWheel", GetMessageNames(events));
+ events[0]->ToEvent()->CallCallback(
+ INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ events = host_->GetAndResetDispatchedMessages();
+ EXPECT_EQ("GesturePinchUpdate", GetMessageNames(events));
+ }
SendEndPinchEvent();
base::RunLoop().RunUntilIdle();
events = host_->GetAndResetDispatchedMessages();
- EXPECT_EQ("GesturePinchEnd", GetMessageNames(events));
+ EXPECT_EQ("MouseWheel GesturePinchEnd", GetMessageNames(events));
}
// Do a gesture that doesn't cross the threshold, but happens when we're not
@@ -1422,7 +1540,7 @@ TEST_F(RenderWidgetHostViewMacPinchTest, PinchThresholding) {
SendEndPinchEvent();
base::RunLoop().RunUntilIdle();
events = host_->GetAndResetDispatchedMessages();
- EXPECT_EQ("GesturePinchEnd", GetMessageNames(events));
+ EXPECT_EQ("MouseWheel GesturePinchEnd", GetMessageNames(events));
}
// Do a gesture again, after the page scale is no longer at one, and ensure
@@ -1458,7 +1576,7 @@ TEST_F(RenderWidgetHostViewMacPinchTest, PinchThresholding) {
SendEndPinchEvent();
base::RunLoop().RunUntilIdle();
events = host_->GetAndResetDispatchedMessages();
- EXPECT_EQ(0U, events.size());
+ EXPECT_EQ("MouseWheel", GetMessageNames(events));
}
}
@@ -1837,11 +1955,11 @@ TEST_F(InputMethodMacTest, MonitorCompositionRangeForActiveWidget) {
TEST_F(RenderWidgetHostViewMacTest, ClearCompositorFrame) {
BrowserCompositorMac* browser_compositor = rwhv_mac_->BrowserCompositor();
- ui::Compositor* ui_compositor = browser_compositor->GetCompositorForTesting();
+ ui::Compositor* ui_compositor = browser_compositor->GetCompositor();
EXPECT_NE(ui_compositor, nullptr);
EXPECT_TRUE(ui_compositor->IsLocked());
rwhv_mac_->ClearCompositorFrame();
- EXPECT_EQ(browser_compositor->GetCompositorForTesting(), ui_compositor);
+ EXPECT_EQ(browser_compositor->GetCompositor(), ui_compositor);
EXPECT_FALSE(ui_compositor->IsLocked());
}
@@ -1904,4 +2022,30 @@ TEST_F(RenderWidgetHostViewMacTest, ConflictingAllocationsResolve) {
EXPECT_EQ(local_surface_id4, merged_local_surface_id);
}
+TEST_F(RenderWidgetHostViewMacTest, TransformToRootNoParentLayer) {
+ gfx::PointF point(10, 20);
+ rwhv_mac_->TransformPointToRootSurface(&point);
+ EXPECT_EQ(point, gfx::PointF(10, 20));
+}
+
+TEST_F(RenderWidgetHostViewMacTest, TransformToRootWithParentLayer) {
+ std::unique_ptr<ui::RecyclableCompositorMac> compositor =
+ ui::RecyclableCompositorMacFactory::Get()->CreateCompositor(
+ ImageTransportFactory::GetInstance()->GetContextFactory(),
+ ImageTransportFactory::GetInstance()->GetContextFactoryPrivate());
+ std::unique_ptr<ui::Layer> root_surface_layer =
+ std::make_unique<ui::Layer>(ui::LAYER_SOLID_COLOR);
+ std::unique_ptr<ui::Layer> parent_layer =
+ std::make_unique<ui::Layer>(ui::LAYER_SOLID_COLOR);
+
+ compositor->compositor()->SetRootLayer(root_surface_layer.get());
+ root_surface_layer->SetBounds(gfx::Rect(-5, -10, 1000, 2000));
+ parent_layer->SetBounds(gfx::Rect(100, 300, 500, 400));
+ root_surface_layer->Add(parent_layer.get());
+ gfx::PointF point(10, 20);
+ rwhv_mac_->SetParentUiLayer(parent_layer.get());
+ rwhv_mac_->TransformPointToRootSurface(&point);
+ EXPECT_EQ(point, gfx::PointF(105, 310));
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/render_widget_targeter.cc b/chromium/content/browser/renderer_host/render_widget_targeter.cc
index 4a5acc5f53b..eef715fc681 100644
--- a/chromium/content/browser/renderer_host/render_widget_targeter.cc
+++ b/chromium/content/browser/renderer_host/render_widget_targeter.cc
@@ -153,10 +153,7 @@ void RenderWidgetTargeter::FindTargetAndDispatch(
RenderWidgetHostViewBase* target = result.view;
auto* event_ptr = &event;
async_depth_ = 0;
- // TODO(kenrb, wjmaclean): Asynchronous hit tests don't work properly with
- // GuestViews, so rely on the synchronous result.
- // See https://crbug.com/802378.
- if (result.should_query_view && !target->IsRenderWidgetHostViewGuest()) {
+ if (result.should_query_view) {
// TODO(kenrb, sadrul): When all event types support asynchronous hit
// testing, we should be able to have FindTargetSynchronously return the
// view and location to use for the renderer hit test query.
@@ -215,6 +212,7 @@ void RenderWidgetTargeter::QueryClient(
}
void RenderWidgetTargeter::FlushEventQueue() {
+ bool events_being_flushed = false;
while (!request_in_flight_ && !requests_.empty()) {
auto request = std::move(requests_.front());
requests_.pop();
@@ -224,9 +222,16 @@ void RenderWidgetTargeter::FlushEventQueue() {
continue;
}
request.tracker->Stop();
+ // Only notify the delegate once that the current event queue is being
+ // flushed. Once all the events are flushed, notify the delegate again.
+ if (!events_being_flushed) {
+ delegate_->SetEventsBeingFlushed(true);
+ events_being_flushed = true;
+ }
FindTargetAndDispatch(request.root_view.get(), *request.event,
request.latency);
}
+ delegate_->SetEventsBeingFlushed(false);
}
void RenderWidgetTargeter::FoundFrameSinkId(
@@ -237,7 +242,8 @@ void RenderWidgetTargeter::FoundFrameSinkId(
uint32_t request_id,
const gfx::PointF& target_location,
TracingUmaTracker tracker,
- const viz::FrameSinkId& frame_sink_id) {
+ const viz::FrameSinkId& frame_sink_id,
+ const gfx::PointF& transformed_location) {
tracker.Stop();
if (request_id != last_request_id_ || !request_in_flight_) {
// This is a response to a request that already timed out, so the event
@@ -259,10 +265,8 @@ void RenderWidgetTargeter::FoundFrameSinkId(
unresponsive_views_.find(view) != unresponsive_views_.end()) {
FoundTarget(root_view.get(), view, *event, latency, target_location, false);
} else {
- gfx::PointF location = target_location;
- target->TransformPointToCoordSpaceForView(location, view, &location);
- QueryClient(root_view.get(), view, *event, latency, location, target.get(),
- target_location);
+ QueryClient(root_view.get(), view, *event, latency, transformed_location,
+ target.get(), target_location);
}
}
diff --git a/chromium/content/browser/renderer_host/render_widget_targeter.h b/chromium/content/browser/renderer_host/render_widget_targeter.h
index e9b3e2addf4..5e6dda1dbc3 100644
--- a/chromium/content/browser/renderer_host/render_widget_targeter.h
+++ b/chromium/content/browser/renderer_host/render_widget_targeter.h
@@ -70,6 +70,8 @@ class RenderWidgetTargeter {
const ui::LatencyInfo& latency,
const base::Optional<gfx::PointF>& target_location) = 0;
+ virtual void SetEventsBeingFlushed(bool events_being_flushed) = 0;
+
virtual RenderWidgetHostViewBase* FindViewFromFrameSinkId(
const viz::FrameSinkId& frame_sink_id) const = 0;
};
@@ -115,6 +117,11 @@ class RenderWidgetTargeter {
// |event| is in the coordinate space of |root_view|. |target_location|, if
// set, is the location in |target|'s coordinate space.
+ // |target| is the current target that will be queried using its
+ // InputTargetClient interface.
+ // |frame_sink_id| is returned from the InputTargetClient to indicate where
+ // the event should be routed, and |transformed_location| is the point in
+ // that new target's coordinate space.
void FoundFrameSinkId(base::WeakPtr<RenderWidgetHostViewBase> root_view,
base::WeakPtr<RenderWidgetHostViewBase> target,
ui::WebScopedInputEvent event,
@@ -122,7 +129,8 @@ class RenderWidgetTargeter {
uint32_t request_id,
const gfx::PointF& target_location,
TracingUmaTracker tracker,
- const viz::FrameSinkId& frame_sink_id);
+ const viz::FrameSinkId& frame_sink_id,
+ const gfx::PointF& transformed_location);
// |event| is in the coordinate space of |root_view|. |target_location|, if
// set, is the location in |target|'s coordinate space. If |latched_target| is
diff --git a/chromium/content/browser/renderer_host/text_input_manager.cc b/chromium/content/browser/renderer_host/text_input_manager.cc
index 24f32e7228a..ce3a5ff83cf 100644
--- a/chromium/content/browser/renderer_host/text_input_manager.cc
+++ b/chromium/content/browser/renderer_host/text_input_manager.cc
@@ -209,6 +209,11 @@ void TextInputManager::SelectionBoundsChanged(
selection_region_map_[view].first_selection_rect.set_size(
params.anchor_rect.size());
+ NotifySelectionBoundsChanged(view);
+}
+
+void TextInputManager::NotifySelectionBoundsChanged(
+ RenderWidgetHostViewBase* view) {
for (auto& observer : observer_list_)
observer.OnSelectionBoundsChanged(this, view);
}
diff --git a/chromium/content/browser/renderer_host/text_input_manager.h b/chromium/content/browser/renderer_host/text_input_manager.h
index 8e4ecfe5be2..b715544c7a2 100644
--- a/chromium/content/browser/renderer_host/text_input_manager.h
+++ b/chromium/content/browser/renderer_host/text_input_manager.h
@@ -184,6 +184,10 @@ class CONTENT_EXPORT TextInputManager {
void SelectionBoundsChanged(RenderWidgetHostViewBase* view,
const ViewHostMsg_SelectionBounds_Params& params);
+ // Notify observers that the selection bounds have been updated. This is also
+ // called when a view with a selection is reactivated.
+ void NotifySelectionBoundsChanged(RenderWidgetHostViewBase* view);
+
// Called when the composition range and/or character bounds have changed.
void ImeCompositionRangeChanged(
RenderWidgetHostViewBase* view,
@@ -255,7 +259,7 @@ class CONTENT_EXPORT TextInputManager {
// user.
bool should_do_learning_;
- base::ObserverList<Observer> observer_list_;
+ base::ObserverList<Observer>::Unchecked observer_list_;
DISALLOW_COPY_AND_ASSIGN(TextInputManager);
};
diff --git a/chromium/content/browser/renderer_host/ui_events_helper.cc b/chromium/content/browser/renderer_host/ui_events_helper.cc
index 6ea4ed53dbe..8b3330f22c9 100644
--- a/chromium/content/browser/renderer_host/ui_events_helper.cc
+++ b/chromium/content/browser/renderer_host/ui_events_helper.cc
@@ -65,8 +65,7 @@ bool MakeUITouchEventsFromWebTouchEvents(
int flags = ui::WebEventModifiersToEventFlags(touch.GetModifiers());
base::TimeTicks timestamp = touch.TimeStamp();
- unsigned count = 0;
- for (unsigned i = 0; i < blink::WebTouchEvent::kTouchesLengthCap; ++i) {
+ for (unsigned i = 0; i < touch.touches_length; ++i) {
const blink::WebTouchPoint& point = touch.touches[i];
if (WebTouchPointStateToEventType(point.state) != type)
continue;
@@ -85,8 +84,6 @@ bool MakeUITouchEventsFromWebTouchEvents(
uievent->set_root_location_f(location);
uievent->set_latency(touch_with_latency.latency);
list->push_back(std::move(uievent));
- if (++count >= touch.touches_length)
- break;
}
return true;
}
diff --git a/chromium/content/browser/renderer_host/web_database_host_impl.cc b/chromium/content/browser/renderer_host/web_database_host_impl.cc
index 99612d10417..da7a48e8903 100644
--- a/chromium/content/browser/renderer_host/web_database_host_impl.cc
+++ b/chromium/content/browser/renderer_host/web_database_host_impl.cc
@@ -9,6 +9,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/strings/utf_string_conversions.h"
+#include "content/browser/child_process_security_policy_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/origin_util.h"
@@ -33,15 +34,6 @@ namespace {
const int kNumDeleteRetries = 2;
// The delay between each retry to delete the SQLite database.
const int kDelayDeleteRetryMs = 100;
-
-bool ValidateOrigin(const url::Origin& origin) {
- if (origin.unique()) {
- mojo::ReportBadMessage("Invalid Origin.");
- return false;
- }
- return true;
-}
-
} // namespace
WebDatabaseHostImpl::WebDatabaseHostImpl(
@@ -80,6 +72,9 @@ void WebDatabaseHostImpl::OpenFile(const base::string16& vfs_file_name,
int32_t desired_flags,
OpenFileCallback callback) {
DCHECK(db_tracker_->task_runner()->RunsTasksInCurrentSequence());
+ if (!ValidateOrigin(vfs_file_name))
+ return;
+
base::File file;
const base::File* tracked_file = nullptr;
std::string origin_identifier;
@@ -130,6 +125,9 @@ void WebDatabaseHostImpl::DeleteFile(const base::string16& vfs_file_name,
bool sync_dir,
DeleteFileCallback callback) {
DCHECK(db_tracker_->task_runner()->RunsTasksInCurrentSequence());
+ if (!ValidateOrigin(vfs_file_name))
+ return;
+
DatabaseDeleteFile(vfs_file_name, sync_dir, std::move(callback),
kNumDeleteRetries);
}
@@ -138,6 +136,9 @@ void WebDatabaseHostImpl::GetFileAttributes(
const base::string16& vfs_file_name,
GetFileAttributesCallback callback) {
DCHECK(db_tracker_->task_runner()->RunsTasksInCurrentSequence());
+ if (!ValidateOrigin(vfs_file_name))
+ return;
+
int32_t attributes = -1;
base::FilePath db_file =
DatabaseUtil::GetFullFilePathForVfsFile(db_tracker_.get(), vfs_file_name);
@@ -150,6 +151,9 @@ void WebDatabaseHostImpl::GetFileAttributes(
void WebDatabaseHostImpl::GetFileSize(const base::string16& vfs_file_name,
GetFileSizeCallback callback) {
DCHECK(db_tracker_->task_runner()->RunsTasksInCurrentSequence());
+ if (!ValidateOrigin(vfs_file_name))
+ return;
+
int64_t size = 0LL;
base::FilePath db_file =
DatabaseUtil::GetFullFilePathForVfsFile(db_tracker_.get(), vfs_file_name);
@@ -163,6 +167,9 @@ void WebDatabaseHostImpl::SetFileSize(const base::string16& vfs_file_name,
int64_t expected_size,
SetFileSizeCallback callback) {
DCHECK(db_tracker_->task_runner()->RunsTasksInCurrentSequence());
+ if (!ValidateOrigin(vfs_file_name))
+ return;
+
bool success = false;
base::FilePath db_file =
DatabaseUtil::GetFullFilePathForVfsFile(db_tracker_.get(), vfs_file_name);
@@ -177,13 +184,12 @@ void WebDatabaseHostImpl::GetSpaceAvailable(
GetSpaceAvailableCallback callback) {
// QuotaManager is only available on the IO thread.
DCHECK(db_tracker_->task_runner()->RunsTasksInCurrentSequence());
- DCHECK(db_tracker_->quota_manager_proxy());
if (!ValidateOrigin(origin)) {
- std::move(callback).Run(0);
return;
}
+ DCHECK(db_tracker_->quota_manager_proxy());
db_tracker_->quota_manager_proxy()->GetUsageAndQuota(
db_tracker_->task_runner(), origin, blink::mojom::StorageType::kTemporary,
base::BindOnce(
@@ -367,4 +373,37 @@ blink::mojom::WebDatabase& WebDatabaseHostImpl::GetWebDatabase() {
return *database_provider_;
}
+bool WebDatabaseHostImpl::ValidateOrigin(const url::Origin& origin) {
+ if (origin.unique()) {
+ mojo::ReportBadMessage("Invalid origin.");
+ return false;
+ }
+
+ if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanAccessDataForOrigin(
+ process_id_, origin.GetURL())) {
+ mojo::ReportBadMessage("Unauthorized origin.");
+ return false;
+ }
+ return true;
+}
+
+bool WebDatabaseHostImpl::ValidateOrigin(const base::string16& vfs_file_name) {
+ std::string origin_identifier;
+ if (vfs_file_name.empty())
+ return true;
+
+ if (!DatabaseUtil::CrackVfsFileName(vfs_file_name, &origin_identifier,
+ nullptr, nullptr)) {
+ return true;
+ }
+
+ if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanAccessDataForOrigin(
+ process_id_,
+ storage::GetOriginURLFromIdentifier(origin_identifier))) {
+ mojo::ReportBadMessage("Unauthorized origin.");
+ return false;
+ }
+ return true;
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/web_database_host_impl.h b/chromium/content/browser/renderer_host/web_database_host_impl.h
index 21bf6dc9b23..c57d2fcbf80 100644
--- a/chromium/content/browser/renderer_host/web_database_host_impl.h
+++ b/chromium/content/browser/renderer_host/web_database_host_impl.h
@@ -8,6 +8,7 @@
#include <string>
#include "base/strings/string16.h"
+#include "build/build_config.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "storage/browser/database/database_tracker.h"
#include "third_party/blink/public/platform/modules/webdatabase/web_database.mojom.h"
@@ -18,10 +19,11 @@ class Origin;
namespace content {
-class WebDatabaseHostImpl : public blink::mojom::WebDatabaseHost,
- public storage::DatabaseTracker::Observer {
+class CONTENT_EXPORT WebDatabaseHostImpl
+ : public blink::mojom::WebDatabaseHost,
+ public storage::DatabaseTracker::Observer {
public:
- WebDatabaseHostImpl(int proess_id,
+ WebDatabaseHostImpl(int process_id,
scoped_refptr<storage::DatabaseTracker> db_tracker);
~WebDatabaseHostImpl() override;
@@ -30,6 +32,9 @@ class WebDatabaseHostImpl : public blink::mojom::WebDatabaseHost,
blink::mojom::WebDatabaseHostRequest request);
private:
+ FRIEND_TEST_ALL_PREFIXES(WebDatabaseHostImplTest, BadMessagesUnauthorized);
+ FRIEND_TEST_ALL_PREFIXES(WebDatabaseHostImplTest, BadMessagesInvalid);
+
// blink::mojom::WebDatabaseHost:
void OpenFile(const base::string16& vfs_file_name,
int32_t desired_flags,
@@ -85,6 +90,17 @@ class WebDatabaseHostImpl : public blink::mojom::WebDatabaseHost,
// exist.
blink::mojom::WebDatabase& GetWebDatabase();
+ // Check that an IPC call has permission to access the passed origin. Must
+ // be called from within the context of a mojo call. Invalid calls will
+ // report a bad message, which will terminate the calling process. If this
+ // returns false, the caller should return immediately without invoking
+ // callbacks.
+ bool ValidateOrigin(const url::Origin& origin);
+
+ // As above, but for calls where the origin is embedded in a VFS filename.
+ // Empty filenames signalling a temp file are permitted.
+ bool ValidateOrigin(const base::string16& vfs_file_name);
+
// Our render process host ID, used to bind to the correct render process.
const int process_id_;
diff --git a/chromium/content/browser/renderer_host/web_database_host_impl_unittest.cc b/chromium/content/browser/renderer_host/web_database_host_impl_unittest.cc
new file mode 100644
index 00000000000..c46954787e2
--- /dev/null
+++ b/chromium/content/browser/renderer_host/web_database_host_impl_unittest.cc
@@ -0,0 +1,178 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/renderer_host/web_database_host_impl.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/child_process_security_policy_impl.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "mojo/core/embedder/embedder.h"
+#include "storage/common/database/database_identifier.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+base::string16 ConstructVfsFileName(const url::Origin& origin,
+ const base::string16& name,
+ const base::string16& suffix) {
+ std::string identifier = storage::GetIdentifierFromOrigin(origin);
+ return base::UTF8ToUTF16(identifier) + base::ASCIIToUTF16("/") + name +
+ base::ASCIIToUTF16("#") + suffix;
+}
+
+class BadMessageObserver {
+ public:
+ BadMessageObserver()
+ : dummy_message_(0, 0, 0, 0, nullptr), context_(&dummy_message_) {
+ mojo::core::SetDefaultProcessErrorCallback(base::BindRepeating(
+ &BadMessageObserver::ReportBadMessage, base::Unretained(this)));
+ }
+
+ ~BadMessageObserver() {
+ mojo::core::SetDefaultProcessErrorCallback(
+ mojo::core::ProcessErrorCallback());
+ }
+
+ const std::string& last_error() const { return last_error_; }
+
+ private:
+ void ReportBadMessage(const std::string& error) { last_error_ = error; }
+
+ mojo::Message dummy_message_;
+ mojo::internal::MessageDispatchContext context_;
+ std::string last_error_;
+
+ DISALLOW_COPY_AND_ASSIGN(BadMessageObserver);
+};
+} // namespace
+
+class WebDatabaseHostImplTest : public ::testing::Test {
+ protected:
+ WebDatabaseHostImplTest() = default;
+ ~WebDatabaseHostImplTest() override = default;
+
+ void SetUp() override {
+ scoped_refptr<storage::DatabaseTracker> db_tracker =
+ base::MakeRefCounted<storage::DatabaseTracker>(
+ base::FilePath(), /*is_incognito=*/false,
+ /*special_storage_policy=*/nullptr,
+ /*quota_manager_proxy=*/nullptr);
+ db_tracker->set_task_runner_for_testing(
+ base::ThreadTaskRunnerHandle::Get());
+
+ host_ = std::make_unique<WebDatabaseHostImpl>(process_id(),
+ std::move(db_tracker));
+ }
+
+ template <typename Callable>
+ void CheckUnauthorizedOrigin(const Callable& func) {
+ BadMessageObserver bad_message_observer;
+ func();
+ EXPECT_EQ("Unauthorized origin.", bad_message_observer.last_error());
+ }
+
+ template <typename Callable>
+ void CheckInvalidOrigin(const Callable& func) {
+ BadMessageObserver bad_message_observer;
+ func();
+ EXPECT_EQ("Invalid origin.", bad_message_observer.last_error());
+ }
+
+ WebDatabaseHostImpl* host() { return host_.get(); }
+ int process_id() { return kProcessId; }
+
+ private:
+ static constexpr int kProcessId = 1234;
+ TestBrowserThreadBundle thread_bundle_;
+ std::unique_ptr<WebDatabaseHostImpl> host_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebDatabaseHostImplTest);
+};
+
+TEST_F(WebDatabaseHostImplTest, BadMessagesUnauthorized) {
+ const url::Origin correct_origin =
+ url::Origin::Create(GURL("http://correct.com"));
+ const url::Origin incorrect_origin =
+ url::Origin::Create(GURL("http://incorrect.net"));
+ const base::string16 db_name(base::ASCIIToUTF16("db_name"));
+ const base::string16 suffix(base::ASCIIToUTF16("suffix"));
+ const base::string16 bad_vfs_file_name =
+ ConstructVfsFileName(incorrect_origin, db_name, suffix);
+
+ auto* security_policy = ChildProcessSecurityPolicyImpl::GetInstance();
+ security_policy->Add(process_id());
+ security_policy->AddIsolatedOrigins({correct_origin, incorrect_origin});
+ security_policy->LockToOrigin(process_id(), correct_origin.GetURL());
+ ASSERT_TRUE(security_policy->CanAccessDataForOrigin(process_id(),
+ correct_origin.GetURL()));
+ ASSERT_FALSE(security_policy->CanAccessDataForOrigin(
+ process_id(), incorrect_origin.GetURL()));
+
+ CheckUnauthorizedOrigin([&]() {
+ host()->OpenFile(bad_vfs_file_name,
+ /*desired_flags=*/0, base::BindOnce([](base::File) {}));
+ });
+
+ CheckUnauthorizedOrigin([&]() {
+ host()->DeleteFile(bad_vfs_file_name,
+ /*sync_dir=*/false, base::BindOnce([](int32_t) {}));
+ });
+
+ CheckUnauthorizedOrigin([&]() {
+ host()->GetFileAttributes(bad_vfs_file_name,
+ base::BindOnce([](int32_t) {}));
+ });
+
+ CheckUnauthorizedOrigin([&]() {
+ host()->GetFileSize(bad_vfs_file_name, base::BindOnce([](int64_t) {}));
+ });
+
+ CheckUnauthorizedOrigin([&]() {
+ host()->SetFileSize(bad_vfs_file_name, /*expected_size=*/0,
+ base::BindOnce([](bool) {}));
+ });
+
+ CheckUnauthorizedOrigin([&]() {
+ host()->GetSpaceAvailable(incorrect_origin, base::BindOnce([](int64_t) {}));
+ });
+
+ CheckUnauthorizedOrigin([&]() {
+ host()->Opened(incorrect_origin, db_name, base::ASCIIToUTF16("description"),
+ /*estimated_size=*/0);
+ });
+
+ CheckUnauthorizedOrigin(
+ [&]() { host()->Modified(incorrect_origin, db_name); });
+
+ CheckUnauthorizedOrigin([&]() { host()->Closed(incorrect_origin, db_name); });
+
+ CheckUnauthorizedOrigin([&]() {
+ host()->HandleSqliteError(incorrect_origin, db_name, /*error=*/0);
+ });
+}
+
+TEST_F(WebDatabaseHostImplTest, BadMessagesInvalid) {
+ const url::Origin opaque_origin;
+ const base::string16 db_name(base::ASCIIToUTF16("db_name"));
+
+ CheckInvalidOrigin([&]() {
+ host()->GetSpaceAvailable(opaque_origin, base::BindOnce([](int64_t) {}));
+ });
+
+ CheckInvalidOrigin([&]() {
+ host()->Opened(opaque_origin, db_name, base::ASCIIToUTF16("description"),
+ /*estimated_size=*/0);
+ });
+
+ CheckInvalidOrigin([&]() { host()->Modified(opaque_origin, db_name); });
+
+ CheckInvalidOrigin([&]() { host()->Closed(opaque_origin, db_name); });
+
+ CheckInvalidOrigin([&]() {
+ host()->HandleSqliteError(opaque_origin, db_name, /*error=*/0);
+ });
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_interface_binders.cc b/chromium/content/browser/renderer_interface_binders.cc
index 896f1b27ded..c3a8bdc572d 100644
--- a/chromium/content/browser/renderer_interface_binders.cc
+++ b/chromium/content/browser/renderer_interface_binders.cc
@@ -171,7 +171,7 @@ void RendererInterfaceBinders::InitializeParameterizedBinderRegistry() {
->CreateService(origin, std::move(request));
}));
parameterized_binder_registry_.AddInterface(
- base::BindRepeating(&BackgroundFetchServiceImpl::Create));
+ base::BindRepeating(&BackgroundFetchServiceImpl::CreateForWorker));
parameterized_binder_registry_.AddInterface(
base::BindRepeating(GetRestrictedCookieManager));
parameterized_binder_registry_.AddInterface(
diff --git a/chromium/content/browser/resolve_proxy_msg_helper.cc b/chromium/content/browser/resolve_proxy_msg_helper.cc
index 08885d871bb..41a3408c313 100644
--- a/chromium/content/browser/resolve_proxy_msg_helper.cc
+++ b/chromium/content/browser/resolve_proxy_msg_helper.cc
@@ -5,25 +5,28 @@
#include "content/browser/resolve_proxy_msg_helper.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/compiler_specific.h"
#include "content/common/view_messages.h"
-#include "net/base/net_errors.h"
-#include "net/log/net_log_with_source.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/storage_partition.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "net/proxy_resolution/proxy_info.h"
+#include "services/network/public/mojom/network_context.mojom.h"
namespace content {
-ResolveProxyMsgHelper::ResolveProxyMsgHelper(
- net::URLRequestContextGetter* getter)
+ResolveProxyMsgHelper::ResolveProxyMsgHelper(int render_process_host_id)
: BrowserMessageFilter(ViewMsgStart),
- context_getter_(getter),
- proxy_resolution_service_(nullptr) {}
-
-ResolveProxyMsgHelper::ResolveProxyMsgHelper(
- net::ProxyResolutionService* proxy_resolution_service)
- : BrowserMessageFilter(ViewMsgStart), proxy_resolution_service_(proxy_resolution_service) {}
+ render_process_host_id_(render_process_host_id),
+ binding_(this) {}
+
+void ResolveProxyMsgHelper::OverrideThreadForMessage(
+ const IPC::Message& message,
+ BrowserThread::ID* thread) {
+ if (message.type() == ViewHostMsg_ResolveProxy::ID)
+ *thread = BrowserThread::UI;
+}
bool ResolveProxyMsgHelper::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
@@ -36,68 +39,97 @@ bool ResolveProxyMsgHelper::OnMessageReceived(const IPC::Message& message) {
void ResolveProxyMsgHelper::OnResolveProxy(const GURL& url,
IPC::Message* reply_msg) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
// Enqueue the pending request.
pending_requests_.push_back(PendingRequest(url, reply_msg));
// If nothing is in progress, start.
- if (pending_requests_.size() == 1)
+ if (!binding_.is_bound()) {
+ DCHECK_EQ(1u, pending_requests_.size());
StartPendingRequest();
+ }
}
ResolveProxyMsgHelper::~ResolveProxyMsgHelper() {
- // Clear all pending requests if the ProxyResolutionService is still alive (if
- // we have a default request context or override).
- if (!pending_requests_.empty()) {
- PendingRequest req = pending_requests_.front();
- proxy_resolution_service_->CancelRequest(req.request);
- }
+ DCHECK(!owned_self_);
+ DCHECK(!binding_.is_bound());
+}
+
+void ResolveProxyMsgHelper::StartPendingRequest() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(!binding_.is_bound());
+ DCHECK(!pending_requests_.empty());
- for (PendingRequestList::iterator it = pending_requests_.begin();
- it != pending_requests_.end();
- ++it) {
- delete it->reply_msg;
+ // Start the request.
+ network::mojom::ProxyLookupClientPtr proxy_lookup_client;
+ binding_.Bind(mojo::MakeRequest(&proxy_lookup_client));
+ binding_.set_connection_error_handler(
+ base::BindOnce(&ResolveProxyMsgHelper::OnProxyLookupComplete,
+ base::Unretained(this), base::nullopt));
+ owned_self_ = this;
+ if (!SendRequestToNetworkService(pending_requests_.front().url,
+ std::move(proxy_lookup_client))) {
+ OnProxyLookupComplete(base::nullopt);
}
+}
- pending_requests_.clear();
+bool ResolveProxyMsgHelper::SendRequestToNetworkService(
+ const GURL& url,
+ network::mojom::ProxyLookupClientPtr proxy_lookup_client) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ RenderProcessHost* render_process_host =
+ RenderProcessHost::FromID(render_process_host_id_);
+ // Fail the request if there's no such RenderProcessHost;
+ if (!render_process_host)
+ return false;
+ render_process_host->GetStoragePartition()
+ ->GetNetworkContext()
+ ->LookUpProxyForURL(url, std::move(proxy_lookup_client));
+ return true;
}
-void ResolveProxyMsgHelper::OnResolveProxyCompleted(int result) {
- CHECK(!pending_requests_.empty());
+void ResolveProxyMsgHelper::OnProxyLookupComplete(
+ const base::Optional<net::ProxyInfo>& proxy_info) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(!pending_requests_.empty());
- const PendingRequest& completed_req = pending_requests_.front();
- ViewHostMsg_ResolveProxy::WriteReplyParams(
- completed_req.reply_msg, result == net::OK, proxy_info_.ToPacString());
- Send(completed_req.reply_msg);
+ binding_.Close();
+
+ // If all references except |owned_self_| have been released, just release
+ // the last reference, without doing anything.
+ if (HasOneRef()) {
+ scoped_refptr<ResolveProxyMsgHelper> self = std::move(owned_self_);
+ return;
+ }
+
+ owned_self_ = nullptr;
// Clear the current (completed) request.
+ PendingRequest completed_req = std::move(pending_requests_.front());
pending_requests_.pop_front();
+ ViewHostMsg_ResolveProxy::WriteReplyParams(
+ completed_req.reply_msg.get(), !!proxy_info,
+ proxy_info ? proxy_info->ToPacString() : std::string());
+ Send(completed_req.reply_msg.release());
+
// Start the next request.
if (!pending_requests_.empty())
StartPendingRequest();
}
-void ResolveProxyMsgHelper::StartPendingRequest() {
- PendingRequest& req = pending_requests_.front();
+ResolveProxyMsgHelper::PendingRequest::PendingRequest(const GURL& url,
+ IPC::Message* reply_msg)
+ : url(url), reply_msg(reply_msg) {}
- // Verify the request wasn't started yet.
- DCHECK(nullptr == req.request);
+ResolveProxyMsgHelper::PendingRequest::PendingRequest(
+ PendingRequest&& pending_request) noexcept = default;
- if (context_getter_.get()) {
- proxy_resolution_service_ = context_getter_->GetURLRequestContext()->proxy_resolution_service();
- context_getter_ = nullptr;
- }
+ResolveProxyMsgHelper::PendingRequest::~PendingRequest() noexcept = default;
- // Start the request.
- int result = proxy_resolution_service_->ResolveProxy(
- req.url, std::string(), &proxy_info_,
- base::Bind(&ResolveProxyMsgHelper::OnResolveProxyCompleted,
- base::Unretained(this)),
- &req.request, nullptr, net::NetLogWithSource());
-
- // Completed synchronously.
- if (result != net::ERR_IO_PENDING)
- OnResolveProxyCompleted(result);
-}
+ResolveProxyMsgHelper::PendingRequest& ResolveProxyMsgHelper::PendingRequest::
+operator=(PendingRequest&& pending_request) noexcept = default;
} // namespace content
diff --git a/chromium/content/browser/resolve_proxy_msg_helper.h b/chromium/content/browser/resolve_proxy_msg_helper.h
index 8eacab90e7d..8034af85184 100644
--- a/chromium/content/browser/resolve_proxy_msg_helper.h
+++ b/chromium/content/browser/resolve_proxy_msg_helper.h
@@ -8,21 +8,24 @@
#include <string>
#include "base/containers/circular_deque.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/optional.h"
+#include "base/sequenced_task_runner_helpers.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_message_filter.h"
-#include "net/base/completion_callback.h"
-#include "net/proxy_resolution/proxy_resolution_service.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/network/public/mojom/proxy_lookup_client.mojom.h"
#include "url/gurl.h"
namespace net {
-class URLRequestContextGetter;
+class ProxyInfo;
}
namespace content {
-// Responds to ChildProcessHostMsg_ResolveProxy, kicking off a ProxyResolve
-// request on the IO thread using the specified proxy service. Completion is
+// Responds to ChildProcessHostMsg_ResolveProxy, kicking off a proxy lookup
+// request on the UI thread using the specified proxy service. Completion is
// notified through the delegate. If multiple requests are started at the same
// time, they will run in FIFO order, with only 1 being outstanding at a time.
//
@@ -30,15 +33,18 @@ namespace content {
// outstanding proxy resolve requests with the proxy service. It also deletes
// the stored IPC::Message pointers for pending requests.
//
-// This object is expected to live on the IO thread.
-class CONTENT_EXPORT ResolveProxyMsgHelper : public BrowserMessageFilter {
+// This object does most of its work on the UI thread. It holds onto a
+// self-reference as long as there's a pending Mojo call, as losing its last
+// reference on the IO thread with an open mojo pipe that lives on the UI
+// thread leads to problems.
+class CONTENT_EXPORT ResolveProxyMsgHelper : public BrowserMessageFilter,
+ network::mojom::ProxyLookupClient {
public:
- explicit ResolveProxyMsgHelper(net::URLRequestContextGetter* getter);
- // Constructor used by unittests.
- explicit ResolveProxyMsgHelper(
- net::ProxyResolutionService* proxy_resolution_service);
+ explicit ResolveProxyMsgHelper(int render_process_host_id);
// BrowserMessageFilter implementation
+ void OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread) override;
bool OnMessageReceived(const IPC::Message& message) override;
void OnResolveProxy(const GURL& url, IPC::Message* reply_msg);
@@ -49,37 +55,57 @@ class CONTENT_EXPORT ResolveProxyMsgHelper : public BrowserMessageFilter {
~ResolveProxyMsgHelper() override;
private:
- // Callback for the ProxyResolutionService (bound to |callback_|).
- void OnResolveProxyCompleted(int result);
+ // Used to destroy the |ResolveProxyMsgHelper| on the UI thread.
+ friend class base::DeleteHelper<ResolveProxyMsgHelper>;
// Starts the first pending request.
void StartPendingRequest();
+ // Virtual for testing. Returns false if unable to get a network service, due
+ // to the RenderProcessHost no longer existing.
+ virtual bool SendRequestToNetworkService(
+ const GURL& url,
+ network::mojom::ProxyLookupClientPtr proxy_lookup_client);
+
+ // network::mojom::ProxyLookupClient implementation.
+ void OnProxyLookupComplete(
+ const base::Optional<net::ProxyInfo>& proxy_info) override;
+
// A PendingRequest is a resolve request that is in progress, or queued.
struct PendingRequest {
public:
- PendingRequest(const GURL& url, IPC::Message* reply_msg)
- : url(url), reply_msg(reply_msg), request(NULL) {}
+ PendingRequest(const GURL& url, IPC::Message* reply_msg);
+ PendingRequest(PendingRequest&& pending_request) noexcept;
+ ~PendingRequest();
+
+ PendingRequest& operator=(PendingRequest&& pending_request) noexcept;
// The URL of the request.
GURL url;
// Data to pass back to the delegate on completion (we own it until then).
- IPC::Message* reply_msg;
+ std::unique_ptr<IPC::Message> reply_msg;
- // Handle for cancelling the current request if it has started (else NULL).
- net::ProxyResolutionService::Request* request;
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PendingRequest);
};
- // Info about the current outstanding proxy request.
- net::ProxyInfo proxy_info_;
+ const int render_process_host_id_;
// FIFO queue of pending requests. The first entry is always the current one.
using PendingRequestList = base::circular_deque<PendingRequest>;
PendingRequestList pending_requests_;
- scoped_refptr<net::URLRequestContextGetter> context_getter_;
- net::ProxyResolutionService* proxy_resolution_service_;
+ // Self-reference. Owned as long as there's an outstanding proxy lookup.
+ // Needed to shut down safely, since this class is refcounted, with some
+ // references owned on multiple threads, while |binding_| lives on the UI
+ // thread, and may receive callbacks there whenever there's a pending request.
+ scoped_refptr<ResolveProxyMsgHelper> owned_self_;
+
+ // Binding for the currently in-progress request, if any.
+ mojo::Binding<network::mojom::ProxyLookupClient> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(ResolveProxyMsgHelper);
};
} // namespace content
diff --git a/chromium/content/browser/resolve_proxy_msg_helper_unittest.cc b/chromium/content/browser/resolve_proxy_msg_helper_unittest.cc
index d9e5b3e3f90..92975535fc9 100644
--- a/chromium/content/browser/resolve_proxy_msg_helper_unittest.cc
+++ b/chromium/content/browser/resolve_proxy_msg_helper_unittest.cc
@@ -7,47 +7,68 @@
#include <tuple>
#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
#include "content/common/view_messages.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "ipc/ipc_test_sink.h"
#include "net/base/net_errors.h"
-#include "net/proxy_resolution/mock_proxy_resolver.h"
-#include "net/proxy_resolution/proxy_config_service.h"
-#include "net/proxy_resolution/proxy_resolution_service.h"
+#include "net/proxy_resolution/proxy_info.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/network/public/mojom/proxy_lookup_client.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
-// This ProxyConfigService always returns "http://pac" as the PAC url to use.
-class MockProxyConfigService : public net::ProxyConfigService {
- public:
- void AddObserver(Observer* observer) override {}
- void RemoveObserver(Observer* observer) override {}
- ConfigAvailability GetLatestProxyConfig(
- net::ProxyConfigWithAnnotation* results) override {
- *results = net::ProxyConfigWithAnnotation(
- net::ProxyConfig::CreateFromCustomPacURL(GURL("http://pac")),
- TRAFFIC_ANNOTATION_FOR_TESTS);
- return CONFIG_VALID;
- }
-};
-
class TestResolveProxyMsgHelper : public ResolveProxyMsgHelper {
public:
- TestResolveProxyMsgHelper(net::ProxyResolutionService* proxy_resolution_service,
- IPC::Listener* listener)
- : ResolveProxyMsgHelper(proxy_resolution_service), listener_(listener) {}
+ // Incoming ProxyLookupClientPtrs are written to |proxy_lookup_client|.
+ explicit TestResolveProxyMsgHelper(
+ IPC::Listener* listener,
+ network::mojom::ProxyLookupClientPtr* proxy_lookup_client)
+ : ResolveProxyMsgHelper(0 /* renderer_process_host_id */),
+ listener_(listener),
+ proxy_lookup_client_(proxy_lookup_client) {}
+
bool Send(IPC::Message* message) override {
+ // Shouldn't be calling Send() if there are no live references to |this|.
+ EXPECT_TRUE(HasAtLeastOneRef());
+
listener_->OnMessageReceived(*message);
delete message;
return true;
}
+ bool SendRequestToNetworkService(
+ const GURL& url,
+ network::mojom::ProxyLookupClientPtr proxy_lookup_client) override {
+ // Only one request should be send at a time.
+ EXPECT_FALSE(*proxy_lookup_client_);
+
+ if (fail_to_send_request_)
+ return false;
+
+ pending_url_ = url;
+ *proxy_lookup_client_ = std::move(proxy_lookup_client);
+ return true;
+ }
+
+ const GURL& pending_url() const { return pending_url_; }
+
+ void set_fail_to_send_request(bool fail_to_send_request) {
+ fail_to_send_request_ = fail_to_send_request;
+ }
+
protected:
~TestResolveProxyMsgHelper() override {}
IPC::Listener* listener_;
+
+ bool fail_to_send_request_ = false;
+
+ network::mojom::ProxyLookupClientPtr* proxy_lookup_client_;
+ GURL pending_url_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestResolveProxyMsgHelper);
};
class ResolveProxyMsgHelperTest : public testing::Test, public IPC::Listener {
@@ -63,12 +84,9 @@ class ResolveProxyMsgHelperTest : public testing::Test, public IPC::Listener {
};
ResolveProxyMsgHelperTest()
- : resolver_factory_(new net::MockAsyncProxyResolverFactory(false)),
- service_(new net::ProxyResolutionService(
- base::WrapUnique(new MockProxyConfigService),
- base::WrapUnique(resolver_factory_),
- nullptr)),
- helper_(new TestResolveProxyMsgHelper(service_.get(), this)) {
+ : helper_(base::MakeRefCounted<TestResolveProxyMsgHelper>(
+ this,
+ &proxy_lookup_client_)) {
test_sink_.AddFilter(this);
}
@@ -86,13 +104,6 @@ class ResolveProxyMsgHelperTest : public testing::Test, public IPC::Listener {
return IPC::SyncMessage::GenerateReply(&message);
}
- net::MockAsyncProxyResolverFactory* resolver_factory_;
- net::MockAsyncProxyResolver resolver_;
- std::unique_ptr<net::ProxyResolutionService> service_;
- scoped_refptr<ResolveProxyMsgHelper> helper_;
- std::unique_ptr<PendingResult> pending_result_;
-
- private:
bool OnMessageReceived(const IPC::Message& msg) override {
ViewHostMsg_ResolveProxy::ReplyParam reply_data;
EXPECT_TRUE(ViewHostMsg_ResolveProxy::ReadReplyParam(&msg, &reply_data));
@@ -104,6 +115,12 @@ class ResolveProxyMsgHelperTest : public testing::Test, public IPC::Listener {
}
TestBrowserThreadBundle thread_bundle_;
+
+ scoped_refptr<TestResolveProxyMsgHelper> helper_;
+ std::unique_ptr<PendingResult> pending_result_;
+
+ network::mojom::ProxyLookupClientPtr proxy_lookup_client_;
+
IPC::TestSink test_sink_;
};
@@ -123,15 +140,14 @@ TEST_F(ResolveProxyMsgHelperTest, Sequential) {
helper_->OnResolveProxy(url1, msg1);
- // Finish ProxyResolutionService's initialization.
- ASSERT_EQ(1u, resolver_factory_->pending_requests().size());
- resolver_factory_->pending_requests()[0]->CompleteNowWithForwarder(
- net::OK, &resolver_);
-
- ASSERT_EQ(1u, resolver_.pending_jobs().size());
- EXPECT_EQ(url1, resolver_.pending_jobs()[0]->url());
- resolver_.pending_jobs()[0]->results()->UseNamedProxy("result1:80");
- resolver_.pending_jobs()[0]->CompleteNow(net::OK);
+ // There should be a pending proxy lookup request. Respond to it.
+ EXPECT_EQ(url1, helper_->pending_url());
+ ASSERT_TRUE(proxy_lookup_client_);
+ net::ProxyInfo proxy_info;
+ proxy_info.UseNamedProxy("result1:80");
+ proxy_lookup_client_->OnProxyLookupComplete(proxy_info);
+ proxy_lookup_client_.reset();
+ base::RunLoop().RunUntilIdle();
// Check result.
EXPECT_EQ(true, pending_result()->result);
@@ -140,10 +156,12 @@ TEST_F(ResolveProxyMsgHelperTest, Sequential) {
helper_->OnResolveProxy(url2, msg2);
- ASSERT_EQ(1u, resolver_.pending_jobs().size());
- EXPECT_EQ(url2, resolver_.pending_jobs()[0]->url());
- resolver_.pending_jobs()[0]->results()->UseNamedProxy("result2:80");
- resolver_.pending_jobs()[0]->CompleteNow(net::OK);
+ EXPECT_EQ(url2, helper_->pending_url());
+ ASSERT_TRUE(proxy_lookup_client_);
+ proxy_info.UseNamedProxy("result2:80");
+ proxy_lookup_client_->OnProxyLookupComplete(proxy_info);
+ proxy_lookup_client_.reset();
+ base::RunLoop().RunUntilIdle();
// Check result.
EXPECT_EQ(true, pending_result()->result);
@@ -152,10 +170,11 @@ TEST_F(ResolveProxyMsgHelperTest, Sequential) {
helper_->OnResolveProxy(url3, msg3);
- ASSERT_EQ(1u, resolver_.pending_jobs().size());
- EXPECT_EQ(url3, resolver_.pending_jobs()[0]->url());
- resolver_.pending_jobs()[0]->results()->UseNamedProxy("result3:80");
- resolver_.pending_jobs()[0]->CompleteNow(net::OK);
+ EXPECT_EQ(url3, helper_->pending_url());
+ ASSERT_TRUE(proxy_lookup_client_);
+ proxy_info.UseNamedProxy("result3:80");
+ proxy_lookup_client_->OnProxyLookupComplete(proxy_info);
+ base::RunLoop().RunUntilIdle();
// Check result.
EXPECT_EQ(true, pending_result()->result);
@@ -173,48 +192,45 @@ TEST_F(ResolveProxyMsgHelperTest, QueueRequests) {
IPC::Message* msg2 = GenerateReply();
IPC::Message* msg3 = GenerateReply();
- // Start three requests. Since the proxy resolver is async, all the
- // requests will be pending.
+ // Start three requests. All the requests will be pending.
helper_->OnResolveProxy(url1, msg1);
-
- // Finish ProxyResolutionService's initialization.
- ASSERT_EQ(1u, resolver_factory_->pending_requests().size());
- resolver_factory_->pending_requests()[0]->CompleteNowWithForwarder(
- net::OK, &resolver_);
-
helper_->OnResolveProxy(url2, msg2);
helper_->OnResolveProxy(url3, msg3);
- // ResolveProxyHelper only keeps 1 request outstanding in
- // ProxyResolutionService at a time.
- ASSERT_EQ(1u, resolver_.pending_jobs().size());
- EXPECT_EQ(url1, resolver_.pending_jobs()[0]->url());
-
- resolver_.pending_jobs()[0]->results()->UseNamedProxy("result1:80");
- resolver_.pending_jobs()[0]->CompleteNow(net::OK);
+ // Complete first request.
+ EXPECT_EQ(url1, helper_->pending_url());
+ ASSERT_TRUE(proxy_lookup_client_);
+ net::ProxyInfo proxy_info;
+ proxy_info.UseNamedProxy("result1:80");
+ proxy_lookup_client_->OnProxyLookupComplete(proxy_info);
+ proxy_lookup_client_.reset();
+ base::RunLoop().RunUntilIdle();
// Check result.
EXPECT_EQ(true, pending_result()->result);
EXPECT_EQ("PROXY result1:80", pending_result()->proxy_list);
clear_pending_result();
- ASSERT_EQ(1u, resolver_.pending_jobs().size());
- EXPECT_EQ(url2, resolver_.pending_jobs()[0]->url());
-
- resolver_.pending_jobs()[0]->results()->UseNamedProxy("result2:80");
- resolver_.pending_jobs()[0]->CompleteNow(net::OK);
+ // Complete second request.
+ EXPECT_EQ(url2, helper_->pending_url());
+ ASSERT_TRUE(proxy_lookup_client_);
+ proxy_info.UseNamedProxy("result2:80");
+ proxy_lookup_client_->OnProxyLookupComplete(proxy_info);
+ proxy_lookup_client_.reset();
+ base::RunLoop().RunUntilIdle();
// Check result.
EXPECT_EQ(true, pending_result()->result);
EXPECT_EQ("PROXY result2:80", pending_result()->proxy_list);
clear_pending_result();
- ASSERT_EQ(1u, resolver_.pending_jobs().size());
- EXPECT_EQ(url3, resolver_.pending_jobs()[0]->url());
-
- resolver_.pending_jobs()[0]->results()->UseNamedProxy("result3:80");
- resolver_.pending_jobs()[0]->CompleteNow(net::OK);
+ // Complete third request.
+ EXPECT_EQ(url3, helper_->pending_url());
+ ASSERT_TRUE(proxy_lookup_client_);
+ proxy_info.UseNamedProxy("result3:80");
+ proxy_lookup_client_->OnProxyLookupComplete(proxy_info);
+ base::RunLoop().RunUntilIdle();
// Check result.
EXPECT_EQ(true, pending_result()->result);
@@ -222,7 +238,7 @@ TEST_F(ResolveProxyMsgHelperTest, QueueRequests) {
clear_pending_result();
}
-// Delete the helper while a request is in progress, and others are pending.
+// Delete the helper while a request is in progress and others are pending.
TEST_F(ResolveProxyMsgHelperTest, CancelPendingRequests) {
GURL url1("http://www.google1.com/");
GURL url2("http://www.google2.com/");
@@ -237,32 +253,133 @@ TEST_F(ResolveProxyMsgHelperTest, CancelPendingRequests) {
// requests will be pending.
helper_->OnResolveProxy(url1, msg1);
-
- // Finish ProxyResolutionService's initialization.
- ASSERT_EQ(1u, resolver_factory_->pending_requests().size());
- resolver_factory_->pending_requests()[0]->CompleteNowWithForwarder(
- net::OK, &resolver_);
-
helper_->OnResolveProxy(url2, msg2);
helper_->OnResolveProxy(url3, msg3);
- // ResolveProxyHelper only keeps 1 request outstanding in
- // ProxyResolutionService at a time.
- ASSERT_EQ(1u, resolver_.pending_jobs().size());
- EXPECT_EQ(url1, resolver_.pending_jobs()[0]->url());
+ // Check the first request is pending.
+ EXPECT_EQ(url1, helper_->pending_url());
+ ASSERT_TRUE(proxy_lookup_client_);
- // Delete the underlying ResolveProxyMsgHelper -- this should cancel all
- // the requests which are outstanding.
+ // Release a reference. The |helper_| will not be deleted, since there's a
+ // pending resolution.
helper_ = nullptr;
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(proxy_lookup_client_.is_bound());
+ EXPECT_FALSE(proxy_lookup_client_.encountered_error());
+
+ // Send Mojo message on the pipe.
+ net::ProxyInfo proxy_info;
+ proxy_info.UseNamedProxy("result1:80");
+ proxy_lookup_client_->OnProxyLookupComplete(proxy_info);
+
+ // Spinning the message loop results in the helper being destroyed and closing
+ // the pipe.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(!proxy_lookup_client_.is_bound() ||
+ proxy_lookup_client_.encountered_error());
+ // The result should not have been sent.
+ EXPECT_FALSE(pending_result());
- // The pending requests sent to the proxy resolver should have been cancelled.
+ // It should also be the case that msg1, msg2, msg3 were deleted by the
+ // cancellation. (Else will show up as a leak).
+}
- EXPECT_EQ(0u, resolver_.pending_jobs().size());
+// Issue a request that fails.
+TEST_F(ResolveProxyMsgHelperTest, RequestFails) {
+ GURL url("http://www.google.com/");
- EXPECT_TRUE(pending_result() == nullptr);
+ // Message will be deleted by the sink.
+ IPC::Message* msg = GenerateReply();
- // It should also be the case that msg1, msg2, msg3 were deleted by the
- // cancellation. (Else will show up as a leak in Valgrind).
+ helper_->OnResolveProxy(url, msg);
+
+ // There should be a pending proxy lookup request. Respond to it.
+ EXPECT_EQ(url, helper_->pending_url());
+ ASSERT_TRUE(proxy_lookup_client_);
+ proxy_lookup_client_->OnProxyLookupComplete(base::nullopt);
+ base::RunLoop().RunUntilIdle();
+
+ // Check result.
+ EXPECT_EQ(false, pending_result()->result);
+ EXPECT_EQ("", pending_result()->proxy_list);
+ clear_pending_result();
+}
+
+// Issue a request, only to have the Mojo pipe closed.
+TEST_F(ResolveProxyMsgHelperTest, PipeClosed) {
+ GURL url("http://www.google.com/");
+
+ // Message will be deleted by the sink.
+ IPC::Message* msg = GenerateReply();
+
+ helper_->OnResolveProxy(url, msg);
+
+ // There should be a pending proxy lookup request. Respond to it by closing
+ // the pipe.
+ EXPECT_EQ(url, helper_->pending_url());
+ ASSERT_TRUE(proxy_lookup_client_);
+ proxy_lookup_client_.reset();
+ base::RunLoop().RunUntilIdle();
+
+ // Check result.
+ EXPECT_EQ(false, pending_result()->result);
+ EXPECT_EQ("", pending_result()->proxy_list);
+ clear_pending_result();
+}
+
+// Fail to send a request to the network service.
+TEST_F(ResolveProxyMsgHelperTest, FailToSendRequest) {
+ GURL url("http://www.google.com/");
+
+ // Message will be deleted by the sink.
+ IPC::Message* msg = GenerateReply();
+
+ helper_->set_fail_to_send_request(true);
+
+ helper_->OnResolveProxy(url, msg);
+ // No request should be pending.
+ EXPECT_TRUE(helper_->pending_url().is_empty());
+
+ // Check result.
+ EXPECT_EQ(false, pending_result()->result);
+ EXPECT_EQ("", pending_result()->proxy_list);
+ clear_pending_result();
+}
+
+// Make sure if mojo callback is invoked after last externally owned reference
+// is released, there is no crash.
+// Regression test for https://crbug.com/870675
+TEST_F(ResolveProxyMsgHelperTest, Lifetime) {
+ GURL url("http://www.google1.com/");
+
+ // Messages are deleted by the sink.
+ IPC::Message* msg = GenerateReply();
+
+ helper_->OnResolveProxy(url, msg);
+
+ // There should be a pending proxy lookup request. Respond to it.
+ EXPECT_EQ(url, helper_->pending_url());
+ ASSERT_TRUE(proxy_lookup_client_);
+
+ // Release the |helper_| pointer. The object should keep a reference to
+ // itself, so should not be deleted.
+ helper_ = nullptr;
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(proxy_lookup_client_.is_bound());
+ EXPECT_FALSE(proxy_lookup_client_.encountered_error());
+
+ // Send Mojo message on the pipe.
+ net::ProxyInfo proxy_info;
+ proxy_info.UseNamedProxy("result1:80");
+ proxy_lookup_client_->OnProxyLookupComplete(proxy_info);
+
+ // Spinning the message loop results in the helper being destroyed and closing
+ // the pipe.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(!proxy_lookup_client_.is_bound() ||
+ proxy_lookup_client_.encountered_error());
+ // The result should not have been sent.
+ EXPECT_FALSE(pending_result());
}
} // namespace content
diff --git a/chromium/content/browser/resources/accessibility/OWNERS b/chromium/content/browser/resources/accessibility/OWNERS
deleted file mode 100644
index 697dba28c57..00000000000
--- a/chromium/content/browser/resources/accessibility/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-file://ui/accessibility/OWNERS
-
-# TEAM: chromium-accessibility@chromium.org
-# COMPONENT: Internals>Accessibility
diff --git a/chromium/content/browser/resources/accessibility/accessibility.css b/chromium/content/browser/resources/accessibility/accessibility.css
deleted file mode 100644
index 45ade4f058d..00000000000
--- a/chromium/content/browser/resources/accessibility/accessibility.css
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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.
- */
-
-body {
- font-family: Arial, sans-serif;
- font-size: 12px;
- margin: 10px 20px;
- min-width: 47em;
- padding-bottom: 65px;
-}
-
-img {
- float: left;
- height: 16px;
- padding-right: 5px;
- width: 16px;
-}
-
-.row {
- border-bottom: 1px solid #A0A0A0;
- padding: 5px;
-}
-
-.url {
- color: #A0A0A0;
-}
-
-p {
- line-height: 1.2em;
-}
-
-.columns {
- display: flex;
-}
-
-.column {
- flex-basis: 50%;
-}
-
-.checkbox_row {
- display: flex;
- align-items: center;
-}
-
-.checkbox_wrapper {
- width: 32px;
- margin: 0 0 2px 0;
- padding: 0;
- flex-grow: 0;
-}
-
-.secondary {
- margin: 0 0 12px 32px;
- color: #696969;
-}
-
-a {
- margin: 10px 20px;
-}
-
-label {
- margin: 0 0 2px 0;
- padding: 0;
- flex-grow: 1;
-}
-
-label.disabled {
- color: #696969;
-}
-
-label input[type="checkbox"] {
- margin-right: 6px;
-}
diff --git a/chromium/content/browser/resources/accessibility/accessibility.html b/chromium/content/browser/resources/accessibility/accessibility.html
deleted file mode 100644
index 80e7b7a665b..00000000000
--- a/chromium/content/browser/resources/accessibility/accessibility.html
+++ /dev/null
@@ -1,147 +0,0 @@
-<!doctype html>
-<html>
-<!--
-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.
--->
-<head>
- <meta charset="utf-8">
- <title>Accessibility Internals</title>
- <link rel="stylesheet" href="chrome://resources/css/chrome_shared.css">
- <link rel="stylesheet" href="accessibility.css">
- <script src="chrome://resources/js/cr.js"></script>
- <script src="chrome://resources/js/load_time_data.js"></script>
- <script src="chrome://resources/js/action_link.js"></script>
- <script src="chrome://resources/js/util.js"></script>
- <script src="strings.js"></script>
- <script src="accessibility.js"></script>
-</head>
-<body>
- <h1>Accessibility Internals</h1>
-
- <div class="columns">
- <div class="column">
- <h2>Global accessibility mode:</h2>
-
- <div class="checkbox_row">
- <span class="checkbox_wrapper">
- <input type="checkbox" id="native"
- aria-describedby="native_secondary">
- </span>
- <label for="native">
- Native accessibility API support
- </label>
- </div>
- <div id="native_secondary" class="secondary">
- Allows Chrome to be controlled via native accessibility APIs
- specific to this platform.
- </div>
-
- <div class="checkbox_row">
- <span class="checkbox_wrapper">
- <input type="checkbox" id="web"
- aria-describedby="web_secondary">
- </span>
- <label for="web">
- Web accessibility
- </label>
- </div>
- <div id="web_secondary" class="secondary">
- Accessibility support is enabled for web content.
- </div>
-
- <div class="checkbox_row">
- <span class="checkbox_wrapper">
- <input type="checkbox" id="text"
- aria-describedby="text_secondary">
- </span>
- <label for="text">
- Text metrics
- </label>
- </div>
- <div id="text_secondary" class="secondary">
- Enables support for querying line breaks and the bounding
- box of arbitrary character ranges.
- </div>
-
- <div class="checkbox_row">
- <span class="checkbox_wrapper">
- <input type="checkbox" id="screenreader"
- aria-describedby="screenreader_secondary">
- </span>
- <label for="screenreader">
- Screen reader support
- </label>
- </div>
- <div id="screenreader_secondary" class="secondary">
- Exposes accessibility APIs typically needed only by
- screen readers.
- </div>
-
- <div class="checkbox_row">
- <span class="checkbox_wrapper">
- <input type="checkbox" id="html"
- aria-describedby="html_secondary">
- </span>
- <label for="html">
- HTML
- </label>
- </div>
- <div id="html_secondary" class="secondary">
- Exposes HTML tag names and attributes via accessibility APIs.
- </div>
-
- <h2>Options:</h2>
-
- <div class="checkbox_row">
- <span class="checkbox_wrapper">
- <input type="checkbox" id="internal"
- aria-describedby="internal_secondary">
- </span>
- <label for="internal">
- Internal
- </label>
- </div>
- <div id="internal_secondary" class="secondary">
- Show internal accessibility tree instead of native
- </div>
-
- </div>
- <div class="column">
- <p>
- Accessibility features in Chrome are off by default and enabled
- automatically on-demand. Changes to this page only take effect
- until the next time Chrome is restarted.
- </p>
- <p>
- To force accessibility to be enabled at launch, run Chrome with this
- command-line flag:
- <pre>--force-renderer-accessibility</pre>
- </p>
- <p>
- To disable accessibility, run Chrome with this flag:
- <pre>--disable-renderer-accessibility</pre>
- </p>
- </div>
- </div>
-
- <!--
- <div id="global" class="row">Global accessibility mode:
- <a is="action-link" role="button" id="toggle_global" aria-labelledby="global"></a>
- </div>
-
- <div id="internal" class="row">Show internal accessibility tree instead of native:
- <a is="action-link" role="button" id="toggle_internal" aria-labelledby="internal"></a>
- </div>
--->
- <h2>Chrome Native UI:</h2>
- <div id="native_ui">
- <a is="action-link" tabindex="0" role="button" id="showNativeUI">show accessibility tree</a>
- </div>
-
- <h2>Pages:</h2>
- <div id="pages" class="list"></div>
- <script src="chrome://resources/js/i18n_template.js"></script>
-</body>
-</html>
diff --git a/chromium/content/browser/resources/accessibility/accessibility.js b/chromium/content/browser/resources/accessibility/accessibility.js
deleted file mode 100644
index 979aa311c22..00000000000
--- a/chromium/content/browser/resources/accessibility/accessibility.js
+++ /dev/null
@@ -1,272 +0,0 @@
-// 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.
-
-cr.define('accessibility', function() {
- 'use strict';
-
- // Note: keep these values in sync with the values in
- // content/common/accessibility_mode_enums.h
- const AXMode = {
- kNativeAPIs: 1 << 0,
- kWebContents: 1 << 1,
- kInlineTextBoxes: 1 << 2,
- kScreenReader: 1 << 3,
- kHTML: 1 << 4,
-
- get kAXModeWebContentsOnly() {
- return AXMode.kWebContents |
- AXMode.kInlineTextBoxes | AXMode.kScreenReader |
- AXMode.kHTML;
- },
-
- get kAXModeComplete() {
- return AXMode.kNativeAPIs | AXMode.kWebContents |
- AXMode.kInlineTextBoxes | AXMode.kScreenReader |
- AXMode.kHTML;
- }
- };
-
- function requestData() {
- var xhr = new XMLHttpRequest();
- xhr.open('GET', 'targets-data.json', false);
- xhr.send(null);
- if (xhr.status === 200) {
- console.log(xhr.responseText);
- return JSON.parse(xhr.responseText);
- }
- return [];
- }
-
- function toggleAccessibility(data, element, mode) {
- chrome.send('toggleAccessibility',
- [String(data.processId), String(data.routeId), mode]);
- document.location.reload();
- }
-
- function requestWebContentsTree(data, element) {
- chrome.send('requestWebContentsTree',
- [String(data.processId), String(data.routeId)]);
- }
-
- function initialize() {
- console.log('initialize');
- var data = requestData();
-
- bindCheckbox('native', data['native']);
- bindCheckbox('web', data['web']);
- bindCheckbox('text', data['text']);
- bindCheckbox('screenreader', data['screenreader']);
- bindCheckbox('html', data['html']);
- bindCheckbox('internal', data['internal']);
-
- $('pages').textContent = '';
-
- var list = data['list'];
- for (var i = 0; i < list.length; i++) {
- addToPagesList(list[i]);
- }
-
- var showNativeUI = $('showNativeUI');
- showNativeUI.addEventListener('click', function() {
- chrome.send('requestNativeUITree', []);
- });
- }
-
- function bindCheckbox(name, value) {
- if (value == 'on')
- $(name).checked = true;
- if (value == 'disabled') {
- $(name).disabled = true;
- $(name).labels[0].classList.add('disabled');
- }
- $(name).addEventListener('change', function() {
- chrome.send('setGlobalFlag', [name, $(name).checked]);
- document.location.reload();
- });
- }
-
- function addToPagesList(data) {
- // TODO: iterate through data and pages rows instead
- var id = data['processId'] + '.' + data['routeId'];
- var row = document.createElement('div');
- row.className = 'row';
- row.id = id;
- formatRow(row, data);
-
- row.processId = data.processId;
- row.routeId = data.routeId;
-
- var list = $('pages');
- list.appendChild(row);
- }
-
- function formatRow(row, data) {
- if (!('url' in data)) {
- if ('error' in data) {
- row.appendChild(createErrorMessageElement(data, row));
- return;
- }
- }
-
- var siteInfo = document.createElement('div');
- var properties = ['favicon_url', 'name', 'url'];
- for (var j = 0; j < properties.length; j++)
- siteInfo.appendChild(formatValue(data, properties[j]));
- row.appendChild(siteInfo);
-
- row.appendChild(createModeElement(AXMode.kNativeAPIs, data))
- row.appendChild(createModeElement(AXMode.kWebContents, data))
- row.appendChild(createModeElement(AXMode.kInlineTextBoxes,
- data))
- row.appendChild(createModeElement(AXMode.kScreenReader, data))
- row.appendChild(createModeElement(AXMode.kHTML, data))
-
- row.appendChild(document.createTextNode(' | '));
-
- if ('tree' in data) {
- row.appendChild(createShowAccessibilityTreeElement(data, row, true));
- row.appendChild(createHideAccessibilityTreeElement(row.id));
- row.appendChild(createAccessibilityTreeElement(data));
- }
- else {
- row.appendChild(createShowAccessibilityTreeElement(data, row, false));
- if ('error' in data)
- row.appendChild(createErrorMessageElement(data, row));
- }
- }
-
- function formatValue(data, property) {
- var value = data[property];
-
- if (property == 'favicon_url') {
- var faviconElement = document.createElement('img');
- if (value)
- faviconElement.src = value;
- faviconElement.alt = "";
- return faviconElement;
- }
-
- var text = value ? String(value) : '';
- if (text.length > 100)
- text = text.substring(0, 100) + '\u2026'; // ellipsis
-
- var span = document.createElement('span');
- span.textContent = ' ' + text + ' ';
- span.className = property;
- return span;
- }
-
- function getNameForAccessibilityMode(mode) {
- switch (mode) {
- case AXMode.kNativeAPIs:
- return "native"
- case AXMode.kWebContents:
- return "web"
- case AXMode.kInlineTextBoxes:
- return "inline text"
- case AXMode.kScreenReader:
- return "screen reader"
- case AXMode.kHTML:
- return "html"
- }
- return "unknown"
- }
-
- function createModeElement(mode, data) {
- var currentMode = data['a11y_mode'];
- var link = document.createElement('a', 'action-link');
- link.setAttribute('role', 'button');
-
- var stateText = ((currentMode & mode) != 0) ? 'true' : 'false';
- link.textContent = getNameForAccessibilityMode(mode) + ": " + stateText;
- link.setAttribute('aria-pressed', stateText);
- link.addEventListener('click',
- toggleAccessibility.bind(this, data, link, mode));
- return link;
- }
-
- function createShowAccessibilityTreeElement(data, row, opt_refresh) {
- var link = document.createElement('a', 'action-link');
- link.setAttribute('role', 'button');
- if (opt_refresh)
- link.textContent = 'refresh accessibility tree';
- else
- link.textContent = 'show accessibility tree';
- link.id = row.id + ':showTree';
- link.addEventListener('click',
- requestWebContentsTree.bind(this, data, link));
- return link;
- }
-
- function createHideAccessibilityTreeElement(id) {
- var link = document.createElement('a', 'action-link');
- link.setAttribute('role', 'button');
- link.textContent = 'hide accessibility tree';
- link.addEventListener('click',
- function() {
- $(id + ':showTree').textContent = 'show accessibility tree';
- var existingTreeElements = $(id).getElementsByTagName('pre');
- for (var i = 0; i < existingTreeElements.length; i++)
- $(id).removeChild(existingTreeElements[i]);
- var row = $(id);
- while (row.lastChild != $(id + ':showTree'))
- row.removeChild(row.lastChild);
- });
- return link;
- }
-
- function createErrorMessageElement(data) {
- var errorMessageElement = document.createElement('div');
- var errorMessage = data.error;
- errorMessageElement.innerHTML = errorMessage + '&nbsp;';
- var closeLink = document.createElement('a');
- closeLink.href='#';
- closeLink.textContent = '[close]';
- closeLink.addEventListener('click', function() {
- var parentElement = errorMessageElement.parentElement;
- parentElement.removeChild(errorMessageElement);
- if (parentElement.childElementCount == 0)
- parentElement.parentElement.removeChild(parentElement);
- });
- errorMessageElement.appendChild(closeLink);
- return errorMessageElement;
- }
-
- // Called from C++
- function showTree(data) {
- var id = data.processId + '.' + data.routeId;
- var row = $(id);
- if (!row)
- return;
-
- row.textContent = '';
- formatRow(row, data);
- }
-
- // Called from C++
- function showNativeUITree(data) {
- var treeElement = document.querySelector('#native_ui pre');
- if (!treeElement) {
- var treeElement = document.createElement('pre');
- $('native_ui').appendChild(treeElement);
- }
- treeElement.textContent = data.tree;
- }
-
- function createAccessibilityTreeElement(data) {
- var treeElement = document.createElement('pre');
- var tree = data.tree;
- treeElement.textContent = tree;
- return treeElement;
- }
-
- // These are the functions we export so they can be called from C++.
- return {
- initialize: initialize,
- showTree: showTree,
- showNativeUITree: showNativeUITree
- };
-});
-
-document.addEventListener('DOMContentLoaded', accessibility.initialize);
diff --git a/chromium/content/browser/resources/indexed_db/indexeddb_internals.html b/chromium/content/browser/resources/indexed_db/indexeddb_internals.html
index 692219c2667..2c87cd9d3a3 100644
--- a/chromium/content/browser/resources/indexed_db/indexeddb_internals.html
+++ b/chromium/content/browser/resources/indexed_db/indexeddb_internals.html
@@ -48,6 +48,10 @@
jsvalues=".idb_origin_url:url;.idb_partition_path:$partition_path">Force close</a>
<a href="#" class="download"
jsvalues=".idb_origin_url:url;.idb_partition_path:$partition_path">Download</a>
+ <a href="#" class="force-schema-downgrade"
+ jsvalues=".idb_origin_url:url;.idb_partition_path:$partition_path">Force schema downgrade</a>
+ <a href="https://crbug.com/829141"
+ target="_blank">?</a>
<span class="download-status" style="display: none">Loading...</span>
</div>
<div class="indexeddb-database" jsselect="$this.databases">
diff --git a/chromium/content/browser/resources/indexed_db/indexeddb_internals.js b/chromium/content/browser/resources/indexed_db/indexeddb_internals.js
index fc80a25d024..9051fe7f35b 100644
--- a/chromium/content/browser/resources/indexed_db/indexeddb_internals.js
+++ b/chromium/content/browser/resources/indexed_db/indexeddb_internals.js
@@ -29,6 +29,14 @@ cr.define('indexeddb', function() {
return false;
}
+ function forceSchemaDowngrade(event) {
+ var link = event.target;
+ progressNodeFor(link).style.display = 'inline';
+ chrome.send('forceSchemaDowngrade', [link.idb_partition_path,
+ link.idb_origin_url]);
+ return false;
+ }
+
function withNode(selector, partition_path, origin_url, callback) {
var links = document.querySelectorAll(selector);
for (var i = 0; i < links.length; ++i) {
@@ -59,6 +67,18 @@ cr.define('indexeddb', function() {
});
}
+ function onForcedSchemaDowngrade(partition_path,
+ origin_url,
+ connection_count) {
+ withNode('a.force-schema-downgrade', partition_path, origin_url,
+ function(link) {
+ progressNodeFor(link).style.display = 'none';
+ });
+ withNode('.connection-count', partition_path, origin_url, function(span) {
+ span.innerText = connection_count;
+ });
+ }
+
// Fired from the backend with a single partition's worth of
// IndexedDB metadata.
function onOriginsReady(origins, partition_path) {
@@ -76,11 +96,18 @@ cr.define('indexeddb', function() {
for (i = 0; i < forceCloseLinks.length; ++i) {
forceCloseLinks[i].addEventListener('click', forceClose, false);
}
+ var forceSchemaDowngradeLinks =
+ container.querySelectorAll('a.force-schema-downgrade');
+ for (i = 0; i < forceSchemaDowngradeLinks.length; ++i) {
+ forceSchemaDowngradeLinks[i].addEventListener(
+ 'click', forceSchemaDowngrade, false);
+ }
}
return {
initialize: initialize,
onForcedClose: onForcedClose,
+ onForcedSchemaDowngrade: onForcedSchemaDowngrade,
onOriginDownloadReady: onOriginDownloadReady,
onOriginsReady: onOriginsReady,
};
diff --git a/chromium/content/browser/resources/media/client_renderer.js b/chromium/content/browser/resources/media/client_renderer.js
index 0b5413e8ae7..5d04e38d678 100644
--- a/chromium/content/browser/resources/media/client_renderer.js
+++ b/chromium/content/browser/resources/media/client_renderer.js
@@ -16,6 +16,8 @@ var ClientRenderer = (function() {
this.logTable = logElement.querySelector('tbody');
this.graphElement = document.getElementById('graphs');
this.audioPropertyName = document.getElementById('audio-property-name');
+ this.audioFocusSessionListElement_ =
+ document.getElementById('audio-focus-session-list');
this.players = null;
this.selectedPlayer = null;
@@ -139,6 +141,19 @@ var ClientRenderer = (function() {
},
/**
+ * Called when the list of audio focus sessions has changed.
+ * @param sessions A list of media sessions that contain the current state.
+ */
+ audioFocusSessionUpdated: function(sessions) {
+ removeChildren(this.audioFocusSessionListElement_);
+
+ sessions.forEach(session => {
+ this.audioFocusSessionListElement_.appendChild(
+ this.createAudioFocusSessionRow_(session));
+ });
+ },
+
+ /**
* Called when an audio component is removed from the collection.
* @param componentType Integer AudioComponent enum value; must match values
* from the AudioLogFactory::AudioComponent enum.
@@ -358,7 +373,7 @@ var ClientRenderer = (function() {
var label = document.createElement('label');
var name_text = p.url || 'Player ' + player.id;
- var name_node = document.createElement('span');
+ var name_node = document.createElement('div');
name_node.appendChild(document.createTextNode(name_text));
name_node.className = 'player-name';
label.appendChild(name_node);
@@ -370,8 +385,7 @@ var ClientRenderer = (function() {
frame.push(p.frame_url);
var frame_text = frame.join(' - ');
if (frame_text) {
- label.appendChild(document.createElement('br'));
- var frame_node = document.createElement('span');
+ var frame_node = document.createElement('div');
frame_node.className = 'player-frame';
frame_node.appendChild(document.createTextNode(frame_text));
label.appendChild(frame_node);
@@ -390,8 +404,7 @@ var ClientRenderer = (function() {
desc.push('(' + p.event + ')');
var desc_text = desc.join(' ');
if (desc_text) {
- label.appendChild(document.createElement('br'));
- var desc_node = document.createElement('span');
+ var desc_node = document.createElement('div');
desc_node.className = 'player-desc';
desc_node.appendChild(document.createTextNode(desc_text));
label.appendChild(desc_node);
@@ -528,6 +541,15 @@ var ClientRenderer = (function() {
this.drawLog_();
}
},
+
+ createAudioFocusSessionRow_: function(session) {
+ const template = $('audio-focus-session-row');
+ const span = template.content.querySelectorAll('span');
+ span[0].textContent = session.name;
+ span[1].textContent = session.owner;
+ span[2].textContent = session.state;
+ return document.importNode(template.content, true);
+ },
};
return ClientRenderer;
diff --git a/chromium/content/browser/resources/media/main.js b/chromium/content/browser/resources/media/main.js
index add25a1fc38..9a25be49b7e 100644
--- a/chromium/content/browser/resources/media/main.js
+++ b/chromium/content/browser/resources/media/main.js
@@ -27,6 +27,13 @@ var media = (function() {
manager.updateVideoCaptureCapabilities(videoCaptureCapabilities);
};
+ media.onReceiveAudioFocusState = function(audioFocusState) {
+ if (!audioFocusState)
+ return;
+
+ manager.updateAudioFocusSessions(audioFocusState.sessions);
+ };
+
media.updateAudioComponent = function(component) {
var uniqueComponentId = component.owner_id + ':' + component.component_id;
switch (component.status) {
diff --git a/chromium/content/browser/resources/media/manager.js b/chromium/content/browser/resources/media/manager.js
index 590a78c1e37..994df2b5bfe 100644
--- a/chromium/content/browser/resources/media/manager.js
+++ b/chromium/content/browser/resources/media/manager.js
@@ -41,6 +41,14 @@ var Manager = (function() {
Manager.prototype = {
/**
+ * Updates the audio focus state.
+ * @param sessions A list of media sessions that contain the current state.
+ */
+ updateAudioFocusSessions: function(sessions) {
+ this.clientRenderer_.audioFocusSessionUpdated(sessions);
+ },
+
+ /**
* Updates an audio-component.
* @param componentType Integer AudioComponent enum value; must match values
* from the AudioLogFactory::AudioComponent enum.
diff --git a/chromium/content/browser/resources/media/media_internals.css b/chromium/content/browser/resources/media/media_internals.css
index 7daaa773c62..a86c5c996cb 100644
--- a/chromium/content/browser/resources/media/media_internals.css
+++ b/chromium/content/browser/resources/media/media_internals.css
@@ -178,11 +178,9 @@ h3 {
color: rgba(0, 0, 0, .5);
}
+label.audio-focus-session,
label.selectable-button {
- -webkit-user-select: none;
- display: inline-block;
- background: #BDF;
- cursor: pointer;
+ display: block;
border: solid 1px #999;
border-radius: 3px;
padding: 6px;
@@ -191,6 +189,12 @@ label.selectable-button {
word-break: break-all;
}
+label.selectable-button {
+ background: #BDF;
+ cursor: pointer;
+ user-select: none;
+}
+
input.selectable-button {
display: none;
}
@@ -205,6 +209,7 @@ input.selectable-button:hover + label.selectable-button {
border-color: #666;
}
+label.audio-focus-session,
label.destructed-player {
background-color: #EEE;
}
@@ -215,6 +220,9 @@ label.destructed-player {
.player-frame {
font-style: italic;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
}
.no-players-selected #players .property-wrapper,
@@ -226,3 +234,6 @@ label.destructed-player {
display: none;
}
+#audio-focus-session-list {
+ list-style: none;
+}
diff --git a/chromium/content/browser/resources/media/media_internals.html b/chromium/content/browser/resources/media/media_internals.html
index e624b5a2419..6df11b93b5c 100644
--- a/chromium/content/browser/resources/media/media_internals.html
+++ b/chromium/content/browser/resources/media/media_internals.html
@@ -25,6 +25,7 @@ found in the LICENSE file.
<tab>Players</tab>
<tab>Audio</tab>
<tab>Video Capture</tab>
+ <tab>Audio Focus</tab>
</tabs>
<tabpanels>
<tabpanel id="players">
@@ -120,6 +121,21 @@ found in the LICENSE file.
</table>
</div>
</tabpanel>
+ <tabpanel id="players">
+ <div id="list-wrapper">
+ <h2>Active Sessions</h2>
+ <ul id="audio-focus-session-list" class="show-none-if-empty"></ul>
+ </div>
+ <template id="audio-focus-session-row">
+ <li>
+ <label class="audio-focus-session">
+ <span class="player-name"></span><br />
+ <span class="player-frame"></span><br />
+ <span class="player-desc"></span>
+ </label>
+ </li>
+ </template>
+ </tabpanel>
</tabpanels>
</tabbox>
<dialog id="clipboard-dialog">
diff --git a/chromium/content/browser/scheduler/responsiveness/OWNERS b/chromium/content/browser/scheduler/responsiveness/OWNERS
new file mode 100644
index 00000000000..8b3b15dc071
--- /dev/null
+++ b/chromium/content/browser/scheduler/responsiveness/OWNERS
@@ -0,0 +1,2 @@
+erikchen@chromium.org
+tdresser@chromium.org
diff --git a/chromium/content/browser/scheduler/responsiveness/README b/chromium/content/browser/scheduler/responsiveness/README
new file mode 100644
index 00000000000..68ee4d93be7
--- /dev/null
+++ b/chromium/content/browser/scheduler/responsiveness/README
@@ -0,0 +1,35 @@
+The classes in this folder estimate the responsiveness of Chrome by measuring
+execution latency on the UI and IO threads of the browser process.
+
+There are four types of work executed on the UI and IO threads.
+1) Both the UI and IO threads can have tasks posted to them via the Task
+ Scheduler [e.g. via content::BrowserThread::PostTask].
+2) The UI thread processes native events directly from the message loop
+ [NSEvents on macOS, MSGs on Windows, InputEvents on Android, XEvents on
+ X11, etc.]
+3) The IO thread's message pump processes IPCs by listening on data channels
+ [e.g. fds] and waking up on available data.
+4) The UI thread's message loop may process other platform-specific sources.
+
+Execution latency is a measure of the duration between when a task or event is
+scheduled or created, and when it finishes executing. We measure this for (1)
+and (2) but not (3) and (4). More details:
+
+1) Record TimeTicks::Now() when the event is scheduled and compare to
+ TimeTicks::Now() when the event finishes execution.
+2) All native events have a creation timestamp. Compare that to
+ TimeTicks::Now() when the event finishes execution.
+3) There's no good solution here, since the current wire format for IPCs does
+ not record the time at which the IPC was written to the data channel. The
+ time between reading from the data channel and finishing execution is
+ typically small, as heavy tasks are supposed to be dispatched off the IO
+ thread.
+4) There is no consistent way to measure the execution latency of work that
+ is neither a task nor an event. If individual sources prove to be
+ a source of non-responsiveness, they will need to be addressed on a
+ case-by-case basis.
+
+Note: As long as there are any tasks or events queued, jank caused by (3) or
+(4) will be accounted for, as it will show up as increased queueing time.
+
+Design doc: https://docs.google.com/document/d/1vDSGFvJblh7yJ3U3RVB_7qZLubyfTbQdQjuN1GoUNkc/edit
diff --git a/chromium/content/browser/scheduler/responsiveness/calculator.cc b/chromium/content/browser/scheduler/responsiveness/calculator.cc
new file mode 100644
index 00000000000..2c82001f04e
--- /dev/null
+++ b/chromium/content/browser/scheduler/responsiveness/calculator.cc
@@ -0,0 +1,216 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/scheduler/responsiveness/calculator.h"
+
+#include <algorithm>
+#include <set>
+
+#include "base/metrics/histogram_macros.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+namespace responsiveness {
+
+namespace {
+
+// We divide the measurement interval into discretized time slices.
+// Each slice is marked as janky if it contained a janky task. A janky task is
+// one whose execution latency is greater than kJankThreshold.
+constexpr base::TimeDelta kMeasurementInterval =
+ base::TimeDelta::FromSeconds(30);
+
+// A task or event longer than kJankThreshold is considered janky.
+constexpr base::TimeDelta kJankThreshold =
+ base::TimeDelta::FromMilliseconds(100);
+
+// If there have been no events/tasks on the UI thread for a significant period
+// of time, it's likely because Chrome was suspended.
+// This value is copied from queueing_time_estimator.cc:kInvalidPeriodThreshold.
+constexpr base::TimeDelta kSuspendInterval = base::TimeDelta::FromSeconds(30);
+
+// Given a |jank|, finds each janky slice between |start_time| and |end_time|,
+// and adds it to |janky_slices|.
+void AddJankySlices(std::set<int>* janky_slices,
+ const Calculator::Jank& jank,
+ base::TimeTicks start_time,
+ base::TimeTicks end_time) {
+ // Ignore the first jank threshold, since that's the part of the task/event
+ // that wasn't janky.
+ base::TimeTicks jank_start = jank.start_time + kJankThreshold;
+
+ // Bound by |start_time| and |end_time|.
+ jank_start = std::max(jank_start, start_time);
+ base::TimeTicks jank_end = std::min(jank.end_time, end_time);
+
+ // Find each janky slice, and add it to |janky_slices|.
+ while (jank_start < jank_end) {
+ // Convert |jank_start| to a slice label.
+ int label = (jank_start - start_time) / kJankThreshold;
+ janky_slices->insert(label);
+
+ jank_start += kJankThreshold;
+ }
+}
+
+} // namespace
+
+Calculator::Jank::Jank(base::TimeTicks start_time, base::TimeTicks end_time)
+ : start_time(start_time), end_time(end_time) {
+ DCHECK_LE(start_time, end_time);
+}
+
+Calculator::Calculator()
+ : last_calculation_time_(base::TimeTicks::Now()),
+ most_recent_activity_time_(last_calculation_time_) {}
+Calculator::~Calculator() = default;
+
+void Calculator::TaskOrEventFinishedOnUIThread(base::TimeTicks schedule_time,
+ base::TimeTicks finish_time) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ if (finish_time - schedule_time >= kJankThreshold) {
+ GetJanksOnUIThread().emplace_back(schedule_time, finish_time);
+ }
+
+ // We rely on the assumption that |finish_time| is the current time.
+ CalculateResponsivenessIfNecessary(/*current_time=*/finish_time);
+}
+
+void Calculator::TaskOrEventFinishedOnIOThread(base::TimeTicks schedule_time,
+ base::TimeTicks finish_time) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ if (finish_time - schedule_time >= kJankThreshold) {
+ base::AutoLock lock(io_thread_lock_);
+ GetJanksOnIOThread().emplace_back(schedule_time, finish_time);
+ }
+}
+
+void Calculator::EmitResponsiveness(int janky_slices) {
+ UMA_HISTOGRAM_COUNTS_1000(
+ "Browser.Responsiveness.JankyIntervalsPerThirtySeconds", janky_slices);
+}
+
+base::TimeTicks Calculator::GetLastCalculationTime() {
+ return last_calculation_time_;
+}
+
+void Calculator::CalculateResponsivenessIfNecessary(
+ base::TimeTicks current_time) {
+ base::TimeTicks last_activity_time = most_recent_activity_time_;
+ most_recent_activity_time_ = current_time;
+
+ // We intentionally dump all data if it appears that Chrome was suspended.
+ // [e.g. machine is asleep, process is backgrounded on Android]. We don't have
+ // an explicit signal for this. Instead, we rely on the assumption that when
+ // Chrome is not suspended, there is a steady stream of tasks and events on
+ // the UI thread. If there's been a significant amount of time since the last
+ // calculation, then it's likely because Chrome was suspended.
+ if (current_time - last_activity_time > kSuspendInterval) {
+ last_calculation_time_ = current_time;
+ GetJanksOnUIThread().clear();
+ {
+ base::AutoLock lock(io_thread_lock_);
+ GetJanksOnIOThread().clear();
+ }
+ return;
+ }
+
+ base::TimeDelta time_since_last_calculation =
+ current_time - last_calculation_time_;
+ if (time_since_last_calculation <= kMeasurementInterval)
+ return;
+
+ // At least |kMeasurementInterval| time has passed, so we want to move forward
+ // |last_calculation_time_| and make measurements based on janks in that
+ // interval.
+ int number_of_measurement_intervals =
+ time_since_last_calculation / kMeasurementInterval;
+ DCHECK(number_of_measurement_intervals >= 1);
+
+ base::TimeTicks new_calculation_time =
+ last_calculation_time_ +
+ number_of_measurement_intervals * kMeasurementInterval;
+
+ // Acquire the janks in the measurement interval from the UI and IO threads.
+ std::vector<JankList> janks_from_multiple_threads;
+ janks_from_multiple_threads.push_back(
+ TakeJanksOlderThanTime(&GetJanksOnUIThread(), new_calculation_time));
+ {
+ base::AutoLock lock(io_thread_lock_);
+ janks_from_multiple_threads.push_back(
+ TakeJanksOlderThanTime(&GetJanksOnIOThread(), new_calculation_time));
+ }
+
+ CalculateResponsiveness(std::move(janks_from_multiple_threads),
+ last_calculation_time_, new_calculation_time);
+
+ last_calculation_time_ = new_calculation_time;
+}
+
+void Calculator::CalculateResponsiveness(
+ std::vector<JankList> janks_from_multiple_threads,
+ base::TimeTicks start_time,
+ base::TimeTicks end_time) {
+ while (start_time < end_time) {
+ base::TimeTicks current_interval_end_time =
+ start_time + kMeasurementInterval;
+
+ // We divide the current measurement interval into slices. Each slice is
+ // given a monotonically increasing label, from 0 to |kNumberOfSlices - 1|.
+ // Example [all times in milliseconds since UNIX epoch]:
+ // The measurement interval is [50135, 80135].
+ // The slice [50135, 50235] is labeled 0.
+ // The slice [50235, 50335] is labeled 1.
+ // ...
+ // The slice [80035, 80135] is labeled 299.
+ std::set<int> janky_slices;
+
+ for (const JankList& janks : janks_from_multiple_threads) {
+ for (const Jank& jank : janks) {
+ AddJankySlices(&janky_slices, jank, start_time,
+ current_interval_end_time);
+ }
+ }
+
+ EmitResponsiveness(janky_slices.size());
+
+ start_time = current_interval_end_time;
+ }
+}
+
+Calculator::JankList& Calculator::GetJanksOnUIThread() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ return janks_on_ui_thread_;
+}
+
+Calculator::JankList& Calculator::GetJanksOnIOThread() {
+ io_thread_lock_.AssertAcquired();
+ return janks_on_io_thread_;
+}
+
+Calculator::JankList Calculator::TakeJanksOlderThanTime(
+ JankList* janks,
+ base::TimeTicks end_time) {
+ // Find all janks with Jank.start_time < |end_time|.
+ auto it = std::partition(
+ janks->begin(), janks->end(),
+ [&end_time](const Jank& jank) { return jank.start_time < end_time; });
+
+ // Early exit. We don't need to remove any Janks either, since Jank.end_time
+ // >= Jank.start_time.
+ if (it == janks->begin())
+ return JankList();
+
+ JankList janks_to_return(janks->begin(), it);
+
+ // Remove all janks with Jank.end_time < |end_time|.
+ auto first_jank_to_keep = std::partition(
+ janks->begin(), janks->end(),
+ [&end_time](const Jank& jank) { return jank.end_time < end_time; });
+ janks->erase(janks->begin(), first_jank_to_keep);
+ return janks_to_return;
+}
+
+} // namespace responsiveness
+} // namespace content
diff --git a/chromium/content/browser/scheduler/responsiveness/calculator.h b/chromium/content/browser/scheduler/responsiveness/calculator.h
new file mode 100644
index 00000000000..a5c7c406362
--- /dev/null
+++ b/chromium/content/browser/scheduler/responsiveness/calculator.h
@@ -0,0 +1,130 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_SCHEDULER_RESPONSIVENESS_CALCULATOR_H_
+#define CONTENT_BROWSER_SCHEDULER_RESPONSIVENESS_CALCULATOR_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "content/common/content_export.h"
+
+namespace content {
+namespace responsiveness {
+
+// This class receives execution latency on events and tasks, and uses that to
+// estimate responsiveness.
+//
+// All members are UI-thread affine, with the exception of
+// |janks_on_io_thread_| which is protected by |io_thread_lock_|.
+class CONTENT_EXPORT Calculator {
+ public:
+ Calculator();
+ virtual ~Calculator();
+
+ // Must be called from the UI thread.
+ // virtual for testing.
+ // The implementation will gracefully handle calls where finish_time <
+ // schedule_time.
+ // The implementation will gracefully handle successive calls with
+ // |schedule_times| that are out of order.
+ virtual void TaskOrEventFinishedOnUIThread(base::TimeTicks schedule_time,
+ base::TimeTicks finish_time);
+
+ // Must be called from the IO thread.
+ // virtual for testing.
+ virtual void TaskOrEventFinishedOnIOThread(base::TimeTicks schedule_time,
+ base::TimeTicks finish_time);
+
+ // Each janking task/event is fully defined by |start_time| and |end_time|.
+ // Note that |duration| = |end_time| - |start_time|.
+ struct Jank {
+ Jank(base::TimeTicks start_time, base::TimeTicks end_time);
+
+ base::TimeTicks start_time;
+ base::TimeTicks end_time;
+ };
+
+ protected:
+ // Emits an UMA metric for responsiveness of a single measurement interval.
+ // Exposed for testing.
+ virtual void EmitResponsiveness(int janky_slices);
+
+ // Exposed for testing.
+ base::TimeTicks GetLastCalculationTime();
+
+ private:
+ using JankList = std::vector<Jank>;
+
+ // If sufficient time has passed since the last calculation, then calculate
+ // responsiveness again and update |last_calculation_time_|.
+ //
+ // We only trigger this from the UI thread since triggering it from the IO
+ // thread would require us to grab the lock, which could cause contention. We
+ // only need this to trigger every 30s or so, and we generally expect there to
+ // be some activity on the UI thread if Chrome is actually in use.
+ void CalculateResponsivenessIfNecessary(base::TimeTicks current_time);
+
+ // Responsiveness is calculated by:
+ // 1) Discretizing time into small intervals.
+ // 2) In each interval, looking to see if there is a Janky event. If so, the
+ // interval is marked as |janky|.
+ // 3) Computing the percentage of intervals that are janky.
+ // The caller guarantees that Jank.end_time < |end_time|.
+ //
+ // This method intentionally takes a std::vector<JankList>, as we may want to
+ // extend it in the future to take JankLists from other threads/processes.
+ void CalculateResponsiveness(
+ std::vector<JankList> janks_from_multiple_threads,
+ base::TimeTicks start_time,
+ base::TimeTicks end_time);
+
+ // Accessor for |janks_on_ui_thread_|. Must be called from the UI thread.
+ JankList& GetJanksOnUIThread();
+
+ // Accessor for |janks_on_io_thread_|. Requires that |io_thread_lock_| has
+ // already been taken. May be called from any thread.
+ JankList& GetJanksOnIOThread();
+
+ // This method:
+ // 1) Removes all Janks with Jank.end_time < |end_time| from |janks|.
+ // 2) Returns all Janks with Jank.start_time < |end_time|.
+ JankList TakeJanksOlderThanTime(JankList* janks, base::TimeTicks end_time);
+
+ // This should only be accessed via the accessor, which checks that the caller
+ // is on the UI thread.
+ JankList janks_on_ui_thread_;
+
+ // We expect there to be low contention and this lock to cause minimal
+ // overhead. If performance of this lock proves to be a problem, we can move
+ // to a lock-free data structure.
+ base::Lock io_thread_lock_;
+
+ // This should only be accessed via the accessor, which checks that
+ // |io_thread_lock_| has been acquired.
+ JankList janks_on_io_thread_;
+
+ // The last time at which metrics were emitted. All janks older than this time
+ // have been consumed. Newer janks are still in their JankLists waiting to be
+ // consumed.
+ base::TimeTicks last_calculation_time_;
+
+ // This class keeps track of the time at which any activity occurred on the UI
+ // thread. If a sufficiently long period of time passes without any activity,
+ // then it's assumed that the process was suspended. In this case, we should
+ // not emit any responsiveness metrics.
+ //
+ // Note that the process may be suspended while a task or event is being
+ // executed, so a very long execution time should be treated similarly.
+ base::TimeTicks most_recent_activity_time_;
+
+ DISALLOW_COPY_AND_ASSIGN(Calculator);
+};
+
+} // namespace responsiveness
+} // namespace content
+
+#endif // CONTENT_BROWSER_SCHEDULER_RESPONSIVENESS_CALCULATOR_H_
diff --git a/chromium/content/browser/scheduler/responsiveness/calculator_unittest.cc b/chromium/content/browser/scheduler/responsiveness/calculator_unittest.cc
new file mode 100644
index 00000000000..25f81ad24fe
--- /dev/null
+++ b/chromium/content/browser/scheduler/responsiveness/calculator_unittest.cc
@@ -0,0 +1,235 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/scheduler/responsiveness/calculator.h"
+
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace responsiveness {
+
+namespace {
+// Copied from calculator.cc.
+constexpr int kMeasurementIntervalInMs = 30 * 1000;
+constexpr int kJankThresholdInMs = 100;
+
+class FakeCalculator : public Calculator {
+ public:
+ std::vector<int>& Emissions() { return janky_slices_; }
+
+ void EmitResponsiveness(int janky_slices) override {
+ janky_slices_.push_back(janky_slices);
+ }
+
+ using Calculator::GetLastCalculationTime;
+
+ private:
+ std::vector<int> janky_slices_;
+};
+
+} // namespace
+
+class ResponsivenessCalculatorTest : public testing::Test {
+ public:
+ void SetUp() override {
+ calculator_ = std::make_unique<FakeCalculator>();
+ last_calculation_time_ = calculator_->GetLastCalculationTime();
+ }
+
+ void AddEventUI(int schedule_time_in_ms, int finish_time_in_ms) {
+ calculator_->TaskOrEventFinishedOnUIThread(
+ last_calculation_time_ +
+ base::TimeDelta::FromMilliseconds(schedule_time_in_ms),
+ last_calculation_time_ +
+ base::TimeDelta::FromMilliseconds(finish_time_in_ms));
+ }
+
+ void AddEventIO(int schedule_time_in_ms, int finish_time_in_ms) {
+ calculator_->TaskOrEventFinishedOnIOThread(
+ last_calculation_time_ +
+ base::TimeDelta::FromMilliseconds(schedule_time_in_ms),
+ last_calculation_time_ +
+ base::TimeDelta::FromMilliseconds(finish_time_in_ms));
+ }
+
+ void TriggerCalculation() {
+ AddEventUI(kMeasurementIntervalInMs + 1, kMeasurementIntervalInMs + 2);
+ last_calculation_time_ = calculator_->GetLastCalculationTime();
+ }
+
+ protected:
+ // This member sets up BrowserThread::IO and BrowserThread::UI. It must be the
+ // first member, as other members may depend on these abstractions.
+ content::TestBrowserThreadBundle test_browser_thread_bundle_;
+
+ std::unique_ptr<FakeCalculator> calculator_;
+ base::TimeTicks last_calculation_time_;
+};
+
+// A single event of length slightly longer than kJankThresholdInMs.
+TEST_F(ResponsivenessCalculatorTest, ShortJank) {
+ AddEventUI(40, 40 + kJankThresholdInMs + 5);
+ TriggerCalculation();
+
+ ASSERT_EQ(1u, calculator_->Emissions().size());
+ EXPECT_EQ(1, calculator_->Emissions()[0]);
+}
+
+// A single event of length slightly longer than 10 * kJankThresholdInMs.
+TEST_F(ResponsivenessCalculatorTest, LongJank) {
+ AddEventUI(40, 40 + 10 * kJankThresholdInMs + 5);
+ TriggerCalculation();
+
+ ASSERT_EQ(1u, calculator_->Emissions().size());
+ EXPECT_EQ(10, calculator_->Emissions()[0]);
+}
+
+// Events that last less than 100ms do not jank, regardless of start time.
+TEST_F(ResponsivenessCalculatorTest, NoJank) {
+ int base_time = 30;
+ for (int i = 0; i < kJankThresholdInMs; ++i) {
+ AddEventUI(base_time, base_time + i);
+ }
+
+ base_time += kJankThresholdInMs;
+ for (int i = 0; i < kJankThresholdInMs; ++i) {
+ AddEventUI(base_time + i, base_time + 2 * i);
+ }
+
+ TriggerCalculation();
+ ASSERT_EQ(1u, calculator_->Emissions().size());
+ EXPECT_EQ(0, calculator_->Emissions()[0]);
+}
+
+// 10 Jank events, but very closely overlapping. Time slices are discretized and
+// fixed, e.g. [0 100] [100 200] [200 300]. In this test, the events all start
+// in the [0 100] slice and end in the [100 200] slice. All of them end up
+// marking the [100 200] slice as janky.
+TEST_F(ResponsivenessCalculatorTest, OverlappingJank) {
+ int base_time = 30;
+ for (int i = 0; i < 10; ++i) {
+ AddEventUI(base_time, base_time + kJankThresholdInMs + 10);
+ }
+
+ TriggerCalculation();
+ ASSERT_EQ(1u, calculator_->Emissions().size());
+ EXPECT_EQ(1, calculator_->Emissions()[0]);
+}
+
+// UI thread has 3 jank events on slices 1, 2, 3
+// IO thread has 3 jank events on slices 3, 4, 5,
+// There should be a total of 5 jank events.
+TEST_F(ResponsivenessCalculatorTest, OverlappingJankMultipleThreads) {
+ int base_time = 105;
+ for (int i = 0; i < 3; ++i) {
+ AddEventUI(base_time + i * kJankThresholdInMs,
+ base_time + (i + 1) * kJankThresholdInMs + 10);
+ }
+
+ base_time = 305;
+ for (int i = 0; i < 3; ++i) {
+ AddEventIO(base_time + i * kJankThresholdInMs,
+ base_time + (i + 1) * kJankThresholdInMs + 10);
+ }
+
+ TriggerCalculation();
+ ASSERT_EQ(1u, calculator_->Emissions().size());
+ EXPECT_EQ(5, calculator_->Emissions()[0]);
+}
+
+// Three janks, each of length 2, separated by some shorter events.
+TEST_F(ResponsivenessCalculatorTest, SeparatedJanks) {
+ int base_time = 105;
+
+ for (int i = 0; i < 3; ++i) {
+ AddEventUI(base_time, base_time + 1);
+ AddEventUI(base_time, base_time + 2 * kJankThresholdInMs + 1);
+ base_time += 10 * kJankThresholdInMs;
+ }
+ TriggerCalculation();
+
+ ASSERT_EQ(1u, calculator_->Emissions().size());
+ EXPECT_EQ(6, calculator_->Emissions()[0]);
+}
+
+TEST_F(ResponsivenessCalculatorTest, MultipleTrigger) {
+ int base_time = 105;
+
+ // 3 Janks, then trigger, then repeat.
+ for (int i = 0; i < 10; ++i) {
+ for (int j = 0; j < 3; ++j) {
+ AddEventUI(base_time, base_time + 3 * kJankThresholdInMs + 1);
+ base_time += 3 * kJankThresholdInMs;
+ }
+ TriggerCalculation();
+ }
+
+ ASSERT_EQ(10u, calculator_->Emissions().size());
+ for (int i = 0; i < 10; ++i) {
+ EXPECT_EQ(9, calculator_->Emissions()[i]);
+ }
+}
+
+// A long delay means that the machine likely went to sleep.
+TEST_F(ResponsivenessCalculatorTest, LongDelay) {
+ int base_time = 105;
+ AddEventUI(base_time, base_time + 3 * kJankThresholdInMs + 1);
+ base_time += 10 * kMeasurementIntervalInMs;
+ AddEventUI(base_time, base_time + 1);
+
+ ASSERT_EQ(0u, calculator_->Emissions().size());
+}
+
+// A long event means that the machine likely went to sleep.
+TEST_F(ResponsivenessCalculatorTest, LongEvent) {
+ int base_time = 105;
+ AddEventUI(base_time, base_time + 10 * kMeasurementIntervalInMs);
+
+ ASSERT_EQ(0u, calculator_->Emissions().size());
+}
+
+// An event that crosses a measurement interval boundary should count towards
+// both measurement intervals.
+TEST_F(ResponsivenessCalculatorTest, EventCrossesBoundary) {
+ // Dummy event so that Calculator doesn't think the process is suspended.
+ AddEventUI(0.5 * kMeasurementIntervalInMs, 0.5 * kMeasurementIntervalInMs);
+
+ // The event goes from [29801, 30150]. It should count as 1 jank in the first
+ // measurement interval and 2 in the second.
+ AddEventUI(kMeasurementIntervalInMs - 2 * kJankThresholdInMs + 1,
+ kMeasurementIntervalInMs + 1.5 * kJankThresholdInMs);
+
+ // Dummy event so that Calculator doesn't think the process is suspended.
+ AddEventUI(1.5 * kMeasurementIntervalInMs, 1.5 * kMeasurementIntervalInMs);
+
+ // Trigger another calculation.
+ AddEventUI(2 * kMeasurementIntervalInMs + 1,
+ 2 * kMeasurementIntervalInMs + 1);
+ ASSERT_EQ(2u, calculator_->Emissions().size());
+ EXPECT_EQ(1, calculator_->Emissions()[0]);
+ EXPECT_EQ(2, calculator_->Emissions()[1]);
+}
+
+// Events may not be ordered by start or end time.
+TEST_F(ResponsivenessCalculatorTest, UnorderedEvents) {
+ // We add the following events:
+ // [100, 250]
+ // [150, 300]
+ // [50, 200]
+ // [50, 390]
+ // The event [50, 400] subsumes all previous events.
+ AddEventUI(kJankThresholdInMs, 2.5 * kJankThresholdInMs);
+ AddEventUI(1.5 * kJankThresholdInMs, 3 * kJankThresholdInMs);
+ AddEventUI(0.5 * kJankThresholdInMs, 2 * kJankThresholdInMs);
+ AddEventUI(0.5 * kJankThresholdInMs, 3.9 * kJankThresholdInMs);
+
+ TriggerCalculation();
+
+ ASSERT_EQ(1u, calculator_->Emissions().size());
+ EXPECT_EQ(3, calculator_->Emissions()[0]);
+}
+
+} // namespace responsiveness
+} // namespace content
diff --git a/chromium/content/browser/scheduler/responsiveness/message_loop_observer.cc b/chromium/content/browser/scheduler/responsiveness/message_loop_observer.cc
new file mode 100644
index 00000000000..01284022732
--- /dev/null
+++ b/chromium/content/browser/scheduler/responsiveness/message_loop_observer.cc
@@ -0,0 +1,34 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/scheduler/responsiveness/message_loop_observer.h"
+
+namespace content {
+namespace responsiveness {
+
+MessageLoopObserver::MessageLoopObserver(TaskCallback will_run_task_callback,
+ TaskCallback did_run_task_callback)
+ : will_run_task_callback_(will_run_task_callback),
+ did_run_task_callback_(did_run_task_callback) {
+ base::MessageLoopCurrent::Get()->SetAddQueueTimeToTasks(true);
+ base::MessageLoopCurrent::Get()->AddTaskObserver(this);
+}
+
+MessageLoopObserver::~MessageLoopObserver() {
+ base::MessageLoopCurrent::Get()->RemoveTaskObserver(this);
+ base::MessageLoopCurrent::Get()->SetAddQueueTimeToTasks(false);
+}
+
+void MessageLoopObserver::WillProcessTask(
+ const base::PendingTask& pending_task) {
+ will_run_task_callback_.Run(&pending_task);
+}
+
+void MessageLoopObserver::DidProcessTask(
+ const base::PendingTask& pending_task) {
+ did_run_task_callback_.Run(&pending_task);
+}
+
+} // namespace responsiveness
+} // namespace content
diff --git a/chromium/content/browser/scheduler/responsiveness/message_loop_observer.h b/chromium/content/browser/scheduler/responsiveness/message_loop_observer.h
new file mode 100644
index 00000000000..e6eed71be4e
--- /dev/null
+++ b/chromium/content/browser/scheduler/responsiveness/message_loop_observer.h
@@ -0,0 +1,47 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_SCHEDULER_RESPONSIVENESS_MESSAGE_LOOP_OBSERVER_H_
+#define CONTENT_BROWSER_SCHEDULER_RESPONSIVENESS_MESSAGE_LOOP_OBSERVER_H_
+
+#include "base/macros.h"
+#include "base/message_loop/message_loop_current.h"
+#include "content/common/content_export.h"
+
+namespace base {
+struct PendingTask;
+} // namespace base
+
+namespace content {
+namespace responsiveness {
+
+// This object is not thread safe. It must be constructed and destroyed on the
+// same thread. The callbacks will occur synchronously from WillProcessTask()
+// and DidProcessTask().
+class CONTENT_EXPORT MessageLoopObserver
+ : base::MessageLoopCurrent::TaskObserver {
+ public:
+ using TaskCallback =
+ base::RepeatingCallback<void(const base::PendingTask* task)>;
+
+ // The constructor will register the object as an observer of the current
+ // MessageLoop. The destructor will unregister the object.
+ MessageLoopObserver(TaskCallback will_run_task_callback,
+ TaskCallback did_run_task_callback);
+ ~MessageLoopObserver() override;
+
+ private:
+ void WillProcessTask(const base::PendingTask& pending_task) override;
+ void DidProcessTask(const base::PendingTask& pending_task) override;
+
+ TaskCallback will_run_task_callback_;
+ TaskCallback did_run_task_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessageLoopObserver);
+};
+
+} // namespace responsiveness
+} // namespace content
+
+#endif // CONTENT_BROWSER_SCHEDULER_RESPONSIVENESS_MESSAGE_LOOP_OBSERVER_H_
diff --git a/chromium/content/browser/scheduler/responsiveness/native_event_observer.cc b/chromium/content/browser/scheduler/responsiveness/native_event_observer.cc
new file mode 100644
index 00000000000..4225e9aa6df
--- /dev/null
+++ b/chromium/content/browser/scheduler/responsiveness/native_event_observer.cc
@@ -0,0 +1,157 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Needed for defined(OS_WIN)
+#include "build/build_config.h"
+
+// Windows headers must come first.
+#if defined(OS_WIN)
+#include <windows.h>
+
+#include <timeapi.h>
+#endif
+
+// Proceed with header includes in usual order.
+#include "content/browser/scheduler/responsiveness/native_event_observer.h"
+
+#include "ui/events/platform/platform_event_source.h"
+
+#if defined(USE_X11)
+#include "ui/events/platform/x11/x11_event_source.h" // nogncheck
+#elif defined(USE_OZONE)
+#include "ui/events/event.h"
+#endif
+
+#if defined(OS_LINUX)
+#include "ui/events/platform_event.h"
+#endif
+
+#if defined(OS_WIN)
+#include "base/message_loop/message_loop_current.h"
+#endif
+
+namespace content {
+namespace responsiveness {
+
+#if defined(OS_WIN) || (defined(OS_LINUX) && defined(USE_X11))
+
+namespace {
+
+// Clamps a TimeDelta to be within [0 seconds, 30 seconds].
+// Relies on the assumption that |delta| is >= 0 seconds.
+base::TimeDelta ClampDeltaFromExternalSource(const base::TimeDelta& delta) {
+ DCHECK_GE(delta, base::TimeDelta());
+
+ // Ignore pathologically long deltas. External source is probably having
+ // issues.
+ constexpr base::TimeDelta pathologically_long_duration =
+ base::TimeDelta::FromSeconds(30);
+ if (delta > pathologically_long_duration)
+ return base::TimeDelta();
+
+ return delta;
+}
+
+} // namespace
+
+#endif // defined(OS_WIN) || (defined(OS_LINUX) && defined(USE_X11))
+
+NativeEventObserver::NativeEventObserver(
+ WillRunEventCallback will_run_event_callback,
+ DidRunEventCallback did_run_event_callback)
+ : will_run_event_callback_(will_run_event_callback),
+ did_run_event_callback_(did_run_event_callback) {
+ RegisterObserver();
+}
+
+NativeEventObserver::~NativeEventObserver() {
+ DeregisterObserver();
+}
+
+#if defined(OS_LINUX)
+void NativeEventObserver::RegisterObserver() {
+ ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
+}
+void NativeEventObserver::DeregisterObserver() {
+ ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver(this);
+}
+
+void NativeEventObserver::WillProcessEvent(const ui::PlatformEvent& event) {
+ will_run_event_callback_.Run(&event);
+}
+
+void NativeEventObserver::DidProcessEvent(const ui::PlatformEvent& event) {
+#if defined(USE_OZONE)
+ did_run_event_callback_.Run(&event, event->time_stamp());
+#elif defined(USE_X11)
+ // X11 uses a uint32_t on the wire protocol. Xlib casts this to an unsigned
+ // long by prepending with 0s. We cast back to a uint32_t so that subtraction
+ // works properly when the timestamp overflows back to 0.
+ uint32_t event_server_time_ms =
+ static_cast<uint32_t>(ui::X11EventSource::GetInstance()->GetTimestamp());
+ uint32_t current_server_time_ms = static_cast<uint32_t>(
+ ui::X11EventSource::GetInstance()->GetCurrentServerTime());
+
+ // On X11, event times are in X11 Server time. To convert to base::TimeTicks,
+ // we perform a round-trip to the X11 Server, subtract the two times to get a
+ // TimeDelta, and then subtract that from base::TimeTicks::Now(). Since we're
+ // working with units of time from an external source, we clamp the TimeDelta
+ // to reasonable values.
+ uint32_t delta_ms = current_server_time_ms - event_server_time_ms;
+ base::TimeDelta delta = base::TimeDelta::FromMilliseconds(delta_ms);
+ base::TimeDelta sanitized = ClampDeltaFromExternalSource(delta);
+
+ did_run_event_callback_.Run(&event, base::TimeTicks::Now() - sanitized);
+#else
+#error
+#endif
+}
+#endif // defined(OS_LINUX)
+
+#if defined(OS_WIN)
+void NativeEventObserver::RegisterObserver() {
+ base::MessageLoopCurrentForUI::Get()->AddMessagePumpObserver(this);
+}
+void NativeEventObserver::DeregisterObserver() {
+ base::MessageLoopCurrentForUI::Get()->RemoveMessagePumpObserver(this);
+}
+void NativeEventObserver::WillDispatchMSG(const MSG& msg) {
+ will_run_event_callback_.Run(&msg);
+}
+void NativeEventObserver::DidDispatchMSG(const MSG& msg) {
+ // On Windows, MSG.time is in units of milliseconds since system started. It
+ // uses the timer exposed by ::GetTickCount().
+ // https://blogs.msdn.microsoft.com/oldnewthing/20140122-00/?p=2013
+ //
+ // This timer has ~16ms granularity. This is okay for us since we require
+ // ~100ms granularity.
+ // https://randomascii.wordpress.com/2013/05/09/timegettime-versus-gettickcount/
+ //
+ // To convert MSG.time to TimeTicks, we subtract MSG.time from
+ // ::GetTickCount() to create a TimeDelta, and then subtract that from
+ // TimeTicks::Now().
+ //
+ // We cast both values to DWORD [uint32], perform subtraction to get a uint32,
+ // and then shove that into a TimeDelta.
+ //
+ // Note: Both measurements of time can experience rollover. If one of them has
+ // rolled over but the other has not, then the result will be very large.
+ // ClampDeltaFromExternalSource takes care of this, in addition to any other
+ // odd timing issues that may come up [e.g. MSG.time time-traveling to give a
+ // larger value than ::timeGetTime() -- this has not been observed in practice
+ // but since we don't control the code in question, we trust nothing].
+ base::TimeDelta delta = base::TimeDelta::FromMilliseconds(
+ ::GetTickCount() - static_cast<DWORD>(msg.time));
+ base::TimeDelta sanitized = ClampDeltaFromExternalSource(delta);
+ did_run_event_callback_.Run(&msg, base::TimeTicks::Now() - sanitized);
+}
+#endif // defined(OS_WIN)
+
+#if defined(OS_ANDROID) || defined(OS_FUCHSIA)
+void NativeEventObserver::RegisterObserver() {}
+void NativeEventObserver::DeregisterObserver() {}
+#endif // defined(OS_ANDROID) || defined(OS_FUCHSIA)
+
+} // namespace responsiveness
+} // namespace content
diff --git a/chromium/content/browser/scheduler/responsiveness/native_event_observer.h b/chromium/content/browser/scheduler/responsiveness/native_event_observer.h
new file mode 100644
index 00000000000..5aaefd3daf5
--- /dev/null
+++ b/chromium/content/browser/scheduler/responsiveness/native_event_observer.h
@@ -0,0 +1,99 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_SCHEDULER_RESPONSIVENESS_NATIVE_EVENT_OBSERVER_H_
+#define CONTENT_BROWSER_SCHEDULER_RESPONSIVENESS_NATIVE_EVENT_OBSERVER_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "content/common/content_export.h"
+
+#if defined(OS_MACOSX)
+#include "content/public/browser/native_event_processor_observer_mac.h"
+#endif
+
+#if defined(OS_LINUX)
+#include "ui/events/platform/platform_event_observer.h"
+#endif
+
+#if defined(OS_WIN)
+#include "base/message_loop/message_pump_win.h"
+#endif
+
+namespace content {
+namespace responsiveness {
+
+// This class must only be used from the UI thread.
+//
+// This class hooks itself into the native event processor for the platform and
+// forwards will_run/did_run callbacks to Watcher. Native events are processed
+// at different layers for each platform, so the interface for this class is
+// necessarily messy.
+//
+// On macOS, the hook should be in -[BrowserCrApplication sendEvent:].
+// On Linux, the hook should be in ui::PlatformEventSource::DispatchEvent.
+// On Windows, the hook should be in MessagePumpForUI::ProcessMessageHelper.
+// On Android, the hook should be in <TBD>.
+class CONTENT_EXPORT NativeEventObserver
+#if defined(OS_MACOSX)
+ : public NativeEventProcessorObserver
+#elif defined(OS_LINUX)
+ : public ui::PlatformEventObserver
+#elif defined(OS_WIN)
+ : public base::MessagePumpForUI::Observer
+#endif
+{
+ public:
+ using WillRunEventCallback =
+ base::RepeatingCallback<void(const void* opaque_identifier)>;
+
+ // |creation_time| refers to the time at which the native event was created.
+ using DidRunEventCallback =
+ base::RepeatingCallback<void(const void* opaque_identifier,
+ base::TimeTicks creation_time)>;
+
+ // The constructor will register the object as an observer of the native event
+ // processor. The destructor will unregister the object.
+ NativeEventObserver(WillRunEventCallback will_run_event_callback,
+ DidRunEventCallback did_run_event_callback);
+
+#if defined(OS_LINUX)
+ ~NativeEventObserver() override;
+#else
+ virtual ~NativeEventObserver();
+#endif
+
+ protected:
+#if defined(OS_MACOSX)
+ // NativeEventProcessorObserver overrides:
+ // Exposed for tests.
+ void WillRunNativeEvent(const void* opaque_identifier) override;
+ void DidRunNativeEvent(const void* opaque_identifier,
+ base::TimeTicks creation_time) override;
+#elif defined(OS_LINUX)
+ // PlatformEventObserver overrides:
+ // Exposed for tests.
+ void WillProcessEvent(const ui::PlatformEvent& event) override;
+ void DidProcessEvent(const ui::PlatformEvent& event) override;
+#elif defined(OS_WIN)
+ // base::MessagePumpForUI::Observer overrides:
+ void WillDispatchMSG(const MSG& msg) override;
+ void DidDispatchMSG(const MSG& msg) override;
+#endif
+
+ private:
+ void RegisterObserver();
+ void DeregisterObserver();
+
+ WillRunEventCallback will_run_event_callback_;
+ DidRunEventCallback did_run_event_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeEventObserver);
+};
+
+} // namespace responsiveness
+} // namespace content
+
+#endif // CONTENT_BROWSER_SCHEDULER_RESPONSIVENESS_NATIVE_EVENT_OBSERVER_H_
diff --git a/chromium/content/browser/scheduler/responsiveness/native_event_observer_browsertest.mm b/chromium/content/browser/scheduler/responsiveness/native_event_observer_browsertest.mm
new file mode 100644
index 00000000000..e62074265b4
--- /dev/null
+++ b/chromium/content/browser/scheduler/responsiveness/native_event_observer_browsertest.mm
@@ -0,0 +1,72 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/scheduler/responsiveness/native_event_observer.h"
+
+#include "base/bind_helpers.h"
+#include "content/public/test/content_browser_test.h"
+#include "ui/events/test/cocoa_test_event_utils.h"
+
+#import <Carbon/Carbon.h>
+
+namespace content {
+namespace responsiveness {
+
+namespace {
+
+class FakeNativeEventObserver : public NativeEventObserver {
+ public:
+ FakeNativeEventObserver()
+ : NativeEventObserver(base::DoNothing(), base::DoNothing()) {}
+ ~FakeNativeEventObserver() override = default;
+
+ void WillRunNativeEvent(const void* opaque_identifier) override {
+ ASSERT_FALSE(will_run_id_);
+ will_run_id_ = opaque_identifier;
+ }
+ void DidRunNativeEvent(const void* opaque_identifier,
+ base::TimeTicks creation_time) override {
+ ASSERT_FALSE(did_run_id_);
+ did_run_id_ = opaque_identifier;
+ creation_time_ = creation_time;
+ }
+
+ const void* will_run_id() { return will_run_id_; }
+ const void* did_run_id() { return did_run_id_; }
+ base::TimeTicks creation_time() { return creation_time_; }
+
+ private:
+ const void* will_run_id_ = nullptr;
+ const void* did_run_id_ = nullptr;
+ base::TimeTicks creation_time_;
+};
+
+} // namespace
+
+class ResponsivenessNativeEventObserverBrowserTest : public ContentBrowserTest {
+};
+
+IN_PROC_BROWSER_TEST_F(ResponsivenessNativeEventObserverBrowserTest,
+ EventForwarding) {
+ FakeNativeEventObserver observer;
+
+ EXPECT_FALSE(observer.will_run_id());
+ EXPECT_FALSE(observer.did_run_id());
+ base::TimeTicks time_at_creation = base::TimeTicks::Now();
+ NSEvent* event = cocoa_test_event_utils::KeyEventWithKeyCode(kVK_Return, '\r',
+ NSKeyDown, 0);
+ [NSApp sendEvent:event];
+
+ EXPECT_EQ(observer.will_run_id(), event);
+ EXPECT_EQ(observer.did_run_id(), event);
+
+ // time_at_creation should be really similar to creation_time. As a sanity
+ // check, make sure they're within a second of each other.
+ EXPECT_LT(
+ fabs((observer.creation_time() - time_at_creation).InMilliseconds()),
+ 1000);
+}
+
+} // namespace responsiveness
+} // namespace content
diff --git a/chromium/content/browser/scheduler/responsiveness/native_event_observer_browsertest_win.cc b/chromium/content/browser/scheduler/responsiveness/native_event_observer_browsertest_win.cc
new file mode 100644
index 00000000000..426ec6ff5ee
--- /dev/null
+++ b/chromium/content/browser/scheduler/responsiveness/native_event_observer_browsertest_win.cc
@@ -0,0 +1,76 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/scheduler/responsiveness/native_event_observer.h"
+
+#include "base/bind_helpers.h"
+#include "base/win/message_window.h"
+#include "content/public/test/content_browser_test.h"
+
+namespace content {
+namespace responsiveness {
+
+namespace {
+
+bool HandleMessage(UINT message,
+ WPARAM wparam,
+ LPARAM lparam,
+ LRESULT* result) {
+ return false;
+}
+
+} // namespace
+
+class ResponsivenessNativeEventObserverBrowserTest : public ContentBrowserTest {
+ public:
+ void WillRunEvent(const void* opaque_id) {
+ ASSERT_FALSE(will_run_id_);
+ will_run_id_ = opaque_id;
+ }
+ void DidRunEvent(const void* opaque_id, base::TimeTicks creation_time) {
+ ASSERT_FALSE(did_run_id_);
+ did_run_id_ = opaque_id;
+ creation_time_ = creation_time;
+ std::move(quit_closure_).Run();
+ }
+
+ protected:
+ const void* will_run_id_ = nullptr;
+ const void* did_run_id_ = nullptr;
+ base::TimeTicks creation_time_;
+ base::OnceClosure quit_closure_;
+};
+
+IN_PROC_BROWSER_TEST_F(ResponsivenessNativeEventObserverBrowserTest,
+ EventForwarding) {
+ base::win::MessageWindow window;
+ EXPECT_TRUE(window.Create(base::BindRepeating(&HandleMessage)));
+
+ NativeEventObserver observer(
+ base::BindRepeating(
+ &ResponsivenessNativeEventObserverBrowserTest::WillRunEvent,
+ base::Unretained(this)),
+ base::BindRepeating(
+ &ResponsivenessNativeEventObserverBrowserTest::DidRunEvent,
+ base::Unretained(this)));
+ base::TimeTicks time_at_creation = base::TimeTicks::Now();
+
+ EXPECT_FALSE(will_run_id_);
+ EXPECT_FALSE(did_run_id_);
+
+ EXPECT_NE(PostMessage(window.hwnd(), WM_USER, 100, 0), 0);
+ base::RunLoop run_loop;
+ quit_closure_ = run_loop.QuitClosure();
+ run_loop.Run();
+
+ EXPECT_EQ(will_run_id_, did_run_id_);
+ EXPECT_NE(will_run_id_, nullptr);
+
+ // time_at_creation should be really similar to creation_time_. As a sanity
+ // check, make sure they're within a second of each other.
+ EXPECT_LT(fabs((creation_time_ - time_at_creation).InMilliseconds()), 1000);
+}
+
+} // namespace responsiveness
+} // namespace content
diff --git a/chromium/content/browser/scheduler/responsiveness/native_event_observer_mac.mm b/chromium/content/browser/scheduler/responsiveness/native_event_observer_mac.mm
new file mode 100644
index 00000000000..a074d87741d
--- /dev/null
+++ b/chromium/content/browser/scheduler/responsiveness/native_event_observer_mac.mm
@@ -0,0 +1,36 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/scheduler/responsiveness/native_event_observer.h"
+
+#import <AppKit/AppKit.h>
+
+#import "content/public/browser/native_event_processor_mac.h"
+
+namespace content {
+namespace responsiveness {
+
+void NativeEventObserver::RegisterObserver() {
+ DCHECK([NSApp conformsToProtocol:@protocol(NativeEventProcessor)]);
+ id<NativeEventProcessor> processor =
+ static_cast<id<NativeEventProcessor>>(NSApp);
+ [processor addNativeEventProcessorObserver:this];
+}
+void NativeEventObserver::DeregisterObserver() {
+ DCHECK([NSApp conformsToProtocol:@protocol(NativeEventProcessor)]);
+ id<NativeEventProcessor> processor =
+ static_cast<id<NativeEventProcessor>>(NSApp);
+ [processor removeNativeEventProcessorObserver:this];
+}
+
+void NativeEventObserver::WillRunNativeEvent(const void* opaque_identifier) {
+ will_run_event_callback_.Run(opaque_identifier);
+}
+void NativeEventObserver::DidRunNativeEvent(const void* opaque_identifier,
+ base::TimeTicks creation_time) {
+ did_run_event_callback_.Run(opaque_identifier, creation_time);
+}
+
+} // namespace responsiveness
+} // namespace content
diff --git a/chromium/content/browser/scheduler/responsiveness/watcher.cc b/chromium/content/browser/scheduler/responsiveness/watcher.cc
new file mode 100644
index 00000000000..2e61f5db182
--- /dev/null
+++ b/chromium/content/browser/scheduler/responsiveness/watcher.cc
@@ -0,0 +1,257 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/scheduler/responsiveness/watcher.h"
+
+#include "base/pending_task.h"
+#include "content/browser/scheduler/responsiveness/calculator.h"
+#include "content/browser/scheduler/responsiveness/message_loop_observer.h"
+#include "content/browser/scheduler/responsiveness/native_event_observer.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+namespace responsiveness {
+
+Watcher::Metadata::Metadata(const void* identifier) : identifier(identifier) {}
+
+Watcher::Watcher() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+}
+
+void Watcher::SetUp() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ // Destroy() has the corresponding call to Release().
+ // We need this additional reference to make sure the object stays alive
+ // through hops to the IO thread, which are necessary both during construction
+ // and destruction.
+ AddRef();
+
+ calculator_ = CreateCalculator();
+ native_event_observer_ui_ = CreateNativeEventObserver();
+
+ RegisterMessageLoopObserverUI();
+
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&Watcher::SetUpOnIOThread, base::Unretained(this),
+ calculator_.get()));
+}
+
+void Watcher::Destroy() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ DCHECK(!destroy_was_called_);
+ destroy_was_called_ = true;
+
+ message_loop_observer_ui_.reset();
+ native_event_observer_ui_.reset();
+
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&Watcher::TearDownOnIOThread, base::Unretained(this)));
+}
+
+std::unique_ptr<Calculator> Watcher::CreateCalculator() {
+ return std::make_unique<Calculator>();
+}
+
+std::unique_ptr<NativeEventObserver> Watcher::CreateNativeEventObserver() {
+ NativeEventObserver::WillRunEventCallback will_run_callback =
+ base::BindRepeating(&Watcher::WillRunEventOnUIThread,
+ base::Unretained(this));
+ NativeEventObserver::DidRunEventCallback did_run_callback =
+ base::BindRepeating(&Watcher::DidRunEventOnUIThread,
+ base::Unretained(this));
+ return std::make_unique<NativeEventObserver>(std::move(will_run_callback),
+ std::move(did_run_callback));
+}
+
+Watcher::~Watcher() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ DCHECK(destroy_was_called_);
+}
+
+void Watcher::RegisterMessageLoopObserverUI() {
+ // We must use base::Unretained(this) to prevent ownership cycle.
+ MessageLoopObserver::TaskCallback will_run_callback = base::BindRepeating(
+ &Watcher::WillRunTaskOnUIThread, base::Unretained(this));
+ MessageLoopObserver::TaskCallback did_run_callback = base::BindRepeating(
+ &Watcher::DidRunTaskOnUIThread, base::Unretained(this));
+ message_loop_observer_ui_.reset(new MessageLoopObserver(
+ std::move(will_run_callback), std::move(did_run_callback)));
+}
+
+void Watcher::RegisterMessageLoopObserverIO() {
+ // We must use base::Unretained(this) to prevent ownership cycle.
+ MessageLoopObserver::TaskCallback will_run_callback = base::BindRepeating(
+ &Watcher::WillRunTaskOnIOThread, base::Unretained(this));
+ MessageLoopObserver::TaskCallback did_run_callback = base::BindRepeating(
+ &Watcher::DidRunTaskOnIOThread, base::Unretained(this));
+ message_loop_observer_io_.reset(new MessageLoopObserver(
+ std::move(will_run_callback), std::move(did_run_callback)));
+}
+
+void Watcher::SetUpOnIOThread(Calculator* calculator) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ RegisterMessageLoopObserverIO();
+ calculator_io_ = calculator;
+}
+
+void Watcher::TearDownOnIOThread() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ message_loop_observer_io_.reset();
+
+ calculator_io_ = nullptr;
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&Watcher::TearDownOnUIThread, base::Unretained(this)));
+}
+
+void Watcher::TearDownOnUIThread() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ // Corresponding call to AddRef() is in the constructor.
+ Release();
+}
+
+void Watcher::WillRunTaskOnUIThread(const base::PendingTask* task) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ WillRunTask(task, &currently_running_metadata_ui_);
+}
+
+void Watcher::DidRunTaskOnUIThread(const base::PendingTask* task) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ // It's safe to use base::Unretained since the callback will be synchronously
+ // invoked.
+ TaskOrEventFinishedCallback callback =
+ base::BindOnce(&Calculator::TaskOrEventFinishedOnUIThread,
+ base::Unretained(calculator_.get()));
+
+ DidRunTask(task, &currently_running_metadata_ui_,
+ &mismatched_task_identifiers_ui_, std::move(callback));
+}
+
+void Watcher::WillRunTaskOnIOThread(const base::PendingTask* task) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ WillRunTask(task, &currently_running_metadata_io_);
+}
+
+void Watcher::DidRunTaskOnIOThread(const base::PendingTask* task) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ // It's safe to use base::Unretained since the callback will be synchronously
+ // invoked.
+ TaskOrEventFinishedCallback callback =
+ base::BindOnce(&Calculator::TaskOrEventFinishedOnIOThread,
+ base::Unretained(calculator_io_));
+ DidRunTask(task, &currently_running_metadata_io_,
+ &mismatched_task_identifiers_io_, std::move(callback));
+}
+
+void Watcher::WillRunTask(const base::PendingTask* task,
+ std::stack<Metadata>* currently_running_metadata) {
+ // Reentrancy should be rare.
+ if (UNLIKELY(!currently_running_metadata->empty())) {
+ currently_running_metadata->top().caused_reentrancy = true;
+ }
+
+ currently_running_metadata->emplace(task);
+
+ // For delayed tasks, record the time right before the task is run.
+ if (!task->delayed_run_time.is_null()) {
+ currently_running_metadata->top().delayed_task_start =
+ base::TimeTicks::Now();
+ }
+}
+
+void Watcher::DidRunTask(const base::PendingTask* task,
+ std::stack<Metadata>* currently_running_metadata,
+ int* mismatched_task_identifiers,
+ TaskOrEventFinishedCallback callback) {
+ // Calls to DidRunTask should always be paired with WillRunTask. The only time
+ // the identifier should differ is when Watcher is first constructed. The
+ // TaskRunner Observers may be added while a task is being run, which means
+ // that there was no corresponding WillRunTask.
+ if (UNLIKELY(currently_running_metadata->empty() ||
+ (task != currently_running_metadata->top().identifier))) {
+ *mismatched_task_identifiers += 1;
+ DCHECK_LE(*mismatched_task_identifiers, 1);
+ return;
+ }
+
+ bool caused_reentrancy = currently_running_metadata->top().caused_reentrancy;
+ base::TimeTicks delayed_task_start =
+ currently_running_metadata->top().delayed_task_start;
+ currently_running_metadata->pop();
+
+ // Ignore tasks that caused reentrancy, since their execution latency will
+ // be very large, but Chrome was still responsive.
+ if (UNLIKELY(caused_reentrancy))
+ return;
+
+ // For delayed tasks, measure the duration of the task itself, rather than the
+ // duration from schedule time to finish time.
+ base::TimeTicks schedule_time;
+ if (delayed_task_start.is_null()) {
+ // Tasks which were posted before the MessageLoopObserver was created will
+ // not have a queue_time, and should be ignored. This doesn't affect delayed
+ // tasks.
+ if (UNLIKELY(!task->queue_time))
+ return;
+
+ schedule_time = task->queue_time.value();
+ } else {
+ schedule_time = delayed_task_start;
+ }
+
+ std::move(callback).Run(schedule_time, base::TimeTicks::Now());
+}
+
+void Watcher::WillRunEventOnUIThread(const void* opaque_identifier) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ // Reentrancy should be rare.
+ if (UNLIKELY(!currently_running_metadata_ui_.empty())) {
+ currently_running_metadata_ui_.top().caused_reentrancy = true;
+ }
+
+ currently_running_metadata_ui_.emplace(opaque_identifier);
+}
+
+void Watcher::DidRunEventOnUIThread(const void* opaque_identifier,
+ base::TimeTicks creation_time) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ // Calls to DidRunEventOnUIThread should always be paired with
+ // WillRunEventOnUIThread. The only time the identifier should differ is when
+ // Watcher is first constructed. The TaskRunner Observers may be added while a
+ // task is being run, which means that there was no corresponding WillRunTask.
+ if (UNLIKELY(currently_running_metadata_ui_.empty() ||
+ (opaque_identifier !=
+ currently_running_metadata_ui_.top().identifier))) {
+ mismatched_event_identifiers_ui_ += 1;
+ DCHECK_LE(mismatched_event_identifiers_ui_, 1);
+ return;
+ }
+
+ bool caused_reentrancy =
+ currently_running_metadata_ui_.top().caused_reentrancy;
+ currently_running_metadata_ui_.pop();
+
+ // Ignore events that caused reentrancy, since their execution latency will
+ // be very large, but Chrome was still responsive.
+ if (UNLIKELY(caused_reentrancy))
+ return;
+
+ calculator_->TaskOrEventFinishedOnUIThread(creation_time,
+ base::TimeTicks::Now());
+}
+
+} // namespace responsiveness
+} // namespace content
diff --git a/chromium/content/browser/scheduler/responsiveness/watcher.h b/chromium/content/browser/scheduler/responsiveness/watcher.h
new file mode 100644
index 00000000000..0e6d3edfce7
--- /dev/null
+++ b/chromium/content/browser/scheduler/responsiveness/watcher.h
@@ -0,0 +1,156 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_SCHEDULER_RESPONSIVENESS_WATCHER_H_
+#define CONTENT_BROWSER_SCHEDULER_RESPONSIVENESS_WATCHER_H_
+
+#include <memory>
+#include <stack>
+
+#include "base/callback.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "content/common/content_export.h"
+
+namespace base {
+struct PendingTask;
+} // namespace base
+
+namespace content {
+namespace responsiveness {
+
+class Calculator;
+class MessageLoopObserver;
+class NativeEventObserver;
+
+// This class watches events and tasks processed on the UI and IO threads of the
+// browser process. It forwards stats on execution latency to Calculator, which
+// emits UMA metrics.
+//
+// This class must only be constructed/destroyed on the UI thread. It has some
+// private members that are affine to the IO thread. It takes care of deleting
+// them appropriately.
+//
+// TODO(erikchen): Once the browser scheduler is implemented, this entire class
+// should become simpler, as either BrowserUIThreadScheduler or
+// BrowserIOThreadScheduler should implement much of the same functionality.
+class CONTENT_EXPORT Watcher : public base::RefCounted<Watcher> {
+ public:
+ Watcher();
+
+ // Must be called immediately after the constructor. This cannot be called
+ // from the constructor because subclasses [for tests] need to be able to
+ // override functions.
+ void SetUp();
+
+ // Destruction requires a thread-hop to the IO thread, so cannot be completed
+ // synchronously. Owners of this class should call this method, and then
+ // release their reference.
+ void Destroy();
+
+ protected:
+ // Exposed for tests.
+ virtual std::unique_ptr<Calculator> CreateCalculator();
+ virtual std::unique_ptr<NativeEventObserver> CreateNativeEventObserver();
+ virtual ~Watcher();
+ virtual void RegisterMessageLoopObserverUI();
+ virtual void RegisterMessageLoopObserverIO();
+
+ private:
+ friend class base::RefCounted<Watcher>;
+ FRIEND_TEST_ALL_PREFIXES(ResponsivenessWatcherTest, TaskForwarding);
+ FRIEND_TEST_ALL_PREFIXES(ResponsivenessWatcherTest, TaskNesting);
+
+ // Metadata for currently running tasks and events is needed to track whether
+ // or not they caused reentrancy.
+ struct Metadata {
+ explicit Metadata(const void* identifier);
+
+ // An opaque identifier for the task or event.
+ const void* identifier = nullptr;
+
+ // Whether the task or event has caused reentrancy.
+ bool caused_reentrancy = false;
+
+ // For delayed tasks, the time at which the event is scheduled to run
+ // is only loosely coupled to the time that the task actually runs. The
+ // difference between these is not interesting for computing responsiveness.
+ // Instead of measuring the duration between |queue_time| and |finish_time|,
+ // we measure the duration of execution itself.
+ base::TimeTicks delayed_task_start;
+ };
+
+ void SetUpOnIOThread(Calculator*);
+ void TearDownOnIOThread();
+ void TearDownOnUIThread();
+
+ // These methods are called by the MessageLoopObserver of the UI thread to
+ // allow Watcher to collect metadata about the tasks being run.
+ void WillRunTaskOnUIThread(const base::PendingTask* task);
+ void DidRunTaskOnUIThread(const base::PendingTask* task);
+
+ // These methods are called by the MessageLoopObserver of the IO thread to
+ // allow Watcher to collect metadata about the tasks being run.
+ void WillRunTaskOnIOThread(const base::PendingTask* task);
+ void DidRunTaskOnIOThread(const base::PendingTask* task);
+
+ // Common implementations for the thread-specific methods.
+ void WillRunTask(const base::PendingTask* task,
+ std::stack<Metadata>* currently_running_metadata);
+
+ // |callback| will either be synchronously invoked, or else never invoked.
+ using TaskOrEventFinishedCallback =
+ base::OnceCallback<void(base::TimeTicks, base::TimeTicks)>;
+ void DidRunTask(const base::PendingTask* task,
+ std::stack<Metadata>* currently_running_metadata,
+ int* mismatched_task_identifiers,
+ TaskOrEventFinishedCallback callback);
+
+ // These methods are called by the NativeEventObserver of the UI thread to
+ // allow Watcher to collect metadata about the events being run.
+ void WillRunEventOnUIThread(const void* opaque_identifier);
+ void DidRunEventOnUIThread(const void* opaque_identifier,
+ base::TimeTicks creation_time);
+
+ // The following members are all affine to the UI thread.
+ std::unique_ptr<Calculator> calculator_;
+ std::unique_ptr<MessageLoopObserver> message_loop_observer_ui_;
+ std::unique_ptr<NativeEventObserver> native_event_observer_ui_;
+
+ // Metadata for currently running tasks and events on the UI thread.
+ std::stack<Metadata> currently_running_metadata_ui_;
+
+ // Task identifiers should only be mismatched once, since the Watcher may
+ // register itself during a Task execution, and thus doesn't capture the
+ // initial WillRunTask() callback.
+ int mismatched_task_identifiers_ui_ = 0;
+
+ // Event identifiers should be mismatched at most once, since the Watcher may
+ // register itself during an event execution, and thus doesn't capture the
+ // initial WillRunEventOnUIThread callback.
+ int mismatched_event_identifiers_ui_ = 0;
+
+ // The following members are all affine to the IO thread.
+ std::stack<Metadata> currently_running_metadata_io_;
+ int mismatched_task_identifiers_io_ = 0;
+ std::unique_ptr<MessageLoopObserver> message_loop_observer_io_;
+
+ // The implementation of this class guarantees that |calculator_io_| will be
+ // non-nullptr and point to a valid object any time it is used on the IO
+ // thread. To ensure this, the first task that this class posts onto the IO
+ // thread sets |calculator_io_|. On destruction, this class first tears down
+ // all consumers of |calculator_io_|, and then clears the member and destroys
+ // Calculator.
+ Calculator* calculator_io_ = nullptr;
+
+ bool destroy_was_called_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(Watcher);
+};
+
+} // namespace responsiveness
+} // namespace content
+
+#endif // CONTENT_BROWSER_SCHEDULER_RESPONSIVENESS_WATCHER_H_
diff --git a/chromium/content/browser/scheduler/responsiveness/watcher_unittest.cc b/chromium/content/browser/scheduler/responsiveness/watcher_unittest.cc
new file mode 100644
index 00000000000..c80be85babb
--- /dev/null
+++ b/chromium/content/browser/scheduler/responsiveness/watcher_unittest.cc
@@ -0,0 +1,236 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/scheduler/responsiveness/watcher.h"
+
+#include "base/location.h"
+#include "base/pending_task.h"
+#include "base/run_loop.h"
+#include "base/synchronization/lock.h"
+#include "build/build_config.h"
+#include "content/browser/scheduler/responsiveness/calculator.h"
+#include "content/browser/scheduler/responsiveness/native_event_observer.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace responsiveness {
+
+namespace {
+
+class FakeCalculator : public Calculator {
+ public:
+ void TaskOrEventFinishedOnUIThread(base::TimeTicks schedule_time,
+ base::TimeTicks finish_time) override {
+ queue_times_ui_.push_back(schedule_time);
+ }
+
+ void TaskOrEventFinishedOnIOThread(base::TimeTicks schedule_time,
+ base::TimeTicks finish_time) override {
+ base::AutoLock l(io_thread_lock_);
+ queue_times_io_.push_back(schedule_time);
+ }
+
+ int NumTasksOnUIThread() { return static_cast<int>(queue_times_ui_.size()); }
+ std::vector<base::TimeTicks>& QueueTimesUIThread() { return queue_times_ui_; }
+ int NumTasksOnIOThread() {
+ base::AutoLock l(io_thread_lock_);
+ return static_cast<int>(queue_times_io_.size());
+ }
+ std::vector<base::TimeTicks>& QueueTimesIOThread() {
+ base::AutoLock l(io_thread_lock_);
+ return queue_times_io_;
+ }
+
+ private:
+ std::vector<base::TimeTicks> queue_times_ui_;
+ base::Lock io_thread_lock_;
+ std::vector<base::TimeTicks> queue_times_io_;
+};
+
+class FakeWatcher : public Watcher {
+ public:
+ std::unique_ptr<Calculator> CreateCalculator() override {
+ std::unique_ptr<FakeCalculator> calculator =
+ std::make_unique<FakeCalculator>();
+ calculator_ = calculator.get();
+ return calculator;
+ }
+
+ std::unique_ptr<NativeEventObserver> CreateNativeEventObserver() override {
+ return nullptr;
+ }
+
+ void RegisterMessageLoopObserverUI() override {
+ if (register_message_loop_observer_)
+ Watcher::RegisterMessageLoopObserverUI();
+ }
+ void RegisterMessageLoopObserverIO() override {
+ if (register_message_loop_observer_)
+ Watcher::RegisterMessageLoopObserverIO();
+ }
+
+ FakeWatcher(bool register_message_loop_observer)
+ : Watcher(),
+ register_message_loop_observer_(register_message_loop_observer) {}
+
+ int NumTasksOnUIThread() { return calculator_->NumTasksOnUIThread(); }
+ std::vector<base::TimeTicks>& QueueTimesUIThread() {
+ return calculator_->QueueTimesUIThread();
+ }
+ std::vector<base::TimeTicks>& QueueTimesIOThread() {
+ return calculator_->QueueTimesIOThread();
+ }
+ int NumTasksOnIOThread() { return calculator_->NumTasksOnIOThread(); }
+
+ private:
+ ~FakeWatcher() override{};
+ FakeCalculator* calculator_ = nullptr;
+ bool register_message_loop_observer_ = false;
+};
+
+} // namespace
+
+class ResponsivenessWatcherTest : public testing::Test {
+ public:
+ void SetUp() override {
+ // Watcher's constructor posts a task to IO thread, which in the unit test
+ // is also this thread. Regardless, we need to let those tasks finish.
+ watcher_ = scoped_refptr<FakeWatcher>(
+ new FakeWatcher(/*register_message_loop_observer=*/false));
+ watcher_->SetUp();
+ test_browser_thread_bundle_.RunUntilIdle();
+ }
+
+ void TearDown() override {
+ watcher_->Destroy();
+ watcher_.reset();
+ }
+
+ protected:
+ // This member sets up BrowserThread::IO and BrowserThread::UI. It must be the
+ // first member, as other members may depend on these abstractions.
+ content::TestBrowserThreadBundle test_browser_thread_bundle_;
+
+ scoped_refptr<FakeWatcher> watcher_;
+};
+
+// Test that tasks are forwarded to calculator.
+TEST_F(ResponsivenessWatcherTest, TaskForwarding) {
+ for (int i = 0; i < 3; ++i) {
+ base::PendingTask task(FROM_HERE, base::OnceClosure());
+ task.queue_time = base::TimeTicks::Now();
+ watcher_->WillRunTaskOnUIThread(&task);
+ watcher_->DidRunTaskOnUIThread(&task);
+ }
+ EXPECT_EQ(3, watcher_->NumTasksOnUIThread());
+ EXPECT_EQ(0, watcher_->NumTasksOnIOThread());
+
+ for (int i = 0; i < 4; ++i) {
+ base::PendingTask task(FROM_HERE, base::OnceClosure());
+ task.queue_time = base::TimeTicks::Now();
+ watcher_->WillRunTaskOnIOThread(&task);
+ watcher_->DidRunTaskOnIOThread(&task);
+ }
+ EXPECT_EQ(3, watcher_->NumTasksOnUIThread());
+ EXPECT_EQ(4, watcher_->NumTasksOnIOThread());
+}
+
+// Test that nested tasks are not forwarded to the calculator.
+TEST_F(ResponsivenessWatcherTest, TaskNesting) {
+ base::TimeTicks now = base::TimeTicks::Now();
+
+ base::PendingTask task1(FROM_HERE, base::OnceClosure());
+ task1.queue_time = now + base::TimeDelta::FromMilliseconds(1);
+ base::PendingTask task2(FROM_HERE, base::OnceClosure());
+ task2.queue_time = now + base::TimeDelta::FromMilliseconds(2);
+ base::PendingTask task3(FROM_HERE, base::OnceClosure());
+ task3.queue_time = now + base::TimeDelta::FromMilliseconds(3);
+
+ watcher_->WillRunTaskOnUIThread(&task1);
+ watcher_->WillRunTaskOnUIThread(&task2);
+ watcher_->WillRunTaskOnUIThread(&task3);
+ watcher_->DidRunTaskOnUIThread(&task3);
+ watcher_->DidRunTaskOnUIThread(&task2);
+ watcher_->DidRunTaskOnUIThread(&task1);
+
+ ASSERT_EQ(1, watcher_->NumTasksOnUIThread());
+
+ // The innermost task should be the one that is passed through, as it didn't
+ // cause reentrancy.
+ EXPECT_EQ(now + base::TimeDelta::FromMilliseconds(3),
+ watcher_->QueueTimesUIThread()[0]);
+ EXPECT_EQ(0, watcher_->NumTasksOnIOThread());
+}
+
+class ResponsivenessWatcherRealIOThreadTest : public testing::Test {
+ public:
+ ResponsivenessWatcherRealIOThreadTest()
+ : test_browser_thread_bundle_(
+ content::TestBrowserThreadBundle::REAL_IO_THREAD) {}
+
+ void SetUp() override {
+ // Watcher's constructor posts a task to IO thread. We need to let those
+ // tasks finish.
+ watcher_ = scoped_refptr<FakeWatcher>(
+ new FakeWatcher(/*register_message_loop_observer=*/true));
+ watcher_->SetUp();
+ test_browser_thread_bundle_.RunIOThreadUntilIdle();
+ }
+
+ void TearDown() override {
+ watcher_->Destroy();
+ watcher_.reset();
+
+ // Destroy a task onto the IO thread, which posts back to the UI thread
+ // to complete destruction.
+ test_browser_thread_bundle_.RunIOThreadUntilIdle();
+ test_browser_thread_bundle_.RunUntilIdle();
+ }
+
+ protected:
+ // This member sets up BrowserThread::IO and BrowserThread::UI. It must be the
+ // first member, as other members may depend on these abstractions.
+ content::TestBrowserThreadBundle test_browser_thread_bundle_;
+
+ scoped_refptr<FakeWatcher> watcher_;
+};
+
+// Flaky on Linux TSAN. https://crbug.com/876561
+#if defined(OS_LINUX) && defined(THREAD_SANITIZER)
+#define MAYBE_MessageLoopObserver DISABLED_MessageLoopObserver
+#else
+#define MAYBE_MessageLoopObserver MessageLoopObserver
+#endif
+TEST_F(ResponsivenessWatcherRealIOThreadTest, MAYBE_MessageLoopObserver) {
+ // Post a do-nothing task onto the UI thread.
+ content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+ base::BindOnce([]() {}));
+
+ // Post a do-nothing task onto the IO thread.
+ content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
+ base::BindOnce([]() {}));
+
+ // Post a task onto the IO thread that hops back to the UI thread. This
+ // guarantees that both of the do-nothing tasks have already been processed.
+ base::RunLoop run_loop;
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO, FROM_HERE,
+ base::BindOnce(
+ [](base::OnceClosure quit_closure) {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE, std::move(quit_closure));
+ },
+ run_loop.QuitClosure()));
+ run_loop.Run();
+
+ ASSERT_GE(watcher_->NumTasksOnUIThread(), 1);
+ EXPECT_FALSE(watcher_->QueueTimesUIThread()[0].is_null());
+ ASSERT_GE(watcher_->NumTasksOnIOThread(), 1);
+ EXPECT_FALSE(watcher_->QueueTimesIOThread()[0].is_null());
+}
+
+} // namespace responsiveness
+} // namespace content
diff --git a/chromium/content/browser/security_exploit_browsertest.cc b/chromium/content/browser/security_exploit_browsertest.cc
index e3b04edb5a3..e9cb49ebc81 100644
--- a/chromium/content/browser/security_exploit_browsertest.cc
+++ b/chromium/content/browser/security_exploit_browsertest.cc
@@ -6,6 +6,7 @@
#include "base/command_line.h"
#include "base/containers/hash_tables.h"
+#include "base/feature_list.h"
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
@@ -14,7 +15,6 @@
#include "content/browser/dom_storage/session_storage_namespace_impl.h"
#include "content/browser/frame_host/navigator.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
-#include "content/browser/loader/resource_message_filter.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/renderer_host/render_view_host_factory.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
@@ -50,6 +50,7 @@
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/url_request/url_request_slow_download_job.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/network_switches.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/mojom/url_loader.mojom.h"
@@ -182,20 +183,6 @@ class SecurityExploitBrowserTest : public ContentBrowserTest {
base::BindOnce(&net::URLRequestSlowDownloadJob::AddUrlHandler));
}
- static void CreateLoaderAndStartOnIOThread(
- scoped_refptr<ResourceMessageFilter> filter,
- network::mojom::URLLoaderRequest request,
- int route_id,
- int request_id,
- const network::ResourceRequest& resource_request,
- network::mojom::URLLoaderClientPtrInfo client) {
- filter->CreateLoaderAndStart(
- std::move(request), route_id, request_id,
- network::mojom::kURLLoadOptionNone, resource_request,
- network::mojom::URLLoaderClientPtr(std::move(client)),
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
- }
-
static void CreateLoaderAndStart(
RenderProcessHost* process,
int route_id,
@@ -215,13 +202,13 @@ class SecurityExploitBrowserTest : public ContentBrowserTest {
int request_id,
const network::ResourceRequest& resource_request,
network::mojom::URLLoaderClientPtrInfo client) {
- RenderProcessHostImpl* impl = static_cast<RenderProcessHostImpl*>(process);
- auto filter = impl->resource_message_filter_;
-
- process->GetChannel()->ipc_task_runner()->PostTask(
- FROM_HERE, base::BindOnce(CreateLoaderAndStartOnIOThread, filter,
- std::move(request), route_id, request_id,
- resource_request, std::move(client)));
+ network::mojom::URLLoaderFactoryPtr factory;
+ process->CreateURLLoaderFactory(mojo::MakeRequest(&factory));
+ factory->CreateLoaderAndStart(
+ std::move(request), route_id, request_id,
+ network::mojom::kURLLoadOptionNone, resource_request,
+ network::mojom::URLLoaderClientPtr(std::move(client)),
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
}
void TryCreateDuplicateRequestIds(Shell* shell, bool block_loaders) {
@@ -467,6 +454,10 @@ void OnHttpHeaderReceived(const std::string& header,
// Renderer processes should not be able to spoof Origin HTTP headers.
IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, InvalidOriginHeaders) {
+ // https://crbug.com/862176
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService))
+ return;
+
// Create a set of IPC messages with various Origin headers.
network::ResourceRequest chrome_origin_msg(
CreateXHRRequestWithOrigin("chrome://settings"));
@@ -529,11 +520,21 @@ IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, InvalidOriginHeaders) {
// Renderer process should not be able to create multiple requests with the same
// id.
IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, InvalidRequestId) {
+ // This test is specific to the ResourceDispatcherHost implementation, which
+ // is not used with network service enabled.
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService))
+ return;
+
// Existing loader in pending_loaders_.
TryCreateDuplicateRequestIds(shell(), false);
}
IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, InvalidBlockedRequestId) {
+ // This test is specific to the ResourceDispatcherHost implementation, which
+ // is not used with network service enabled.
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService))
+ return;
+
// Existing loader in blocked_loaders_map_.
TryCreateDuplicateRequestIds(shell(), true);
}
@@ -623,13 +624,18 @@ IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
EXPECT_TRUE(NavigateToURL(shell(), start_url));
- RenderProcessHostKillWaiter kill_waiter(
- shell()->web_contents()->GetMainFrame()->GetProcess());
+ RenderFrameHostImpl* frame = static_cast<RenderFrameHostImpl*>(
+ shell()->web_contents()->GetMainFrame());
+ RenderProcessHostKillWaiter kill_waiter(frame->GetProcess());
ScopedInterfaceProviderRequestReplacer replacer(shell()->web_contents(),
nullptr);
NavigateToURLAndExpectNoCommit(shell(), non_same_document_url);
EXPECT_EQ(bad_message::RFH_INTERFACE_PROVIDER_MISSING, kill_waiter.Wait());
+
+ // Verify that the death of the renderer process doesn't leave behing and leak
+ // NavigationRequests - see https://crbug.com/869193.
+ EXPECT_EQ(0u, frame->GetNavigationEntryIdsPendingCommit().size());
}
// Test that a compromised renderer cannot ask to upload an arbitrary file in
@@ -648,7 +654,7 @@ IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
root->current_frame_host()->GetProcess());
// Prepare a file to upload.
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_temp_dir;
+ base::ScopedAllowBlockingForTesting allow_blocking;
base::ScopedTempDir temp_dir;
base::FilePath file_path;
std::string file_content("test-file-content");
diff --git a/chromium/content/browser/service_manager/common_browser_interfaces.cc b/chromium/content/browser/service_manager/common_browser_interfaces.cc
index ea58b9e3599..f537f90fa48 100644
--- a/chromium/content/browser/service_manager/common_browser_interfaces.cc
+++ b/chromium/content/browser/service_manager/common_browser_interfaces.cc
@@ -11,12 +11,13 @@
#include "base/callback.h"
#include "base/command_line.h"
#include "base/memory/ref_counted.h"
+#include "base/task/post_task.h"
#include "base/task_runner.h"
-#include "base/task_scheduler/post_task.h"
#include "build/build_config.h"
#include "components/discardable_memory/service/discardable_shared_memory_manager.h"
+#include "components/viz/host/gpu_client.h"
#include "content/browser/browser_main_loop.h"
-#include "content/browser/gpu/gpu_client_impl.h"
+#include "content/browser/gpu/browser_gpu_client_delegate.h"
#include "content/common/child_process_host_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/connection_filter.h"
@@ -24,7 +25,7 @@
#include "content/public/common/service_names.mojom.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/ui/public/interfaces/gpu.mojom.h"
+#include "services/ws/public/mojom/gpu.mojom.h"
#include "ui/base/ui_base_features.h"
#if defined(OS_WIN)
@@ -50,7 +51,7 @@ class ConnectionFilterImpl : public ConnectionFilter {
#elif defined(OS_MACOSX)
registry_.AddInterface(base::BindRepeating(&FontLoaderDispatcher::Create));
#endif
- if (features::IsAshInBrowserProcess()) {
+ if (!features::IsUsingWindowService()) {
// For mus, the mojom::discardable_memory::DiscardableSharedMemoryManager
// is exposed from ui::Service. So we don't need bind the interface here.
auto* browser_main_loop = BrowserMainLoop::GetInstance();
@@ -62,8 +63,6 @@ class ConnectionFilterImpl : public ConnectionFilter {
base::Unretained(manager)));
}
}
- }
- if (features::IsAshInBrowserProcess()) {
registry_.AddInterface(base::BindRepeating(
&ConnectionFilterImpl::BindGpuRequest, base::Unretained(this)));
}
@@ -82,16 +81,16 @@ class ConnectionFilterImpl : public ConnectionFilter {
const std::string& interface_name,
mojo::ScopedMessagePipeHandle* interface_pipe,
service_manager::Connector* connector) override {
- // Ignore ui::mojom::Gpu interface request from Renderer process.
+ // Ignore ws::mojom::Gpu interface request from Renderer process.
// The request will be handled in RenderProcessHostImpl.
if (source_info.identity.name() == mojom::kRendererServiceName &&
- interface_name == ui::mojom::Gpu::Name_)
+ interface_name == ws::mojom::Gpu::Name_)
return;
registry_.TryBindInterface(interface_name, interface_pipe, source_info);
}
- void BindGpuRequest(ui::mojom::GpuRequest request,
+ void BindGpuRequest(ws::mojom::GpuRequest request,
const service_manager::BindSourceInfo& source_info) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -104,8 +103,9 @@ class ConnectionFilterImpl : public ConnectionFilter {
const uint64_t gpu_client_tracing_id =
ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(
gpu_client_id);
- auto gpu_client = std::make_unique<GpuClientImpl>(
- gpu_client_id, gpu_client_tracing_id,
+ auto gpu_client = std::make_unique<viz::GpuClient>(
+ std::make_unique<BrowserGpuClientDelegate>(), gpu_client_id,
+ gpu_client_tracing_id,
BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
gpu_client->SetConnectionErrorHandler(
base::BindOnce(&ConnectionFilterImpl::OnGpuConnectionClosed,
@@ -115,7 +115,7 @@ class ConnectionFilterImpl : public ConnectionFilter {
}
void OnGpuConnectionClosed(const service_manager::Identity& service_identity,
- GpuClient* client) {
+ viz::GpuClient* client) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
gpu_clients_.erase(service_identity);
}
@@ -133,7 +133,7 @@ class ConnectionFilterImpl : public ConnectionFilter {
service_manager::BinderRegistryWithArgs<
const service_manager::BindSourceInfo&>
registry_;
- std::map<service_manager::Identity, std::unique_ptr<GpuClientImpl>>
+ std::map<service_manager::Identity, std::unique_ptr<viz::GpuClient>>
gpu_clients_;
DISALLOW_COPY_AND_ASSIGN(ConnectionFilterImpl);
diff --git a/chromium/content/browser/service_manager/service_manager_context.cc b/chromium/content/browser/service_manager/service_manager_context.cc
index 2daaf7231c0..f35734b66d0 100644
--- a/chromium/content/browser/service_manager/service_manager_context.cc
+++ b/chromium/content/browser/service_manager/service_manager_context.cc
@@ -23,7 +23,7 @@
#include "base/process/process_handle.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "build/build_config.h"
#include "content/app/strings/grit/content_strings.h"
#include "content/browser/browser_main_loop.h"
@@ -100,6 +100,13 @@
#include "components/services/font/public/interfaces/constants.mojom.h"
#endif
+#if defined(OS_CHROMEOS)
+#include "chromeos/assistant/buildflags.h" // nogncheck
+#if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
+#include "chromeos/services/assistant/public/mojom/constants.mojom.h" // nogncheck
+#endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
+#endif
+
namespace content {
namespace {
@@ -298,7 +305,7 @@ class ServiceBinaryLauncherFactory
bool ShouldEnableVizService() {
#if defined(USE_AURA)
// aura::Env can be null in tests.
- return aura::Env::GetInstanceDontCreate() &&
+ return aura::Env::HasInstance() &&
aura::Env::GetInstance()->mode() == aura::Env::Mode::MUS;
#else
return false;
@@ -508,7 +515,7 @@ ServiceManagerContext::ServiceManagerContext(
// affinity on the clients. We therefore require a single-thread runner.
scoped_refptr<base::SingleThreadTaskRunner> device_blocking_task_runner =
base::CreateSingleThreadTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::BACKGROUND});
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
#if defined(OS_ANDROID)
JNIEnv* env = base::android::AttachCurrentThread();
@@ -567,7 +574,7 @@ ServiceManagerContext::ServiceManagerContext(
base::CreateSingleThreadTaskRunnerWithTraits(
#endif
base::TaskTraits({base::MayBlock(), base::WithBaseSyncPrimitives(),
- base::TaskPriority::BACKGROUND}),
+ base::TaskPriority::BEST_EFFORT}),
base::SingleThreadTaskRunnerThreadMode::DEDICATED);
packaged_services_connection_->AddEmbeddedService(
video_capture::mojom::kServiceName, video_capture_info);
@@ -666,6 +673,15 @@ ServiceManagerContext::ServiceManagerContext(
&base::ASCIIToUTF16, "Content Decryption Module Service");
#endif
+#if defined(OS_CHROMEOS)
+#if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
+ out_of_process_services
+ [chromeos::assistant::mojom::kAudioDecoderServiceName] =
+ base::BindRepeating(&base::ASCIIToUTF16,
+ "Assistant Audio Decoder Service");
+#endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
+#endif
+
if (ShouldEnableVizService()) {
out_of_process_services[viz::mojom::kVizServiceName] =
base::BindRepeating(&base::ASCIIToUTF16, "Visuals Service");
@@ -721,7 +737,7 @@ bool ServiceManagerContext::HasValidProcessForProcessGroup(
auto iter = g_active_process_groups.Get().find(process_group_name);
if (iter == g_active_process_groups.Get().end() || !iter->second)
return false;
- return iter->second->GetData().handle != base::kNullProcessHandle;
+ return iter->second->GetData().IsHandleValid();
}
// static
diff --git a/chromium/content/browser/service_worker/README.md b/chromium/content/browser/service_worker/README.md
index 55d7fb79b43..c0550d31bc2 100644
--- a/chromium/content/browser/service_worker/README.md
+++ b/chromium/content/browser/service_worker/README.md
@@ -3,18 +3,28 @@
[content/renderer/service_worker]: /content/renderer/service_worker
[content/renderer/service_worker]: /content/renderer/service_worker
[content/common/service_worker]: /content/common/service_worker
+[disk_cache]: /net/disk_cache/README.md
+[embedded_worker.mojom]: https://codesearch.chromium.org/chromium/src/content/common/service_worker/embedded_worker.mojom
+[service_worker_container.mojom]: https://codesearch.chromium.org/chromium/src/content/common/service_worker/service_worker_container.mojom
+[service_worker_database.h]: https://codesearch.chromium.org/chromium/src/content/browser/service_worker/service_worker_database.h
[third_party/blink/common/service_worker]: /third_party/blink/common/service_worker
[third_party/blink/public/common/service_worker]: /third_party/blink/public/common/service_worker
[third_party/blink/public/mojom/service_worker]: /third_party/blink/public/mojom/service_worker
[third_party/blink/public/platform/modules/service_worker]: /third_party/blink/public/platform/modules/service_worker
[third_party/blink/public/web/modules/service_worker]: /third_party/blink/public/web/modules/service_worker
[third_party/blink/renderer/modules/service_worker]: /third_party/blink/renderer/modules/service_worker
-[Blink Public API]: /third_party/blink/public
+[Blink Public API]: /third_party/blink/public/README.md
+[Cache Storage API]: /content/browser/cache_storage/README.md
+[LevelDB]: /third_party/leveldatabase/README.chromium
[Onion Soup]: https://docs.google.com/document/d/1K1nO8G9dO9kNSmtVz2gJ2GG9gQOTgm65sJlV3Fga4jE/edit?usp=sharing
+[Quota Manager]: /storage/browser/quota
+[ServiceWorkerDatabase]: https://codesearch.chromium.org/chromium/src/content/browser/service_worker/service_worker_database.h
+[ServiceWorkerStorage]: https://codesearch.chromium.org/chromium/src/content/browser/service_worker/service_worker_storage.h
+[Service Worker specification]: https://w3c.github.io/ServiceWorker/
This is Chromium's implementation of [service
-workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API). See the
-[Service Worker specification](https://w3c.github.io/ServiceWorker/).
+workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API).
+See the [Service Worker specification].
## Directory structure
@@ -27,7 +37,7 @@ workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API). S
third_party/blink per [Onion Soup].
- [content/common/service_worker]: Common process code.
- [third_party/blink/common/service_worker]: Common process code. Contains the
- implementation of third_party/blink/public/common/service_worker.
+ implementation of [third_party/blink/public/common/service_worker].
- [third_party/blink/public/common/service_worker]: Header files for common
process code that can be used by both inside Blink and outside Blink.
- [third_party/blink/public/mojom/service_worker]: Mojom files for common
@@ -39,6 +49,73 @@ workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API). S
- [third_party/blink/renderer/modules/service_worker]: Renderer process code in
Blink. This is the closest code to the web-exposed Service Worker API.
+## Storage
+
+Service worker storage consists of the following.
+- **Service worker registration metadata** is stored in a [LevelDB] instance
+ located at ${DIR_USER_DATA}/Service Worker/Database.
+- **Service worker scripts** are stored in a [disk_cache] instance using the
+ "simple" implementation, located at ${DIR_USER_DATA}/Service
+ Worker/ScriptCache. Registration metadata points to these scripts.
+
+Code pointers include [ServiceWorkerDatabase] and [ServiceWorkerStorage].
+
+The related [Cache Storage API] uses a [disk_cache] instance using the "simple"
+implementation, located at ${DIR_USER_DATA}/Service Worker/CacheStorage. This
+location was chosen because the [Cache Storage API] is currently defined in the
+[Service Worker specification], but it can be used independently of service
+workers.
+
+For incognito windows, everything is in-memory.
+
+### Eviction
+
+Service workers storage lasts indefinitely, i.e, there is no periodic deletion
+of old but still installed service workers. Installed service workers are only
+evicted by the [Quota Manager] (or user action). The Quota Manager controls
+several web platform APIs, including sandboxed filesystem, WebSQL, appcache,
+IndexedDB, cache storage, service worker (registration and scripts), and
+background fetch.
+
+The Quota Manager starts eviction when one of the following conditions is true
+(as of August 2018):
+- **The global pool is full**: Chrome is using > 1/3 of the disk (>2/3 on CrOS).
+- **The system is critically low on space**: the disk has < min(1GB,1%) free
+ (regardless of how much Chrome is contributing!)
+
+When eviction starts, origins are purged on an LRU basis until the triggering
+condition no longer applies. Purging an origin deletes its storage completely.
+
+Note that Quota Manager eviction is independent of HTTP cache eviction. The
+HTTP cache is typically much smaller than the storage under the control of the
+Quota Manager, and it likely uses a simple non-origin-based LRU algorithm.
+
+## UseCounter integration
+
+Blink has a UseCounter mechanism intended to measure the percentage of page
+loads on the web that used a given feature. Service workers complicate this
+measurement because a feature use in a service worker potentially affects many
+page loads, including ones in the future.
+
+Therefore, service workers integrate with the UseCounter mechanism as follows:
+- **If a feature use occurs before the service worker finished installing**, it
+is recorded in storage along with the service worker. Any page thereafter that
+the service worker controls is counted as using the feature.
+- **If a feature use occurs after the service worker finished installing**, all
+currently controlled pages are counted as using the feature.
+
+For more details and rationale, see [Design of UseCounter for
+workers](https://docs.google.com/document/d/1VyYZnhjBdk-MzCRAcX37TM5-yjwTY40U_J9rWnEAo8c/edit?usp=sharing)
+and [crbug 376039](https://bugs.chromium.org/p/chromium/issues/detail?id=376039).
+
+Code pointers include:
+- (Browser -> Page) ServiceWorkerContainer.SetController and
+ServiceWorkerContainer.CountFeature in [service_worker_container.mojom].
+- (Service worker -> Browser) EmbeddedWorkerInstanceHost.CountFeature
+in [embedded_worker.mojom].
+- (Persistence) ServiceWorkerDatabase::RegistrationData::used_features
+in [service_worker_database.h].
+
## Other documentation
- [Service Worker Security FAQ](/docs/security/service-worker-security-faq.md)
diff --git a/chromium/content/browser/service_worker/embedded_worker_instance.cc b/chromium/content/browser/service_worker/embedded_worker_instance.cc
index 7e3365820e3..597aba71671 100644
--- a/chromium/content/browser/service_worker/embedded_worker_instance.cc
+++ b/chromium/content/browser/service_worker/embedded_worker_instance.cc
@@ -29,6 +29,7 @@
#include "content/public/common/child_process_host.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
+#include "content/public/common/renderer_preference_watcher.mojom.h"
#include "ipc/ipc_message.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "third_party/blink/public/common/features.h"
@@ -78,18 +79,60 @@ void NotifyWorkerVersionDoomedOnUI(int worker_process_id, int worker_route_id) {
worker_process_id, worker_route_id);
}
+std::unique_ptr<URLLoaderFactoryBundleInfo> CreateFactoryBundle(
+ RenderProcessHost* rph,
+ bool use_non_network_factories) {
+ auto factory_bundle = std::make_unique<URLLoaderFactoryBundleInfo>();
+ network::mojom::URLLoaderFactoryPtrInfo default_factory_info;
+ rph->CreateURLLoaderFactory(mojo::MakeRequest(&default_factory_info));
+ factory_bundle->default_factory_info() = std::move(default_factory_info);
+
+ if (use_non_network_factories) {
+ ContentBrowserClient::NonNetworkURLLoaderFactoryMap factories;
+ GetContentClient()
+ ->browser()
+ ->RegisterNonNetworkSubresourceURLLoaderFactories(
+ rph->GetID(), MSG_ROUTING_NONE, &factories);
+
+ for (auto& pair : factories) {
+ const std::string& scheme = pair.first;
+ std::unique_ptr<network::mojom::URLLoaderFactory> factory =
+ std::move(pair.second);
+
+ // To be safe, ignore schemes that aren't allowed to register service
+ // workers. We assume that importScripts should fail on such schemes.
+ if (!base::ContainsValue(GetServiceWorkerSchemes(), scheme))
+ continue;
+ network::mojom::URLLoaderFactoryPtr factory_ptr;
+ mojo::MakeStrongBinding(std::move(factory),
+ mojo::MakeRequest(&factory_ptr));
+ factory_bundle->factories_info().emplace(scheme,
+ factory_ptr.PassInterface());
+ }
+ }
+ return factory_bundle;
+}
+
using SetupProcessCallback = base::OnceCallback<void(
blink::ServiceWorkerStatusCode,
mojom::EmbeddedWorkerStartParamsPtr,
std::unique_ptr<ServiceWorkerProcessManager::AllocatedProcessInfo>,
std::unique_ptr<EmbeddedWorkerInstance::DevToolsProxy>,
- std::unique_ptr<URLLoaderFactoryBundleInfo>,
+ std::unique_ptr<
+ URLLoaderFactoryBundleInfo> /* factory_bundle_for_browser */,
+ std::unique_ptr<
+ URLLoaderFactoryBundleInfo> /* factory_bundle_for_renderer */,
blink::mojom::CacheStoragePtrInfo)>;
// Allocates a renderer process for starting a worker and does setup like
// registering with DevTools. Called on the UI thread. Calls |callback| on the
// IO thread. |context| and |weak_context| are only for passing to DevTools and
// must not be dereferenced here on the UI thread.
+// S13nServiceWorker:
+// This also sets up two URLLoaderFactoryBundles, one for
+// ServiceWorkerScriptLoaderFactory and the other is for passing to the
+// renderer. These bundles include factories for non-network URLs like
+// chrome-extension:// as needed.
void SetupOnUIThread(base::WeakPtr<ServiceWorkerProcessManager> process_manager,
bool can_use_existing_process,
mojom::EmbeddedWorkerStartParamsPtr params,
@@ -101,16 +144,18 @@ void SetupOnUIThread(base::WeakPtr<ServiceWorkerProcessManager> process_manager,
auto process_info =
std::make_unique<ServiceWorkerProcessManager::AllocatedProcessInfo>();
std::unique_ptr<EmbeddedWorkerInstance::DevToolsProxy> devtools_proxy;
- std::unique_ptr<URLLoaderFactoryBundleInfo> factory_bundle;
+ std::unique_ptr<URLLoaderFactoryBundleInfo> factory_bundle_for_browser;
+ std::unique_ptr<URLLoaderFactoryBundleInfo> factory_bundle_for_renderer;
if (!process_manager) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- base::BindOnce(std::move(callback),
- blink::ServiceWorkerStatusCode::kErrorAbort,
- std::move(params), std::move(process_info),
- std::move(devtools_proxy), std::move(factory_bundle),
- nullptr /* cache_storage */));
+ base::BindOnce(
+ std::move(callback), blink::ServiceWorkerStatusCode::kErrorAbort,
+ std::move(params), std::move(process_info),
+ std::move(devtools_proxy), std::move(factory_bundle_for_browser),
+ std::move(factory_bundle_for_renderer),
+ nullptr /* cache_storage */));
return;
}
@@ -124,7 +169,9 @@ void SetupOnUIThread(base::WeakPtr<ServiceWorkerProcessManager> process_manager,
BrowserThread::IO, FROM_HERE,
base::BindOnce(std::move(callback), status, std::move(params),
std::move(process_info), std::move(devtools_proxy),
- std::move(factory_bundle), nullptr /* cache_storage */));
+ std::move(factory_bundle_for_browser),
+ std::move(factory_bundle_for_renderer),
+ nullptr /* cache_storage */));
return;
}
const int process_id = process_info->process_id;
@@ -162,40 +209,16 @@ void SetupOnUIThread(base::WeakPtr<ServiceWorkerProcessManager> process_manager,
// since it's used for a single service worker startup until installation
// finishes (with the exception of https://crbug.com/719052).
if (blink::ServiceWorkerUtils::IsServicificationEnabled()) {
- network::mojom::URLLoaderFactoryPtrInfo default_factory_info;
- rph->CreateURLLoaderFactory(mojo::MakeRequest(&default_factory_info));
- factory_bundle = std::make_unique<URLLoaderFactoryBundleInfo>();
- factory_bundle->default_factory_info() = std::move(default_factory_info);
- }
-
- // S13nServiceWorker:
- // Create the loader factories for non-http(s) URLs, for example
- // chrome-extension:// URLs. For performance, only do this step when the main
- // script URL is non-http(s). We assume an http(s) service worker cannot
- // importScripts a non-http(s) URL.
- if (blink::ServiceWorkerUtils::IsServicificationEnabled() &&
- !params->script_url.SchemeIsHTTPOrHTTPS()) {
- ContentBrowserClient::NonNetworkURLLoaderFactoryMap factories;
- GetContentClient()
- ->browser()
- ->RegisterNonNetworkSubresourceURLLoaderFactories(
- rph->GetID(), MSG_ROUTING_NONE, &factories);
-
- for (auto& pair : factories) {
- const std::string& scheme = pair.first;
- std::unique_ptr<network::mojom::URLLoaderFactory> factory =
- std::move(pair.second);
-
- // To be safe, ignore schemes that aren't allowed to register service
- // workers. We assume that importScripts should fail on such schemes.
- if (!base::ContainsValue(GetServiceWorkerSchemes(), scheme))
- continue;
- network::mojom::URLLoaderFactoryPtr factory_ptr;
- mojo::MakeStrongBinding(std::move(factory),
- mojo::MakeRequest(&factory_ptr));
- factory_bundle->factories_info().emplace(scheme,
- factory_ptr.PassInterface());
- }
+ // For performance, we only create the loader factories for non-http(s)
+ // URLs (e.g. chrome-extension://) when the main script URL is
+ // non-http(s). We assume an http(s) service worker cannot
+ // importScripts a non-http(s) URL.
+ bool use_non_network_factories = !params->script_url.SchemeIsHTTPOrHTTPS();
+
+ factory_bundle_for_browser =
+ CreateFactoryBundle(rph, use_non_network_factories);
+ factory_bundle_for_renderer =
+ CreateFactoryBundle(rph, use_non_network_factories);
}
// Register to DevTools and update params accordingly.
@@ -218,12 +241,20 @@ void SetupOnUIThread(base::WeakPtr<ServiceWorkerProcessManager> process_manager,
GetContentClient()->browser()->UpdateRendererPreferencesForWorker(
process_manager->browser_context(), &params->renderer_preferences);
+ // Create a RendererPreferenceWatcher to observe updates in the preferences.
+ mojom::RendererPreferenceWatcherPtr watcher_ptr;
+ params->preference_watcher_request = mojo::MakeRequest(&watcher_ptr);
+ GetContentClient()->browser()->RegisterRendererPreferenceWatcherForWorkers(
+ process_manager->browser_context(), std::move(watcher_ptr));
+
// Continue to OnSetupCompleted on the IO thread.
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::BindOnce(std::move(callback), status, std::move(params),
std::move(process_info), std::move(devtools_proxy),
- std::move(factory_bundle), cache_storage.PassInterface()));
+ std::move(factory_bundle_for_browser),
+ std::move(factory_bundle_for_renderer),
+ cache_storage.PassInterface()));
}
bool HasSentStartWorker(EmbeddedWorkerInstance::StartingPhase phase) {
@@ -463,7 +494,8 @@ class EmbeddedWorkerInstance::StartTask {
std::unique_ptr<ServiceWorkerProcessManager::AllocatedProcessInfo>
process_info,
std::unique_ptr<EmbeddedWorkerInstance::DevToolsProxy> devtools_proxy,
- std::unique_ptr<URLLoaderFactoryBundleInfo> factory_bundle,
+ std::unique_ptr<URLLoaderFactoryBundleInfo> factory_bundle_for_browser,
+ std::unique_ptr<URLLoaderFactoryBundleInfo> factory_bundle_for_renderer,
blink::mojom::CacheStoragePtrInfo cache_storage) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -512,9 +544,15 @@ class EmbeddedWorkerInstance::StartTask {
// S13nServiceWorker: Build the URLLoaderFactory for loading new scripts.
scoped_refptr<network::SharedURLLoaderFactory> factory_for_new_scripts;
if (blink::ServiceWorkerUtils::IsServicificationEnabled()) {
- DCHECK(factory_bundle);
+ DCHECK(factory_bundle_for_browser);
factory_for_new_scripts = base::MakeRefCounted<URLLoaderFactoryBundle>(
- std::move(factory_bundle));
+ std::move(factory_bundle_for_browser));
+
+ // Send the factory bundle for subresource loading from the service worker
+ // (i.e. fetch()).
+ DCHECK(factory_bundle_for_renderer);
+ params->subresource_loader_factories =
+ std::move(factory_bundle_for_renderer);
}
instance_->SendStartWorker(std::move(params),
@@ -720,11 +758,13 @@ void EmbeddedWorkerInstance::SendStartWorker(
observer.OnStartWorkerMessageSent();
}
-void EmbeddedWorkerInstance::RequestTermination() {
+void EmbeddedWorkerInstance::RequestTermination(
+ RequestTerminationCallback callback) {
if (!blink::ServiceWorkerUtils::IsServicificationEnabled()) {
mojo::ReportBadMessage(
"Invalid termination request: RequestTermination() was called but "
"S13nServiceWorker is not enabled");
+ std::move(callback).Run(true /* will_be_terminated */);
return;
}
@@ -733,12 +773,19 @@ void EmbeddedWorkerInstance::RequestTermination() {
mojo::ReportBadMessage(
"Invalid termination request: Termination should be requested during "
"running or stopping");
+ std::move(callback).Run(true /* will_be_terminated */);
return;
}
- if (status() == EmbeddedWorkerStatus::STOPPING)
+ if (status() == EmbeddedWorkerStatus::STOPPING) {
+ std::move(callback).Run(true /* will_be_terminated */);
return;
+ }
owner_version_->StopWorkerIfIdle(true /* requested_from_renderer */);
+
+ // If DevTools is attached and the worker won't be stopped, the worker needs
+ // to continue to work.
+ std::move(callback).Run(status() != EmbeddedWorkerStatus::RUNNING);
}
void EmbeddedWorkerInstance::CountFeature(blink::mojom::WebFeature feature) {
@@ -913,7 +960,7 @@ void EmbeddedWorkerInstance::SetDevToolsAttached(bool attached) {
return;
if (inflight_start_task_)
inflight_start_task_->set_skip_recording_startup_time();
- registry_->OnDevToolsAttached(embedded_worker_id_);
+ registry_->AbortLifetimeTracking(embedded_worker_id_);
}
void EmbeddedWorkerInstance::OnNetworkAccessedForScriptLoad() {
diff --git a/chromium/content/browser/service_worker/embedded_worker_instance.h b/chromium/content/browser/service_worker/embedded_worker_instance.h
index 4f034cdf345..261425d2f41 100644
--- a/chromium/content/browser/service_worker/embedded_worker_instance.h
+++ b/chromium/content/browser/service_worker/embedded_worker_instance.h
@@ -210,7 +210,7 @@ class CONTENT_EXPORT EmbeddedWorkerInstance
base::WeakPtr<EmbeddedWorkerInstance> AsWeakPtr();
private:
- typedef base::ObserverList<Listener> ListenerList;
+ typedef base::ObserverList<Listener>::Unchecked ListenerList;
class StartTask;
class WorkerProcessHandle;
friend class EmbeddedWorkerRegistry;
@@ -253,7 +253,7 @@ class CONTENT_EXPORT EmbeddedWorkerInstance
// Implements mojom::EmbeddedWorkerInstanceHost.
// These functions all run on the IO thread.
- void RequestTermination() override;
+ void RequestTermination(RequestTerminationCallback callback) override;
void CountFeature(blink::mojom::WebFeature feature) override;
void OnReadyForInspection() override;
void OnScriptLoaded() override;
diff --git a/chromium/content/browser/service_worker/embedded_worker_registry.cc b/chromium/content/browser/service_worker/embedded_worker_registry.cc
index c63e6333f45..34287d99034 100644
--- a/chromium/content/browser/service_worker/embedded_worker_registry.cc
+++ b/chromium/content/browser/service_worker/embedded_worker_registry.cc
@@ -68,7 +68,7 @@ void EmbeddedWorkerRegistry::OnWorkerStopped(int process_id,
lifetime_tracker_.StopTiming(embedded_worker_id);
}
-void EmbeddedWorkerRegistry::OnDevToolsAttached(int embedded_worker_id) {
+void EmbeddedWorkerRegistry::AbortLifetimeTracking(int embedded_worker_id) {
lifetime_tracker_.AbortTiming(embedded_worker_id);
}
diff --git a/chromium/content/browser/service_worker/embedded_worker_registry.h b/chromium/content/browser/service_worker/embedded_worker_registry.h
index 20825f66eef..8aa9743703d 100644
--- a/chromium/content/browser/service_worker/embedded_worker_registry.h
+++ b/chromium/content/browser/service_worker/embedded_worker_registry.h
@@ -55,9 +55,8 @@ class CONTENT_EXPORT EmbeddedWorkerRegistry
bool OnWorkerStarted(int process_id, int embedded_worker_id);
void OnWorkerStopped(int process_id, int embedded_worker_id);
- // Called by EmbeddedWorkerInstance when it learns DevTools has attached to
- // it.
- void OnDevToolsAttached(int embedded_worker_id);
+ // Aborts the timer which tracks the lifetime of the worker for UMA logging.
+ void AbortLifetimeTracking(int embedded_worker_id);
// Returns an embedded worker instance for given |embedded_worker_id|.
EmbeddedWorkerInstance* GetWorker(int embedded_worker_id);
diff --git a/chromium/content/browser/service_worker/embedded_worker_test_helper.cc b/chromium/content/browser/service_worker/embedded_worker_test_helper.cc
index 4942766b0e6..92fcf8b5fe8 100644
--- a/chromium/content/browser/service_worker/embedded_worker_test_helper.cc
+++ b/chromium/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -24,8 +24,6 @@
#include "content/common/background_fetch/background_fetch_types.h"
#include "content/common/renderer.mojom.h"
#include "content/common/service_worker/service_worker.mojom.h"
-#include "content/common/service_worker/service_worker_messages.h"
-#include "content/public/common/push_event_payload.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_browser_context.h"
#include "mojo/public/cpp/bindings/associated_binding_set.h"
@@ -36,6 +34,7 @@
#include "storage/common/blob_storage/blob_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/service_worker/service_worker_utils.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_response.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom.h"
namespace content {
@@ -43,20 +42,13 @@ namespace content {
namespace {
void OnFetchEventCommon(
- mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
+ blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
mojom::ServiceWorker::DispatchFetchEventCallback finish_callback) {
- response_callback->OnResponse(
- ServiceWorkerResponse(
- std::make_unique<std::vector<GURL>>(), 200, "OK",
- network::mojom::FetchResponseType::kDefault,
- std::make_unique<ServiceWorkerHeaderMap>(), std::string(), 0,
- nullptr /* blob */,
- blink::mojom::ServiceWorkerResponseError::kUnknown, base::Time(),
- false /* is_in_cache_storage */,
- std::string() /* cache_storage_cache_name */,
- std::make_unique<
- ServiceWorkerHeaderList>() /* cors_exposed_header_names */),
- base::Time::Now());
+ auto response = blink::mojom::FetchAPIResponse::New();
+ response->status_code = 200;
+ response->status_text = "OK";
+ response->response_type = network::mojom::FetchResponseType::kDefault;
+ response_callback->OnResponse(std::move(response), base::Time::Now());
std::move(finish_callback)
.Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
base::Time::Now());
@@ -220,46 +212,36 @@ class EmbeddedWorkerTestHelper::MockServiceWorker
}
void DispatchBackgroundFetchAbortEvent(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ const BackgroundFetchRegistration& registration,
DispatchBackgroundFetchAbortEventCallback callback) override {
if (!helper_)
return;
- helper_->OnBackgroundFetchAbortEventStub(developer_id, unique_id, fetches,
- std::move(callback));
+ helper_->OnBackgroundFetchAbortEventStub(registration, std::move(callback));
}
void DispatchBackgroundFetchClickEvent(
- const std::string& developer_id,
- mojom::BackgroundFetchState state,
+ const BackgroundFetchRegistration& registration,
DispatchBackgroundFetchClickEventCallback callback) override {
if (!helper_)
return;
- helper_->OnBackgroundFetchClickEventStub(developer_id, state,
- std::move(callback));
+ helper_->OnBackgroundFetchClickEventStub(registration, std::move(callback));
}
void DispatchBackgroundFetchFailEvent(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ const BackgroundFetchRegistration& registration,
DispatchBackgroundFetchFailEventCallback callback) override {
if (!helper_)
return;
- helper_->OnBackgroundFetchFailEventStub(developer_id, unique_id, fetches,
- std::move(callback));
+ helper_->OnBackgroundFetchFailEventStub(registration, std::move(callback));
}
- void DispatchBackgroundFetchedEvent(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
- DispatchBackgroundFetchedEventCallback callback) override {
+ void DispatchBackgroundFetchSuccessEvent(
+ const BackgroundFetchRegistration& registration,
+ DispatchBackgroundFetchSuccessEventCallback callback) override {
if (!helper_)
return;
- helper_->OnBackgroundFetchedEventStub(developer_id, unique_id, fetches,
- std::move(callback));
+ helper_->OnBackgroundFetchSuccessEventStub(registration,
+ std::move(callback));
}
void DispatchCookieChangeEvent(
@@ -273,7 +255,7 @@ class EmbeddedWorkerTestHelper::MockServiceWorker
void DispatchFetchEvent(
blink::mojom::DispatchFetchEventParamsPtr params,
- mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
+ blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
DispatchFetchEventCallback callback) override {
if (!helper_)
return;
@@ -305,7 +287,7 @@ class EmbeddedWorkerTestHelper::MockServiceWorker
std::move(callback));
}
- void DispatchPushEvent(const PushEventPayload& payload,
+ void DispatchPushEvent(const base::Optional<std::string>& payload,
DispatchPushEventCallback callback) override {
if (!helper_)
return;
@@ -359,9 +341,24 @@ class EmbeddedWorkerTestHelper::MockServiceWorker
std::move(callback));
}
+ void DispatchExtendableMessageEventWithCustomTimeout(
+ mojom::ExtendableMessageEventPtr event,
+ base::TimeDelta timeout,
+ DispatchExtendableMessageEventWithCustomTimeoutCallback callback)
+ override {
+ if (!helper_)
+ return;
+ helper_->OnExtendableMessageEventStub(std::move(event),
+ std::move(callback));
+ }
+
void Ping(PingCallback callback) override { std::move(callback).Run(); }
- void SetIdleTimerDelayToZero() override { NOTIMPLEMENTED(); }
+ void SetIdleTimerDelayToZero() override {
+ if (!helper_)
+ return;
+ helper_->OnSetIdleTimerDelayToZero(embedded_worker_id_);
+ }
private:
base::WeakPtr<EmbeddedWorkerTestHelper> helper_;
@@ -487,7 +484,11 @@ void EmbeddedWorkerTestHelper::SetNetworkFactory(
if (!factory)
factory = default_network_loader_factory_.get();
+ // Reset factory in URLLoaderFactoryGetter so that we don't hit DCHECK()
+ // there.
+ url_loader_factory_getter_->SetNetworkFactoryForTesting(nullptr);
url_loader_factory_getter_->SetNetworkFactoryForTesting(factory);
+
render_process_host_->OverrideURLLoaderFactory(factory);
new_render_process_host_->OverrideURLLoaderFactory(factory);
}
@@ -584,36 +585,30 @@ void EmbeddedWorkerTestHelper::OnActivateEvent(
}
void EmbeddedWorkerTestHelper::OnBackgroundFetchAbortEvent(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ const BackgroundFetchRegistration& registration,
mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback callback) {
std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
base::Time::Now());
}
void EmbeddedWorkerTestHelper::OnBackgroundFetchClickEvent(
- const std::string& developer_id,
- mojom::BackgroundFetchState state,
+ const BackgroundFetchRegistration& registration,
mojom::ServiceWorker::DispatchBackgroundFetchClickEventCallback callback) {
std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
base::Time::Now());
}
void EmbeddedWorkerTestHelper::OnBackgroundFetchFailEvent(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ const BackgroundFetchRegistration& registration,
mojom::ServiceWorker::DispatchBackgroundFetchFailEventCallback callback) {
std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
base::Time::Now());
}
-void EmbeddedWorkerTestHelper::OnBackgroundFetchedEvent(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
- mojom::ServiceWorker::DispatchBackgroundFetchedEventCallback callback) {
+void EmbeddedWorkerTestHelper::OnBackgroundFetchSuccessEvent(
+ const BackgroundFetchRegistration& registration,
+ mojom::ServiceWorker::DispatchBackgroundFetchSuccessEventCallback
+ callback) {
std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
base::Time::Now());
}
@@ -644,14 +639,14 @@ void EmbeddedWorkerTestHelper::OnFetchEvent(
int /* embedded_worker_id */,
const network::ResourceRequest& /* request */,
blink::mojom::FetchEventPreloadHandlePtr /* preload_handle */,
- mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
+ blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
mojom::ServiceWorker::DispatchFetchEventCallback finish_callback) {
// TODO(falken): In-line common into here.
OnFetchEventCommon(std::move(response_callback), std::move(finish_callback));
}
void EmbeddedWorkerTestHelper::OnPushEvent(
- const PushEventPayload& payload,
+ base::Optional<std::string> payload,
mojom::ServiceWorker::DispatchPushEventCallback callback) {
std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
base::Time::Now());
@@ -710,6 +705,11 @@ void EmbeddedWorkerTestHelper::OnPaymentRequestEvent(
base::Time::Now());
}
+void EmbeddedWorkerTestHelper::OnSetIdleTimerDelayToZero(
+ int embedded_worker_id) {
+ // Subclasses may implement this method.
+}
+
void EmbeddedWorkerTestHelper::SimulateWorkerReadyForInspection(
int embedded_worker_id) {
EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
@@ -856,49 +856,40 @@ void EmbeddedWorkerTestHelper::OnActivateEventStub(
}
void EmbeddedWorkerTestHelper::OnBackgroundFetchAbortEventStub(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ const BackgroundFetchRegistration& registration,
mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&EmbeddedWorkerTestHelper::OnBackgroundFetchAbortEvent,
- AsWeakPtr(), developer_id, unique_id, fetches,
- std::move(callback)));
+ AsWeakPtr(), registration, std::move(callback)));
}
void EmbeddedWorkerTestHelper::OnBackgroundFetchClickEventStub(
- const std::string& developer_id,
- mojom::BackgroundFetchState state,
+ const BackgroundFetchRegistration& registration,
mojom::ServiceWorker::DispatchBackgroundFetchClickEventCallback callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&EmbeddedWorkerTestHelper::OnBackgroundFetchClickEvent,
- AsWeakPtr(), developer_id, state, std::move(callback)));
+ AsWeakPtr(), registration, std::move(callback)));
}
void EmbeddedWorkerTestHelper::OnBackgroundFetchFailEventStub(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ const BackgroundFetchRegistration& registration,
mojom::ServiceWorker::DispatchBackgroundFetchFailEventCallback callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&EmbeddedWorkerTestHelper::OnBackgroundFetchFailEvent,
- AsWeakPtr(), developer_id, unique_id, fetches,
- std::move(callback)));
+ AsWeakPtr(), registration, std::move(callback)));
}
-void EmbeddedWorkerTestHelper::OnBackgroundFetchedEventStub(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
- mojom::ServiceWorker::DispatchBackgroundFetchedEventCallback callback) {
+void EmbeddedWorkerTestHelper::OnBackgroundFetchSuccessEventStub(
+ const BackgroundFetchRegistration& registration,
+ mojom::ServiceWorker::DispatchBackgroundFetchSuccessEventCallback
+ callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::BindOnce(&EmbeddedWorkerTestHelper::OnBackgroundFetchedEvent,
- AsWeakPtr(), developer_id, unique_id, fetches,
- std::move(callback)));
+ base::BindOnce(&EmbeddedWorkerTestHelper::OnBackgroundFetchSuccessEvent,
+ AsWeakPtr(), registration, std::move(callback)));
}
void EmbeddedWorkerTestHelper::OnCookieChangeEventStub(
@@ -931,7 +922,7 @@ void EmbeddedWorkerTestHelper::OnFetchEventStub(
int embedded_worker_id,
const network::ResourceRequest& request,
blink::mojom::FetchEventPreloadHandlePtr preload_handle,
- mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
+ blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
mojom::ServiceWorker::DispatchFetchEventCallback finish_callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
@@ -965,11 +956,12 @@ void EmbeddedWorkerTestHelper::OnNotificationCloseEventStub(
}
void EmbeddedWorkerTestHelper::OnPushEventStub(
- const PushEventPayload& payload,
+ base::Optional<std::string> payload,
mojom::ServiceWorker::DispatchPushEventCallback callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&EmbeddedWorkerTestHelper::OnPushEvent,
- AsWeakPtr(), payload, std::move(callback)));
+ FROM_HERE,
+ base::BindOnce(&EmbeddedWorkerTestHelper::OnPushEvent, AsWeakPtr(),
+ std::move(payload), std::move(callback)));
}
void EmbeddedWorkerTestHelper::OnAbortPaymentEventStub(
diff --git a/chromium/content/browser/service_worker/embedded_worker_test_helper.h b/chromium/content/browser/service_worker/embedded_worker_test_helper.h
index 9204ee99207..04943106abf 100644
--- a/chromium/content/browser/service_worker/embedded_worker_test_helper.h
+++ b/chromium/content/browser/service_worker/embedded_worker_test_helper.h
@@ -35,7 +35,7 @@ class GURL;
namespace content {
-struct BackgroundFetchSettledFetch;
+struct BackgroundFetchRegistration;
class EmbeddedWorkerRegistry;
class EmbeddedWorkerTestHelper;
class MockRenderProcessHost;
@@ -43,7 +43,6 @@ class ServiceWorkerContextCore;
class ServiceWorkerContextWrapper;
class TestBrowserContext;
struct PlatformNotificationData;
-struct PushEventPayload;
// In-Process EmbeddedWorker test helper.
//
@@ -95,10 +94,6 @@ class EmbeddedWorkerTestHelper {
// If |user_data_directory| is empty, the context makes storage stuff in
// memory.
explicit EmbeddedWorkerTestHelper(const base::FilePath& user_data_directory);
- // S13nServiceWorker
- EmbeddedWorkerTestHelper(
- const base::FilePath& user_data_directory,
- scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter);
virtual ~EmbeddedWorkerTestHelper();
// Registers a Mojo endpoint object derived from
@@ -172,24 +167,18 @@ class EmbeddedWorkerTestHelper {
virtual void OnActivateEvent(
mojom::ServiceWorker::DispatchActivateEventCallback callback);
virtual void OnBackgroundFetchAbortEvent(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ const BackgroundFetchRegistration& registration,
mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback callback);
virtual void OnBackgroundFetchClickEvent(
- const std::string& developer_id,
- mojom::BackgroundFetchState state,
+ const BackgroundFetchRegistration& registration,
mojom::ServiceWorker::DispatchBackgroundFetchClickEventCallback callback);
virtual void OnBackgroundFetchFailEvent(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ const BackgroundFetchRegistration& registration,
mojom::ServiceWorker::DispatchBackgroundFetchFailEventCallback callback);
- virtual void OnBackgroundFetchedEvent(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
- mojom::ServiceWorker::DispatchBackgroundFetchedEventCallback callback);
+ virtual void OnBackgroundFetchSuccessEvent(
+ const BackgroundFetchRegistration& registration,
+ mojom::ServiceWorker::DispatchBackgroundFetchSuccessEventCallback
+ callback);
virtual void OnCookieChangeEvent(
const net::CanonicalCookie& cookie,
::network::mojom::CookieChangeCause cause,
@@ -203,7 +192,7 @@ class EmbeddedWorkerTestHelper {
int embedded_worker_id,
const network::ResourceRequest& request,
blink::mojom::FetchEventPreloadHandlePtr preload_handle,
- mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
+ blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
mojom::ServiceWorker::DispatchFetchEventCallback finish_callback);
virtual void OnNotificationClickEvent(
const std::string& notification_id,
@@ -216,7 +205,7 @@ class EmbeddedWorkerTestHelper {
const PlatformNotificationData& notification_data,
mojom::ServiceWorker::DispatchNotificationCloseEventCallback callback);
virtual void OnPushEvent(
- const PushEventPayload& payload,
+ base::Optional<std::string> payload,
mojom::ServiceWorker::DispatchPushEventCallback callback);
virtual void OnAbortPaymentEvent(
payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
@@ -229,6 +218,7 @@ class EmbeddedWorkerTestHelper {
payments::mojom::PaymentRequestEventDataPtr data,
payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
mojom::ServiceWorker::DispatchPaymentRequestEventCallback callback);
+ virtual void OnSetIdleTimerDelayToZero(int embedded_worker_id);
// These functions simulate making Mojo calls to the browser.
void SimulateWorkerReadyForInspection(int embedded_worker_id);
@@ -248,6 +238,11 @@ class EmbeddedWorkerTestHelper {
return embedded_worker_id_host_map_[embedded_worker_id].get();
}
+ mojom::EmbeddedWorkerInstanceHostProxy* GetEmbeddedWorkerInstanceHost(
+ int embedded_worker_id) {
+ return embedded_worker_id_instance_host_ptr_map_[embedded_worker_id].get();
+ }
+
private:
class MockNetworkURLLoaderFactory;
class MockServiceWorker;
@@ -266,24 +261,18 @@ class EmbeddedWorkerTestHelper {
void OnActivateEventStub(
mojom::ServiceWorker::DispatchActivateEventCallback callback);
void OnBackgroundFetchAbortEventStub(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ const BackgroundFetchRegistration& registration,
mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback callback);
void OnBackgroundFetchClickEventStub(
- const std::string& developer_id,
- mojom::BackgroundFetchState state,
+ const BackgroundFetchRegistration& registration,
mojom::ServiceWorker::DispatchBackgroundFetchClickEventCallback callback);
void OnBackgroundFetchFailEventStub(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
+ const BackgroundFetchRegistration& registration,
mojom::ServiceWorker::DispatchBackgroundFetchFailEventCallback callback);
- void OnBackgroundFetchedEventStub(
- const std::string& developer_id,
- const std::string& unique_id,
- const std::vector<BackgroundFetchSettledFetch>& fetches,
- mojom::ServiceWorker::DispatchBackgroundFetchedEventCallback callback);
+ void OnBackgroundFetchSuccessEventStub(
+ const BackgroundFetchRegistration& registration,
+ mojom::ServiceWorker::DispatchBackgroundFetchSuccessEventCallback
+ callback);
void OnCookieChangeEventStub(
const net::CanonicalCookie& cookie,
::network::mojom::CookieChangeCause cause,
@@ -297,7 +286,7 @@ class EmbeddedWorkerTestHelper {
int embedded_worker_id,
const network::ResourceRequest& request,
blink::mojom::FetchEventPreloadHandlePtr preload_handle,
- mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
+ blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
mojom::ServiceWorker::DispatchFetchEventCallback finish_callback);
void OnNotificationClickEventStub(
const std::string& notification_id,
@@ -310,7 +299,7 @@ class EmbeddedWorkerTestHelper {
const PlatformNotificationData& notification_data,
mojom::ServiceWorker::DispatchNotificationCloseEventCallback callback);
void OnPushEventStub(
- const PushEventPayload& payload,
+ base::Optional<std::string> payload,
mojom::ServiceWorker::DispatchPushEventCallback callback);
void OnAbortPaymentEventStub(
payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
diff --git a/chromium/content/browser/service_worker/service_worker_browsertest.cc b/chromium/content/browser/service_worker/service_worker_browsertest.cc
index d8275ba30f8..7e129e81e95 100644
--- a/chromium/content/browser/service_worker/service_worker_browsertest.cc
+++ b/chromium/content/browser/service_worker/service_worker_browsertest.cc
@@ -22,8 +22,8 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/task_scheduler/post_task.h"
-#include "base/task_scheduler/task_traits.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
#include "base/test/bind_test_util.h"
#include "base/test/scoped_feature_list.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -45,7 +45,6 @@
#include "content/browser/service_worker/service_worker_test_utils.h"
#include "content/browser/service_worker/service_worker_version.h"
#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/common/service_worker/service_worker_messages.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
@@ -63,6 +62,7 @@
#include "content/public/common/content_switches.h"
#include "content/public/common/referrer.h"
#include "content/public/common/resource_type.h"
+#include "content/public/common/url_loader_throttle.h"
#include "content/public/common/web_preferences.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
@@ -75,15 +75,19 @@
#include "net/dns/mock_host_resolver.h"
#include "net/http/http_response_info.h"
#include "net/log/net_log_with_source.h"
+#include "net/test/embedded_test_server/default_handlers.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "net/url_request/url_request_filter.h"
#include "net/url_request/url_request_test_job.h"
+#include "services/network/loader_util.h"
+#include "services/network/public/cpp/features.h"
#include "storage/browser/blob/blob_data_handle.h"
#include "storage/browser/blob/blob_data_snapshot.h"
#include "storage/browser/blob/blob_reader.h"
#include "storage/browser/blob/blob_storage_context.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
#include "third_party/blink/public/common/service_worker/service_worker_type_converters.h"
#include "third_party/blink/public/common/service_worker/service_worker_utils.h"
@@ -105,7 +109,7 @@ const int kV8CacheTimeStampDataSize =
struct FetchResult {
blink::ServiceWorkerStatusCode status;
ServiceWorkerFetchDispatcher::FetchEventResult result;
- ServiceWorkerResponse response;
+ blink::mojom::FetchAPIResponsePtr response;
std::unique_ptr<storage::BlobDataHandle> blob_data_handle;
};
@@ -200,6 +204,7 @@ class WorkerActivatedObserver
}
// ServiceWorkerContextCoreObserver overrides.
void OnVersionStateChanged(int64_t version_id,
+ const GURL& scope,
ServiceWorkerVersion::Status) override {
ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
const ServiceWorkerVersion* version = context_->GetLiveVersion(version_id);
@@ -611,7 +616,7 @@ class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
void FetchOnRegisteredWorker(
ServiceWorkerFetchDispatcher::FetchEventResult* result,
- ServiceWorkerResponse* response,
+ blink::mojom::FetchAPIResponsePtr* response,
std::unique_ptr<storage::BlobDataHandle>* blob_data_handle) {
blob_context_ = ChromeBlobStorageContext::GetFor(
shell()->web_contents()->GetBrowserContext());
@@ -627,7 +632,7 @@ class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
fetch_run_loop.Run();
ASSERT_TRUE(prepare_result);
*result = fetch_result.result;
- *response = fetch_result.response;
+ *response = std::move(fetch_result.response);
*blob_data_handle = std::move(fetch_result.blob_data_handle);
ASSERT_EQ(blink::ServiceWorkerStatusCode::kOk, fetch_result.status);
}
@@ -671,8 +676,8 @@ class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
wrapper()->context()->AsWeakPtr(), &remote_endpoints_.back());
host->SetDocumentUrl(
embedded_test_server()->GetURL("/service_worker/host"));
- host->AssociateRegistration(registration_.get(),
- false /* notify_controllerchange */);
+ host->SetControllerRegistration(registration_,
+ false /* notify_controllerchange */);
wrapper()->context()->AddProviderHost(std::move(host));
}
@@ -962,20 +967,20 @@ class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
FetchResult* out_result,
blink::ServiceWorkerStatusCode actual_status,
ServiceWorkerFetchDispatcher::FetchEventResult actual_result,
- const ServiceWorkerResponse& actual_response,
+ blink::mojom::FetchAPIResponsePtr actual_response,
blink::mojom::ServiceWorkerStreamHandlePtr /* stream */,
- blink::mojom::BlobPtr /* blob */,
scoped_refptr<ServiceWorkerVersion> worker) {
ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
ASSERT_TRUE(fetch_dispatcher_);
fetch_dispatcher_.reset();
out_result->status = actual_status;
out_result->result = actual_result;
- out_result->response = actual_response;
- if (!actual_response.blob_uuid.empty()) {
+ out_result->response = std::move(actual_response);
+ if (out_result->response->blob) {
+ DCHECK(!out_result->response->blob->uuid.empty());
out_result->blob_data_handle =
blob_context->context()->GetBlobDataFromUUID(
- actual_response.blob_uuid);
+ out_result->response->blob->uuid);
}
if (!quit.is_null())
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit);
@@ -1346,7 +1351,7 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, TimeoutWorkerInEvent) {
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, FetchEvent_Response) {
StartServerAndNavigateToSetup();
ServiceWorkerFetchDispatcher::FetchEventResult result;
- ServiceWorkerResponse response;
+ blink::mojom::FetchAPIResponsePtr response;
std::unique_ptr<storage::BlobDataHandle> blob_data_handle;
InstallTestHelper("/service_worker/fetch_event.js",
blink::ServiceWorkerStatusCode::kOk);
@@ -1356,12 +1361,12 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, FetchEvent_Response) {
FetchOnRegisteredWorker(&result, &response, &blob_data_handle);
ASSERT_EQ(ServiceWorkerFetchDispatcher::FetchEventResult::kGotResponse,
result);
- EXPECT_EQ(301, response.status_code);
- EXPECT_EQ("Moved Permanently", response.status_text);
- ServiceWorkerHeaderMap expected_headers;
+ EXPECT_EQ(301, response->status_code);
+ EXPECT_EQ("Moved Permanently", response->status_text);
+ base::flat_map<std::string, std::string> expected_headers;
expected_headers["content-language"] = "fi";
expected_headers["content-type"] = "text/html; charset=UTF-8";
- EXPECT_EQ(expected_headers, response.headers);
+ EXPECT_EQ(expected_headers, response->headers);
std::string body;
RunOnIOThread(base::BindOnce(&ReadResponseBody, &body,
@@ -1373,8 +1378,8 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
FetchEvent_ResponseViaCache) {
StartServerAndNavigateToSetup();
ServiceWorkerFetchDispatcher::FetchEventResult result;
- ServiceWorkerResponse response1;
- ServiceWorkerResponse response2;
+ blink::mojom::FetchAPIResponsePtr response1;
+ blink::mojom::FetchAPIResponsePtr response2;
std::unique_ptr<storage::BlobDataHandle> blob_data_handle;
const base::Time start_time(base::Time::Now());
InstallTestHelper("/service_worker/fetch_event_response_via_cache.js",
@@ -1385,27 +1390,29 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
FetchOnRegisteredWorker(&result, &response1, &blob_data_handle);
ASSERT_EQ(ServiceWorkerFetchDispatcher::FetchEventResult::kGotResponse,
result);
- EXPECT_EQ(200, response1.status_code);
- EXPECT_EQ("OK", response1.status_text);
- EXPECT_TRUE(response1.response_time >= start_time);
- EXPECT_FALSE(response1.is_in_cache_storage);
- EXPECT_EQ(std::string(), response2.cache_storage_cache_name);
+ EXPECT_EQ(200, response1->status_code);
+ EXPECT_EQ("OK", response1->status_text);
+ EXPECT_TRUE(response1->response_time >= start_time);
+ EXPECT_FALSE(response1->is_in_cache_storage);
+ ASSERT_TRUE(response1->cache_storage_cache_name);
+ EXPECT_EQ(std::string(), *response1->cache_storage_cache_name);
FetchOnRegisteredWorker(&result, &response2, &blob_data_handle);
ASSERT_EQ(ServiceWorkerFetchDispatcher::FetchEventResult::kGotResponse,
result);
- EXPECT_EQ(200, response2.status_code);
- EXPECT_EQ("OK", response2.status_text);
- EXPECT_EQ(response1.response_time, response2.response_time);
- EXPECT_TRUE(response2.is_in_cache_storage);
- EXPECT_EQ("cache_name", response2.cache_storage_cache_name);
+ EXPECT_EQ(200, response2->status_code);
+ EXPECT_EQ("OK", response2->status_text);
+ EXPECT_EQ(response1->response_time, response2->response_time);
+ EXPECT_TRUE(response2->is_in_cache_storage);
+ ASSERT_TRUE(response2->cache_storage_cache_name);
+ EXPECT_EQ("cache_name", *response2->cache_storage_cache_name);
}
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
FetchEvent_respondWithRejection) {
StartServerAndNavigateToSetup();
ServiceWorkerFetchDispatcher::FetchEventResult result;
- ServiceWorkerResponse response;
+ blink::mojom::FetchAPIResponsePtr response;
std::unique_ptr<storage::BlobDataHandle> blob_data_handle;
InstallTestHelper("/service_worker/fetch_event_rejected.js",
blink::ServiceWorkerStatusCode::kOk);
@@ -1432,7 +1439,7 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
ASSERT_EQ(ServiceWorkerFetchDispatcher::FetchEventResult::kGotResponse,
result);
- EXPECT_EQ(0, response.status_code);
+ EXPECT_EQ(0, response->status_code);
ASSERT_FALSE(blob_data_handle);
}
@@ -1733,6 +1740,90 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, Reload) {
run_loop.Run();
}
+// Test when the renderer requests termination because the service worker is
+// idle, and the browser ignores the request because DevTools is attached. The
+// renderer should continue processing events on the service worker instead of
+// waiting for termination or an event from the browser. Regression test for
+// https://crbug.com/878667.
+IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, IdleTimerWithDevTools) {
+ StartServerAndNavigateToSetup();
+
+ // This test is based on a new idle timer mechanism which is available only
+ // when S13nServiceWorker or NetworkService is enabled.
+ if (!blink::ServiceWorkerUtils::IsServicificationEnabled()) {
+ LOG(WARNING)
+ << "This test requires NetworkService or ServiceWorkerServicification.";
+ return;
+ }
+
+ // Register a service worker.
+ scoped_refptr<WorkerActivatedObserver> observer =
+ new WorkerActivatedObserver(wrapper());
+ observer->Init();
+ const GURL scope =
+ embedded_test_server()->GetURL("/service_worker/fetch_from_page.html");
+ const GURL worker_url = embedded_test_server()->GetURL(
+ "/service_worker/fetch_event_respond_with_fetch.js");
+
+ blink::mojom::ServiceWorkerRegistrationOptions options(
+ scope, blink::mojom::ServiceWorkerUpdateViaCache::kNone);
+ public_context()->RegisterServiceWorker(
+ worker_url, options,
+ base::BindOnce(&ExpectResultAndRun, true, base::DoNothing()));
+ observer->Wait();
+
+ // Navigate to a new page and request a sub resource. This should succeed
+ // normally.
+ {
+ const GURL url = embedded_test_server()->GetURL(
+ "/service_worker/fetch_from_page.html?url=/service_worker/empty.html");
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+ const base::string16 title = base::ASCIIToUTF16("DONE");
+ TitleWatcher watcher(shell()->web_contents(), title);
+ EXPECT_EQ(title, watcher.WaitAndGetTitle());
+ }
+
+ // Simulate to attach DevTools.
+ base::RunLoop loop;
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(
+ [](base::OnceClosure done, ServiceWorkerContextWrapper* wrapper,
+ int64_t version_id) {
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ scoped_refptr<ServiceWorkerVersion> version =
+ wrapper->GetLiveVersion(version_id);
+ version->SetDevToolsAttached(true);
+
+ // Set the idle timer delay to zero for making the service worker
+ // idle immediately. This may cause infinite loop of IPCs when no
+ // event was queued in the renderer because a callback of
+ // RequestTermination() is called and it triggers another
+ // RequestTermination() immediately. However, this is unusual
+ // situation happening only in testing so it's acceptable.
+ // In production code, WakeUp() as the result of
+ // RequestTermination() doesn't happen when the idle timer delay is
+ // set to zero. Instead, activating a new worker will be triggered.
+ version->endpoint()->SetIdleTimerDelayToZero();
+ std::move(done).Run();
+ },
+ loop.QuitClosure(), base::Unretained(wrapper()),
+ observer->version_id()));
+ loop.Run();
+
+ // Trigger another sub resource request. The sub resource request will
+ // directly go to the worker thread and be queued because the worker is
+ // idle. However, the browser process notifies the renderer to let it continue
+ // to work because DevTools is attached, and it'll result in running all
+ // queued events.
+ EXPECT_EQ(200, EvalJs(shell(), R"(
+ (async () => {
+ let response = await fetch(params.get('url'));
+ return response.status;
+ })()
+ )"));
+}
+
class ServiceWorkerNavigationPreloadTest : public ServiceWorkerBrowserTest {
public:
using self = ServiceWorkerNavigationPreloadTest;
@@ -1991,21 +2082,32 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerNavigationPreloadTest, NetworkFallback) {
EXPECT_EQ("Hello world.",
LoadNavigationPreloadTestPage(page_url, worker_url, "PASS"));
- // The page request must be sent once or twice:
+ // The page request can be sent one, two, or three times.
// - A navigation preload request may be sent. But it is possible that the
// navigation preload request is canceled before reaching the server.
// - A fallback request must be sent since respondWith wasn't used.
+ // - A second fallback request can be sent because the HttpCache may get
+ // confused when there are two concurrent requests (navigation preload and
+ // fallback) and one of them is cancelled (navigation preload). It restarts
+ // the ongoing request, possibly triggering another network request (see
+ // https://crbug.com/876911).
const int request_count = GetRequestCount(kPageUrl);
- ASSERT_TRUE(request_count == 1 || request_count == 2);
+ ASSERT_TRUE(request_count == 1 || request_count == 2 || request_count == 3)
+ << request_count;
if (request_count == 1) {
// Fallback request.
EXPECT_FALSE(HasNavigationPreloadHeader(request_log_[kPageUrl][0]));
- } else if (request_count == 2) {
+ } else {
// Navigation preload request.
ASSERT_TRUE(HasNavigationPreloadHeader(request_log_[kPageUrl][0]));
EXPECT_EQ("true", GetNavigationPreloadHeader(request_log_[kPageUrl][0]));
// Fallback request.
EXPECT_FALSE(HasNavigationPreloadHeader(request_log_[kPageUrl][1]));
+
+ // Additional fallback request when the HttpCache reissues a network
+ // request.
+ if (request_count == 3)
+ EXPECT_FALSE(HasNavigationPreloadHeader(request_log_[kPageUrl][2]));
}
}
@@ -2997,12 +3099,14 @@ class CacheStorageSideDataSizeChecker
const base::Closure& continuation,
CacheStorageCacheHandle cache_handle,
CacheStorageError error,
- std::unique_ptr<ServiceWorkerResponse> response) {
+ blink::mojom::FetchAPIResponsePtr response) {
ASSERT_EQ(CacheStorageError::kSuccess, error);
ASSERT_TRUE(response->blob);
- auto blob = response->blob;
- response->blob->get()->ReadSideData(base::BindLambdaForTesting(
- [blob, result,
+ blink::mojom::BlobPtr blob_ptr(std::move(response->blob->blob));
+ auto blob_handle =
+ base::MakeRefCounted<storage::BlobHandle>(std::move(blob_ptr));
+ blob_handle->get()->ReadSideData(base::BindLambdaForTesting(
+ [blob_handle, result,
continuation](const base::Optional<std::vector<uint8_t>>& data) {
if (data)
*result = data->size();
@@ -3216,4 +3320,268 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerDisableWebSecurityTest, UpdateNoCrash) {
RunTestWithCrossOriginURL(kPageUrl, kScopeUrl);
}
+class HeaderInjectingThrottle : public URLLoaderThrottle {
+ public:
+ HeaderInjectingThrottle() = default;
+ ~HeaderInjectingThrottle() override = default;
+
+ void WillStartRequest(network::ResourceRequest* request,
+ bool* defer) override {
+ GURL url = request->url;
+ if (url.query().find("PlzRedirect") != std::string::npos) {
+ GURL::Replacements replacements;
+ replacements.SetQueryStr("DidRedirect");
+ request->url = url.ReplaceComponents(replacements);
+ return;
+ }
+
+ request->headers.SetHeader("x-injected", "injected value");
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HeaderInjectingThrottle);
+};
+
+class ThrottlingContentBrowserClient : public TestContentBrowserClient {
+ public:
+ ThrottlingContentBrowserClient() : TestContentBrowserClient() {}
+ ~ThrottlingContentBrowserClient() override {}
+
+ // ContentBrowserClient overrides:
+ std::vector<std::unique_ptr<URLLoaderThrottle>> CreateURLLoaderThrottles(
+ const network::ResourceRequest& request,
+ ResourceContext* resource_context,
+ const base::RepeatingCallback<WebContents*()>& wc_getter,
+ NavigationUIData* navigation_ui_data,
+ int frame_tree_node_id) override {
+ std::vector<std::unique_ptr<URLLoaderThrottle>> throttles;
+ auto throttle = std::make_unique<HeaderInjectingThrottle>();
+ throttles.push_back(std::move(throttle));
+ return throttles;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ThrottlingContentBrowserClient);
+};
+
+class ServiceWorkerURLLoaderThrottleTest : public ServiceWorkerBrowserTest {
+ public:
+ ~ServiceWorkerURLLoaderThrottleTest() override {}
+
+ void SetUpOnMainThread() override {
+ ServiceWorkerBrowserTest::SetUpOnMainThread();
+ net::test_server::RegisterDefaultHandlers(embedded_test_server());
+ embedded_test_server()->StartAcceptingConnections();
+ }
+
+ void TearDownOnMainThread() override {
+ ServiceWorkerBrowserTest::TearDownOnMainThread();
+ }
+
+ void NavigateAndWaitForDone(const GURL& url) {
+ const base::string16 title = base::ASCIIToUTF16("DONE");
+ TitleWatcher watcher(shell()->web_contents(), title);
+ watcher.AlsoWaitForTitle(base::ASCIIToUTF16("ERROR"));
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+ EXPECT_EQ(title, watcher.WaitAndGetTitle());
+ }
+
+ void RegisterServiceWorker(const std::string& worker_url) {
+ GURL url = embedded_test_server()->GetURL(
+ "/service_worker/create_service_worker.html?worker_url=" + worker_url);
+ NavigateAndWaitForDone(url);
+ }
+
+ void RegisterServiceWorkerWithScope(const std::string& worker_url,
+ const std::string& scope) {
+ GURL url = embedded_test_server()->GetURL(
+ "/service_worker/create_service_worker.html?worker_url=" + worker_url +
+ "&scope=" + scope);
+ NavigateAndWaitForDone(url);
+ }
+};
+
+// Test that the throttles can inject headers during navigation that are
+// observable inside the service worker's fetch event.
+IN_PROC_BROWSER_TEST_F(ServiceWorkerURLLoaderThrottleTest,
+ FetchEventForNavigationHasThrottledRequest) {
+ // This tests throttling behavior which only has an effect on service worker
+ // interception when servicification is on.
+ if (!blink::ServiceWorkerUtils::IsServicificationEnabled()) {
+ LOG(WARNING)
+ << "This test requires NetworkService or ServiceWorkerServicification.";
+ return;
+ }
+
+ // Add a throttle which injects a header.
+ ThrottlingContentBrowserClient content_browser_client;
+ auto* old_content_browser_client =
+ SetBrowserClientForTesting(&content_browser_client);
+
+ // Register the service worker.
+ RegisterServiceWorker("/service_worker/echo_request_headers.js");
+
+ // Perform a navigation. Add "?dump_headers" to tell the service worker to
+ // respond with the request headers.
+ GURL url =
+ embedded_test_server()->GetURL("/service_worker/empty.html?dump_headers");
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+
+ // Extract the headers.
+ EvalJsResult result = EvalJs(shell()->web_contents()->GetMainFrame(),
+ "document.body.textContent");
+ ASSERT_TRUE(result.error.empty());
+ std::unique_ptr<base::DictionaryValue> dict = base::DictionaryValue::From(
+ base::JSONReader::Read(result.ExtractString()));
+ ASSERT_TRUE(dict);
+
+ // Default headers are present.
+ EXPECT_TRUE(CheckHeader(*dict, "accept", network::kFrameAcceptHeader));
+ // Injected headers are present.
+ EXPECT_TRUE(CheckHeader(*dict, "x-injected", "injected value"));
+
+ SetBrowserClientForTesting(old_content_browser_client);
+}
+
+// Test that redirects by throttles occur before service worker interception.
+IN_PROC_BROWSER_TEST_F(ServiceWorkerURLLoaderThrottleTest,
+ RedirectOccursBeforeFetchEvent) {
+ // This tests throttling behavior which only has an effect on service worker
+ // interception when servicification is on.
+ if (!blink::ServiceWorkerUtils::IsServicificationEnabled()) {
+ LOG(WARNING)
+ << "This test requires NetworkService or ServiceWorkerServicification.";
+ return;
+ }
+
+ // Add a throttle which performs a redirect.
+ ThrottlingContentBrowserClient content_browser_client;
+ auto* old_content_browser_client =
+ SetBrowserClientForTesting(&content_browser_client);
+
+ // Register the service worker.
+ RegisterServiceWorker("/service_worker/fetch_event_pass_through.js");
+
+ // Perform a navigation. Add "?PlzRedirect" to tell the throttle to
+ // redirect to another URL.
+ GURL url =
+ embedded_test_server()->GetURL("/service_worker/empty.html?PlzRedirect");
+ GURL redirect_url =
+ embedded_test_server()->GetURL("/service_worker/empty.html?DidRedirect");
+ NavigateToURLBlockUntilNavigationsComplete(shell(), url, 1);
+ EXPECT_EQ(redirect_url, shell()->web_contents()->GetLastCommittedURL());
+
+ // This script asks the service worker what fetch events it saw.
+ const std::string script = R"(
+ (async () => {
+ const saw_message = new Promise(resolve => {
+ navigator.serviceWorker.onmessage = event => {
+ resolve(event.data);
+ };
+ });
+ const registration = await navigator.serviceWorker.ready;
+ registration.active.postMessage('');
+ return await saw_message;
+ })();
+ )";
+
+ // Ensure the service worker did not see a fetch event for the PlzRedirect
+ // URL, since throttles should have redirected before interception.
+ base::Value list(base::Value::Type::LIST);
+ list.GetList().emplace_back(redirect_url.spec());
+ EXPECT_EQ(list, EvalJs(shell()->web_contents()->GetMainFrame(), script));
+
+ SetBrowserClientForTesting(old_content_browser_client);
+}
+
+// Test that the headers injected by throttles during navigation are
+// present in the network request in the case of network fallback.
+IN_PROC_BROWSER_TEST_F(
+ ServiceWorkerURLLoaderThrottleTest,
+ NavigationHasThrottledRequestHeadersAfterNetworkFallback) {
+ // This tests throttling behavior which only has an effect on service worker
+ // interception when servicification is on.
+ if (!blink::ServiceWorkerUtils::IsServicificationEnabled()) {
+ LOG(WARNING)
+ << "This test requires NetworkService or ServiceWorkerServicification.";
+ return;
+ }
+
+ // Add a throttle which injects a header.
+ ThrottlingContentBrowserClient content_browser_client;
+ auto* old_content_browser_client =
+ SetBrowserClientForTesting(&content_browser_client);
+
+ // Register the service worker. Use "/" scope so the "/echoheader" default
+ // handler of EmbeddedTestServer is in-scope.
+ RegisterServiceWorkerWithScope("/service_worker/fetch_event_pass_through.js",
+ "/");
+
+ // Perform a navigation. Use "/echoheader" which echoes the given header.
+ GURL url = embedded_test_server()->GetURL("/echoheader?x-injected");
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+
+ // Check that there is a controller to check that the test is really testing
+ // service worker network fallback.
+ EXPECT_EQ(true, EvalJs(shell()->web_contents()->GetMainFrame(),
+ "!!navigator.serviceWorker.controller"));
+
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ // The injected header should be present.
+ EXPECT_EQ("injected value", EvalJs(shell()->web_contents()->GetMainFrame(),
+ "document.body.textContent"));
+ } else {
+ // S13nServiceWorker: the injected header is not present. Throttle-modified
+ // headers are not propagated to network requests through
+ // ResourceDispatcherHost, because the legacy network code has its own code
+ // path that applies the same throttling independent from the navigation's
+ // URLLoaderThrottles.
+ DCHECK(base::FeatureList::IsEnabled(
+ blink::features::kServiceWorkerServicification));
+ EXPECT_EQ("None", EvalJs(shell()->web_contents()->GetMainFrame(),
+ "document.body.textContent"));
+ }
+
+ SetBrowserClientForTesting(old_content_browser_client);
+}
+
+// Test that the headers injected by throttles during navigation are
+// present in the navigation preload request.
+IN_PROC_BROWSER_TEST_F(ServiceWorkerURLLoaderThrottleTest,
+ NavigationPreloadHasThrottledRequestHeaders) {
+ // This tests throttling behavior which only has an effect on service worker
+ // interception when servicification is on.
+ if (!blink::ServiceWorkerUtils::IsServicificationEnabled()) {
+ LOG(WARNING)
+ << "This test requires NetworkService or ServiceWorkerServicification.";
+ return;
+ }
+
+ // Add a throttle which injects a header.
+ ThrottlingContentBrowserClient content_browser_client;
+ auto* old_content_browser_client =
+ SetBrowserClientForTesting(&content_browser_client);
+
+ // Register the service worker. Use "/" scope so the "/echoheader" default
+ // handler of EmbeddedTestServer is in-scope.
+ RegisterServiceWorkerWithScope("/service_worker/navigation_preload_worker.js",
+ "/");
+
+ // Perform a navigation. Use "/echoheader" which echoes the given header. The
+ // server responds to the navigation preload request with this echoed
+ // response, and the service worker responds with the navigation preload
+ // response.
+ //
+ // Also test that "Service-Worker-Navigation-Preload" is present to verify
+ // we are testing the navigation preload request.
+ GURL url = embedded_test_server()->GetURL(
+ "/echoheader?Service-Worker-Navigation-Preload&x-injected");
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+ EXPECT_EQ("true\ninjected value",
+ EvalJs(shell()->web_contents()->GetMainFrame(),
+ "document.body.textContent"));
+
+ SetBrowserClientForTesting(old_content_browser_client);
+}
+
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_cache_writer.cc b/chromium/content/browser/service_worker/service_worker_cache_writer.cc
index b58e6db84b0..2d43b2ec095 100644
--- a/chromium/content/browser/service_worker/service_worker_cache_writer.cc
+++ b/chromium/content/browser/service_worker/service_worker_cache_writer.cc
@@ -298,9 +298,7 @@ int ServiceWorkerCacheWriter::DoReadDataForCompareDone(int result) {
return net::OK;
}
- // bytes_compared_ only gets incremented when a full block is compared, to
- // avoid having to use only parts of the buffered network data.
- bytes_compared_ += result;
+ bytes_compared_ += compare_offset_;
state_ = STATE_DONE;
return net::OK;
}
diff --git a/chromium/content/browser/service_worker/service_worker_cache_writer.h b/chromium/content/browser/service_worker/service_worker_cache_writer.h
index 2f06d2c777c..e357240657f 100644
--- a/chromium/content/browser/service_worker/service_worker_cache_writer.h
+++ b/chromium/content/browser/service_worker/service_worker_cache_writer.h
@@ -202,14 +202,25 @@ class CONTENT_EXPORT ServiceWorkerCacheWriter {
size_t cached_length_;
+ // The amount of data from the network (|data_to_write_|) which has already
+ // been compared with data from storage (|data_to_read_|). This is
+ // initialized to 0 for every new arrival of network data.
+ size_t compare_offset_;
+
+ // Count of bytes which has been read from the network for comparison, and
+ // known as identical with the stored scripts. It is incremented only when a
+ // full block of network data is compared, to avoid having to use only
+ // fragments of the buffered network data.
size_t bytes_compared_;
+
+ // Count of bytes copied from |copy_reader_| to |writer_|.
size_t bytes_copied_;
+
+ // Count of bytes written back to |writer_|.
size_t bytes_written_;
bool did_replace_;
- size_t compare_offset_;
-
std::unique_ptr<ServiceWorkerResponseReader> compare_reader_;
std::unique_ptr<ServiceWorkerResponseReader> copy_reader_;
std::unique_ptr<ServiceWorkerResponseWriter> writer_;
diff --git a/chromium/content/browser/service_worker/service_worker_cache_writer_unittest.cc b/chromium/content/browser/service_worker/service_worker_cache_writer_unittest.cc
index c0a62ea2dcb..38d9f5c1f28 100644
--- a/chromium/content/browser/service_worker/service_worker_cache_writer_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_cache_writer_unittest.cc
@@ -832,5 +832,66 @@ TEST_F(ServiceWorkerCacheWriterTest, CompareFailedCopyLong) {
EXPECT_TRUE(copy_reader->AllExpectedReadsDone());
}
+// Tests behavior when the compare reader does not complete in single try and
+// needs to issue another read.
+TEST_F(ServiceWorkerCacheWriterTest, MultipleComparisonInSingleWrite) {
+ // Data for |compare_reader|.
+ const std::vector<std::string> data_from_cache{"a", "b", "c"};
+
+ // Data for |writer|. The first 2 bytes are provided in a larger chunk than
+ // the |compare_reader| does.
+ const std::vector<std::string> data_from_net{"ab", "x"};
+
+ // Data for |copy_reader|. The comparison between cache and network data fails
+ // at the 3rd byte, so the cache writer will read only first 2 bytes from the
+ // |copy_reader|.
+ const std::vector<std::string> data_to_copy{"ab"};
+
+ // The written data is expected to be identical with |data_from_net|.
+ const std::vector<std::string> data_expected{"ab", "x"};
+
+ size_t bytes_cached = 0;
+ size_t bytes_from_net = 0;
+ size_t bytes_common = 0;
+
+ for (const auto& data : data_from_cache)
+ bytes_cached += data.size();
+
+ for (const auto& data : data_from_net)
+ bytes_from_net += data.size();
+
+ for (const auto& data : data_to_copy)
+ bytes_common += data.size();
+
+ MockServiceWorkerResponseWriter* writer = ExpectWriter();
+ MockServiceWorkerResponseReader* compare_reader = ExpectReader();
+ MockServiceWorkerResponseReader* copy_reader = ExpectReader();
+
+ compare_reader->ExpectReadInfoOk(bytes_cached, false);
+ for (const auto& data : data_from_cache)
+ compare_reader->ExpectReadDataOk(data, false);
+
+ copy_reader->ExpectReadInfoOk(bytes_common, false);
+ for (const auto& data : data_to_copy)
+ copy_reader->ExpectReadDataOk(data, false);
+
+ writer->ExpectWriteInfoOk(bytes_from_net, false);
+ for (const auto& data : data_expected)
+ writer->ExpectWriteDataOk(data.size(), false);
+
+ Initialize();
+
+ net::Error error = WriteHeaders(bytes_from_net);
+ EXPECT_EQ(net::OK, error);
+ for (const auto& data : data_from_net) {
+ error = WriteData(data);
+ EXPECT_EQ(net::OK, error);
+ }
+
+ EXPECT_TRUE(writer->AllExpectedWritesDone());
+ EXPECT_TRUE(compare_reader->AllExpectedReadsDone());
+ EXPECT_TRUE(copy_reader->AllExpectedReadsDone());
+}
+
} // namespace
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_consts.cc b/chromium/content/browser/service_worker/service_worker_consts.cc
index 0a6663fa0c5..b149396d1c3 100644
--- a/chromium/content/browser/service_worker/service_worker_consts.cc
+++ b/chromium/content/browser/service_worker/service_worker_consts.cc
@@ -46,6 +46,9 @@ const char ServiceWorkerConsts::kSetNavigationPreloadHeaderErrorPrefix[] =
const char ServiceWorkerConsts::kShutdownErrorMessage[] =
"The Service Worker system has shutdown.";
+const char ServiceWorkerConsts::kUpdateTimeoutErrorMesage[] =
+ "Service worker self-update limit exceeded.";
+
const char ServiceWorkerConsts::kUserDeniedPermissionMessage[] =
"The user denied permission to use Service Worker.";
diff --git a/chromium/content/browser/service_worker/service_worker_consts.h b/chromium/content/browser/service_worker/service_worker_consts.h
index d119a472c79..1eab9d5b933 100644
--- a/chromium/content/browser/service_worker/service_worker_consts.h
+++ b/chromium/content/browser/service_worker/service_worker_consts.h
@@ -21,6 +21,7 @@ struct ServiceWorkerConsts {
static const char kNoDocumentURLErrorMessage[];
static const char kSetNavigationPreloadHeaderErrorPrefix[];
static const char kShutdownErrorMessage[];
+ static const char kUpdateTimeoutErrorMesage[];
static const char kUserDeniedPermissionMessage[];
};
diff --git a/chromium/content/browser/service_worker/service_worker_content_settings_proxy_impl.cc b/chromium/content/browser/service_worker/service_worker_content_settings_proxy_impl.cc
index e4b82677f15..3ba2c39cc15 100644
--- a/chromium/content/browser/service_worker/service_worker_content_settings_proxy_impl.cc
+++ b/chromium/content/browser/service_worker/service_worker_content_settings_proxy_impl.cc
@@ -4,9 +4,13 @@
#include "content/browser/service_worker/service_worker_content_settings_proxy_impl.h"
+#include <utility>
+#include <vector>
+
#include "base/threading/thread.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/global_routing_id.h"
#include "content/public/common/content_client.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
@@ -40,7 +44,7 @@ void ServiceWorkerContentSettingsProxyImpl::AllowIndexedDB(
// content setting. However, service worker is not necessarily associated
// with frames or making the request on behalf of frames,
// so just pass an empty |render_frames|.
- std::vector<std::pair<int, int>> render_frames;
+ std::vector<GlobalFrameRoutingId> render_frames;
std::move(callback).Run(GetContentClient()->browser()->AllowWorkerIndexedDB(
origin_.GetURL(), name, context_->wrapper()->resource_context(),
render_frames));
diff --git a/chromium/content/browser/service_worker/service_worker_context_core.cc b/chromium/content/browser/service_worker/service_worker_context_core.cc
index 8e6f44affb4..df3b6835062 100644
--- a/chromium/content/browser/service_worker/service_worker_context_core.cc
+++ b/chromium/content/browser/service_worker/service_worker_context_core.cc
@@ -21,6 +21,7 @@
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/service_worker/embedded_worker_registry.h"
#include "content/browser/service_worker/embedded_worker_status.h"
+#include "content/browser/service_worker/service_worker_consts.h"
#include "content/browser/service_worker/service_worker_context_core_observer.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_info.h"
@@ -197,6 +198,7 @@ class RegistrationDeletionListener
scoped_refptr<ServiceWorkerRegistration> registration_;
base::OnceClosure callback_;
};
+
} // namespace
const base::FilePath::CharType
@@ -442,6 +444,13 @@ void ServiceWorkerContextCore::RegisterServiceWorker(
const blink::mojom::ServiceWorkerRegistrationOptions& options,
RegistrationCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ std::string error_message;
+ if (!IsValidRegisterRequest(script_url, options.scope, &error_message)) {
+ std::move(callback).Run(
+ blink::ServiceWorkerStatusCode::kErrorInvalidArguments, error_message,
+ blink::mojom::kInvalidServiceWorkerRegistrationId);
+ return;
+ }
was_service_worker_registered_ = true;
job_coordinator_->Register(
script_url, options,
@@ -573,6 +582,26 @@ void ServiceWorkerContextCore::UnregistrationComplete(
}
}
+bool ServiceWorkerContextCore::IsValidRegisterRequest(
+ const GURL& script_url,
+ const GURL& scope_url,
+ std::string* out_error) const {
+ if (!scope_url.is_valid() || !script_url.is_valid()) {
+ *out_error = ServiceWorkerConsts::kBadMessageInvalidURL;
+ return false;
+ }
+ if (ServiceWorkerUtils::ContainsDisallowedCharacter(scope_url, script_url,
+ out_error)) {
+ return false;
+ }
+ std::vector<GURL> urls = {scope_url, script_url};
+ if (!ServiceWorkerUtils::AllOriginsMatchAndCanAccessServiceWorkers(urls)) {
+ *out_error = ServiceWorkerConsts::kBadMessageImproperOrigins;
+ return false;
+ }
+ return true;
+}
+
ServiceWorkerRegistration* ServiceWorkerContextCore::GetLiveRegistration(
int64_t id) {
RegistrationsMap::iterator it = live_registrations_.find(id);
@@ -749,7 +778,7 @@ void ServiceWorkerContextCore::OnVersionStateChanged(
ServiceWorkerVersion* version) {
observer_list_->Notify(
FROM_HERE, &ServiceWorkerContextCoreObserver::OnVersionStateChanged,
- version->version_id(), version->status());
+ version->version_id(), version->scope(), version->status());
}
void ServiceWorkerContextCore::OnDevToolsRoutingIdChanged(
@@ -807,9 +836,9 @@ void ServiceWorkerContextCore::OnControlleeAdded(
ServiceWorkerVersion* version,
const std::string& client_uuid,
const ServiceWorkerClientInfo& client_info) {
- observer_list_->Notify(FROM_HERE,
- &ServiceWorkerContextCoreObserver::OnControlleeAdded,
- version->version_id(), client_uuid, client_info);
+ observer_list_->Notify(
+ FROM_HERE, &ServiceWorkerContextCoreObserver::OnControlleeAdded,
+ version->version_id(), version->scope(), client_uuid, client_info);
}
void ServiceWorkerContextCore::OnControlleeRemoved(
@@ -817,7 +846,13 @@ void ServiceWorkerContextCore::OnControlleeRemoved(
const std::string& client_uuid) {
observer_list_->Notify(FROM_HERE,
&ServiceWorkerContextCoreObserver::OnControlleeRemoved,
- version->version_id(), client_uuid);
+ version->version_id(), version->scope(), client_uuid);
+}
+
+void ServiceWorkerContextCore::OnNoControllees(ServiceWorkerVersion* version) {
+ observer_list_->Notify(FROM_HERE,
+ &ServiceWorkerContextCoreObserver::OnNoControllees,
+ version->version_id(), version->scope());
}
ServiceWorkerProcessManager* ServiceWorkerContextCore::process_manager() {
diff --git a/chromium/content/browser/service_worker/service_worker_context_core.h b/chromium/content/browser/service_worker/service_worker_context_core.h
index 9a299aa9eb2..e75d5b6fd82 100644
--- a/chromium/content/browser/service_worker/service_worker_context_core.h
+++ b/chromium/content/browser/service_worker/service_worker_context_core.h
@@ -152,6 +152,7 @@ class CONTENT_EXPORT ServiceWorkerContextCore
const ServiceWorkerClientInfo& client_info) override;
void OnControlleeRemoved(ServiceWorkerVersion* version,
const std::string& client_uuid) override;
+ void OnNoControllees(ServiceWorkerVersion* version) override;
ServiceWorkerContextWrapper* wrapper() const { return wrapper_; }
ServiceWorkerStorage* storage() { return storage_.get(); }
@@ -318,6 +319,10 @@ class CONTENT_EXPORT ServiceWorkerContextCore
int64_t registration_id,
blink::ServiceWorkerStatusCode status);
+ bool IsValidRegisterRequest(const GURL& script_url,
+ const GURL& scope_url,
+ std::string* out_error) const;
+
void DidGetRegistrationsForDeleteForOrigin(
base::OnceCallback<void(blink::ServiceWorkerStatusCode)> callback,
blink::ServiceWorkerStatusCode status,
diff --git a/chromium/content/browser/service_worker/service_worker_context_core_observer.h b/chromium/content/browser/service_worker/service_worker_context_core_observer.h
index 0787d0ed5c3..cc4a5d6d6b2 100644
--- a/chromium/content/browser/service_worker/service_worker_context_core_observer.h
+++ b/chromium/content/browser/service_worker/service_worker_context_core_observer.h
@@ -64,6 +64,7 @@ class ServiceWorkerContextCoreObserver {
virtual void OnRunningStateChanged(int64_t version_id,
EmbeddedWorkerStatus running_status) {}
virtual void OnVersionStateChanged(int64_t version_id,
+ const GURL& scope,
ServiceWorkerVersion::Status status) {}
virtual void OnVersionDevToolsRoutingIdChanged(int64_t version_id,
int process_id,
@@ -76,10 +77,13 @@ class ServiceWorkerContextCoreObserver {
virtual void OnReportConsoleMessage(int64_t version_id,
const ConsoleMessage& message) {}
virtual void OnControlleeAdded(int64_t version_id,
+ const GURL& scope,
const std::string& uuid,
const ServiceWorkerClientInfo& info) {}
virtual void OnControlleeRemoved(int64_t version_id,
+ const GURL& scope,
const std::string& uuid) {}
+ virtual void OnNoControllees(int64_t version_id, const GURL& scope) {}
// Called when the ServiceWorkerContainer.register() promise is resolved.
//
// This is called before the service worker registration is persisted to
diff --git a/chromium/content/browser/service_worker/service_worker_context_request_handler.cc b/chromium/content/browser/service_worker/service_worker_context_request_handler.cc
index 1fcb4c80b49..1570948c6ef 100644
--- a/chromium/content/browser/service_worker/service_worker_context_request_handler.cc
+++ b/chromium/content/browser/service_worker/service_worker_context_request_handler.cc
@@ -67,8 +67,6 @@ std::string ServiceWorkerContextRequestHandler::CreateJobStatusToString(
return "ERROR_UNINSTALLED_SCRIPT_IMPORT";
case CreateJobStatus::ERROR_OUT_OF_RESOURCE_IDS:
return "ERROR_OUT_OF_RESOURCE_IDS";
- case CreateJobStatus::NUM_TYPES:
- NOTREACHED();
}
NOTREACHED() << static_cast<int>(status);
return "UNKNOWN";
diff --git a/chromium/content/browser/service_worker/service_worker_context_request_handler.h b/chromium/content/browser/service_worker/service_worker_context_request_handler.h
index 26bf3869d41..4c9fa5c784a 100644
--- a/chromium/content/browser/service_worker/service_worker_context_request_handler.h
+++ b/chromium/content/browser/service_worker/service_worker_context_request_handler.h
@@ -51,7 +51,7 @@ class CONTENT_EXPORT ServiceWorkerContextRequestHandler
ERROR_OUT_OF_RESOURCE_IDS,
// Add new types here.
- NUM_TYPES
+ kMaxValue = ERROR_OUT_OF_RESOURCE_IDS,
};
ServiceWorkerContextRequestHandler(
diff --git a/chromium/content/browser/service_worker/service_worker_context_request_handler_unittest.cc b/chromium/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
index cdf3aa4bb4c..692d21dc1f8 100644
--- a/chromium/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
@@ -31,6 +31,7 @@
#include "services/network/public/mojom/request_context_frame_type.mojom.h"
#include "storage/browser/blob/blob_storage_context.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
namespace content {
@@ -60,6 +61,11 @@ class ServiceWorkerContextRequestHandlerTest : public testing::Test {
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
void SetUp() override {
+ // ServiceWorkerContextRequestHandler is a non-S13nServiceWorker specific
+ // class and we don't use it when S13nServiceWorker is enabled.
+ scoped_feature_list_.InitAndDisableFeature(
+ blink::features::kServiceWorkerServicification);
+
helper_.reset(new EmbeddedWorkerTestHelper(base::FilePath()));
context()->storage()->LazyInitializeForTest(base::DoNothing());
base::RunLoop().RunUntilIdle();
@@ -156,6 +162,9 @@ class ServiceWorkerContextRequestHandlerTest : public testing::Test {
}
protected:
+ // |scoped_feature_list_| must be before |thread_bundle_|.
+ // See comments in ServiceWorkerProviderHostTest.
+ base::test::ScopedFeatureList scoped_feature_list_;
TestBrowserThreadBundle browser_thread_bundle_;
std::unique_ptr<EmbeddedWorkerTestHelper> helper_;
scoped_refptr<ServiceWorkerRegistration> registration_;
diff --git a/chromium/content/browser/service_worker/service_worker_context_unittest.cc b/chromium/content/browser/service_worker/service_worker_context_unittest.cc
index f7c92935136..7ca85191c7b 100644
--- a/chromium/content/browser/service_worker/service_worker_context_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_context_unittest.cc
@@ -20,7 +20,7 @@
#include "content/browser/service_worker/service_worker_storage.h"
#include "content/browser/service_worker/service_worker_test_utils.h"
#include "content/browser/service_worker/service_worker_version.h"
-#include "content/common/service_worker/service_worker_messages.h"
+#include "content/public/browser/service_worker_context_observer.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -169,6 +169,9 @@ class ServiceWorkerContextTest : public ServiceWorkerContextCoreObserver,
}
ServiceWorkerContextCore* context() { return helper_->context(); }
+ ServiceWorkerContextWrapper* context_wrapper() {
+ return helper_->context_wrapper();
+ }
protected:
TestBrowserThreadBundle browser_thread_bundle_;
@@ -205,6 +208,182 @@ class RecordableEmbeddedWorkerInstanceClient
DISALLOW_COPY_AND_ASSIGN(RecordableEmbeddedWorkerInstanceClient);
};
+class TestServiceWorkerContextObserver : public ServiceWorkerContextObserver {
+ public:
+ enum class EventType {
+ RegistrationCompleted,
+ VersionActivated,
+ VersionRedundant,
+ NoControllees
+ };
+ struct EventLog {
+ EventType type;
+ base::Optional<GURL> url;
+ base::Optional<int64_t> version_id;
+ };
+
+ explicit TestServiceWorkerContextObserver(ServiceWorkerContext* context)
+ : context_(context) {
+ context_->AddObserver(this);
+ };
+
+ ~TestServiceWorkerContextObserver() override {
+ context_->RemoveObserver(this);
+ }
+
+ void OnRegistrationCompleted(const GURL& scope) override {
+ EventLog log;
+ log.type = EventType::RegistrationCompleted;
+ log.url = scope;
+ events_.push_back(log);
+ }
+
+ void OnVersionActivated(int64_t version_id, const GURL& scope) override {
+ EventLog log;
+ log.type = EventType::VersionActivated;
+ log.version_id = version_id;
+ log.url = scope;
+ events_.push_back(log);
+ }
+
+ void OnVersionRedundant(int64_t version_id, const GURL& scope) override {
+ EventLog log;
+ log.type = EventType::VersionRedundant;
+ log.version_id = version_id;
+ log.url = scope;
+ events_.push_back(log);
+ }
+
+ void OnNoControllees(int64_t version_id, const GURL& scope) override {
+ EventLog log;
+ log.type = EventType::NoControllees;
+ log.version_id = version_id;
+ log.url = scope;
+ events_.push_back(log);
+ }
+
+ const std::vector<EventLog>& events() { return events_; }
+
+ private:
+ ServiceWorkerContext* context_;
+ std::vector<EventLog> events_;
+ DISALLOW_COPY_AND_ASSIGN(TestServiceWorkerContextObserver);
+};
+
+// Make sure OnRegistrationCompleted is called on observer.
+TEST_F(ServiceWorkerContextTest, RegistrationCompletedObserver) {
+ GURL pattern("https://www.example.com/");
+ GURL script_url("https://www.example.com/service_worker.js");
+ blink::mojom::ServiceWorkerRegistrationOptions options;
+ options.scope = pattern;
+
+ TestServiceWorkerContextObserver observer(context_wrapper());
+
+ int64_t registration_id = blink::mojom::kInvalidServiceWorkerRegistrationId;
+ bool called = false;
+ context()->RegisterServiceWorker(
+ script_url, options, MakeRegisteredCallback(&called, &registration_id));
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_TRUE(called);
+ EXPECT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, registration_id);
+ ASSERT_EQ(2u, observer.events().size());
+ EXPECT_EQ(TestServiceWorkerContextObserver::EventType::RegistrationCompleted,
+ observer.events()[0].type);
+ EXPECT_EQ(pattern, observer.events()[0].url);
+ EXPECT_EQ(TestServiceWorkerContextObserver::EventType::VersionActivated,
+ observer.events()[1].type);
+ EXPECT_EQ(pattern, observer.events()[1].url);
+}
+
+// Make sure OnNoControllees is called on observer.
+TEST_F(ServiceWorkerContextTest, NoControlleesObserver) {
+ GURL pattern("https://www.example.com/");
+ GURL script_url("https://www.example.com/service_worker.js");
+ blink::mojom::ServiceWorkerRegistrationOptions options;
+ options.scope = pattern;
+
+ auto registration = base::MakeRefCounted<ServiceWorkerRegistration>(
+ options, 1l /* dummy registration id */, context()->AsWeakPtr());
+
+ auto version = base::MakeRefCounted<ServiceWorkerVersion>(
+ registration.get(), script_url, 2l /* dummy version id */,
+ context()->AsWeakPtr());
+
+ ServiceWorkerRemoteProviderEndpoint endpoint;
+ std::unique_ptr<ServiceWorkerProviderHost> host =
+ CreateProviderHostForWindow(helper_->mock_render_process_id(), 1, true,
+ context()->AsWeakPtr(), &endpoint);
+
+ version->AddControllee(host.get());
+ base::RunLoop().RunUntilIdle();
+
+ TestServiceWorkerContextObserver observer(context_wrapper());
+
+ version->RemoveControllee(host->client_uuid());
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_EQ(1u, observer.events().size());
+ EXPECT_EQ(TestServiceWorkerContextObserver::EventType::NoControllees,
+ observer.events()[0].type);
+ EXPECT_EQ(pattern, observer.events()[0].url);
+ EXPECT_EQ(2l, observer.events()[0].version_id);
+}
+
+// Make sure OnVersionActivated is called on observer.
+TEST_F(ServiceWorkerContextTest, VersionActivatedObserver) {
+ GURL pattern("https://www.example.com/");
+ GURL script_url("https://www.example.com/service_worker.js");
+ blink::mojom::ServiceWorkerRegistrationOptions options;
+ options.scope = pattern;
+
+ auto registration = base::MakeRefCounted<ServiceWorkerRegistration>(
+ options, 1l /* dummy registration id */, context()->AsWeakPtr());
+
+ auto version = base::MakeRefCounted<ServiceWorkerVersion>(
+ registration.get(), script_url, 2l /* dummy version id */,
+ context()->AsWeakPtr());
+
+ TestServiceWorkerContextObserver observer(context_wrapper());
+
+ version->set_fetch_handler_existence(
+ ServiceWorkerVersion::FetchHandlerExistence::DOES_NOT_EXIST);
+ version->SetStatus(ServiceWorkerVersion::Status::ACTIVATED);
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_EQ(1u, observer.events().size());
+ EXPECT_EQ(TestServiceWorkerContextObserver::EventType::VersionActivated,
+ observer.events()[0].type);
+ EXPECT_EQ(2l, observer.events()[0].version_id);
+}
+
+// Make sure OnVersionRedundant is called on observer.
+TEST_F(ServiceWorkerContextTest, VersionRedundantObserver) {
+ GURL pattern("https://www.example.com/");
+ GURL script_url("https://www.example.com/service_worker.js");
+ blink::mojom::ServiceWorkerRegistrationOptions options;
+ options.scope = pattern;
+
+ auto registration = base::MakeRefCounted<ServiceWorkerRegistration>(
+ options, 1l /* dummy registration id */, context()->AsWeakPtr());
+
+ auto version = base::MakeRefCounted<ServiceWorkerVersion>(
+ registration.get(), script_url, 2l /* dummy version id */,
+ context()->AsWeakPtr());
+
+ TestServiceWorkerContextObserver observer(context_wrapper());
+
+ version->set_fetch_handler_existence(
+ ServiceWorkerVersion::FetchHandlerExistence::DOES_NOT_EXIST);
+ version->SetStatus(ServiceWorkerVersion::Status::REDUNDANT);
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_EQ(1u, observer.events().size());
+ EXPECT_EQ(TestServiceWorkerContextObserver::EventType::VersionRedundant,
+ observer.events()[0].type);
+ EXPECT_EQ(2l, observer.events()[0].version_id);
+}
+
// Make sure basic registration is working.
TEST_F(ServiceWorkerContextTest, Register) {
GURL pattern("https://www.example.com/");
diff --git a/chromium/content/browser/service_worker/service_worker_context_watcher.cc b/chromium/content/browser/service_worker/service_worker_context_watcher.cc
index 5bb4c8f5527..93255031e6d 100644
--- a/chromium/content/browser/service_worker/service_worker_context_watcher.cc
+++ b/chromium/content/browser/service_worker/service_worker_context_watcher.cc
@@ -248,6 +248,7 @@ void ServiceWorkerContextWatcher::OnRunningStateChanged(
void ServiceWorkerContextWatcher::OnVersionStateChanged(
int64_t version_id,
+ const GURL& scope,
content::ServiceWorkerVersion::Status status) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
auto it = version_info_map_.find(version_id);
@@ -332,6 +333,7 @@ void ServiceWorkerContextWatcher::OnReportConsoleMessage(
void ServiceWorkerContextWatcher::OnControlleeAdded(
int64_t version_id,
+ const GURL& scope,
const std::string& uuid,
const ServiceWorkerClientInfo& info) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -344,6 +346,7 @@ void ServiceWorkerContextWatcher::OnControlleeAdded(
}
void ServiceWorkerContextWatcher::OnControlleeRemoved(int64_t version_id,
+ const GURL& scope,
const std::string& uuid) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
auto it = version_info_map_.find(version_id);
diff --git a/chromium/content/browser/service_worker/service_worker_context_watcher.h b/chromium/content/browser/service_worker/service_worker_context_watcher.h
index 1eb56b76459..3d3e20c248d 100644
--- a/chromium/content/browser/service_worker/service_worker_context_watcher.h
+++ b/chromium/content/browser/service_worker/service_worker_context_watcher.h
@@ -89,6 +89,7 @@ class CONTENT_EXPORT ServiceWorkerContextWatcher
content::EmbeddedWorkerStatus running_status) override;
void OnVersionStateChanged(
int64_t version_id,
+ const GURL& scope,
content::ServiceWorkerVersion::Status status) override;
void OnVersionDevToolsRoutingIdChanged(int64_t version_id,
int process_id,
@@ -102,9 +103,11 @@ class CONTENT_EXPORT ServiceWorkerContextWatcher
void OnReportConsoleMessage(int64_t version_id,
const ConsoleMessage& message) override;
void OnControlleeAdded(int64_t version_id,
+ const GURL& scope,
const std::string& uuid,
const ServiceWorkerClientInfo& info) override;
void OnControlleeRemoved(int64_t version_id,
+ const GURL& scope,
const std::string& uuid) override;
void OnRegistrationCompleted(int64_t registration_id,
const GURL& pattern) override;
diff --git a/chromium/content/browser/service_worker/service_worker_context_wrapper.cc b/chromium/content/browser/service_worker/service_worker_context_wrapper.cc
index 9927359ee1b..4203d20bd22 100644
--- a/chromium/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/chromium/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -12,12 +12,14 @@
#include "base/barrier_closure.h"
#include "base/bind.h"
+#include "base/feature_list.h"
#include "base/files/file_path.h"
+#include "base/guid.h"
#include "base/lazy_instance.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/single_thread_task_runner.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/browser/service_worker/embedded_worker_status.h"
#include "content/browser/service_worker/service_worker_process_manager.h"
@@ -28,19 +30,21 @@
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/service_worker_context_observer.h"
+#include "content/public/common/content_features.h"
#include "net/base/url_util.h"
#include "storage/browser/quota/quota_manager_proxy.h"
#include "storage/browser/quota/special_storage_policy.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
+#include "url/gurl.h"
namespace content {
namespace {
-typedef std::set<std::string> HeaderNameSet;
-base::LazyInstance<HeaderNameSet>::DestructorAtExit g_excluded_header_name_set =
- LAZY_INSTANCE_INITIALIZER;
+// Value used to set the timeout when starting a long running ServiceWorker. See
+// ServiceWorkerContextWrapper::StartServiceWorkerAndDispatchLongRunningMessage.
+const int kActiveWorkerTimeoutDays = 999;
void WorkerStarted(ServiceWorkerContextWrapper::StatusCallback callback,
blink::ServiceWorkerStatusCode status) {
@@ -90,7 +94,9 @@ void DidStartWorker(scoped_refptr<ServiceWorkerVersion> version,
return;
}
EmbeddedWorkerInstance* instance = version->embedded_worker();
- std::move(info_callback).Run(instance->process_id(), instance->thread_id());
+ std::move(info_callback)
+ .Run(version->version_id(), instance->process_id(),
+ instance->thread_id());
}
void FoundRegistrationForStartWorker(
@@ -152,29 +158,37 @@ void FinishUnregistrationOnIO(ServiceWorkerContext::ResultCallback callback,
status == blink::ServiceWorkerStatusCode::kOk));
}
-} // namespace
-
-// static
-void ServiceWorkerContext::AddExcludedHeadersForFetchEvent(
- const std::set<std::string>& header_names) {
+void MessageFinishedSending(ServiceWorkerContext::ResultCallback callback,
+ blink::ServiceWorkerStatusCode status) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- g_excluded_header_name_set.Get().insert(header_names.begin(),
- header_names.end());
+ std::move(callback).Run(status == blink::ServiceWorkerStatusCode::kOk);
}
-// static
-bool ServiceWorkerContext::IsExcludedHeaderNameForFetchEvent(
- const std::string& header_name) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- return g_excluded_header_name_set.Get().find(header_name) !=
- g_excluded_header_name_set.Get().end();
+void RunOnceClosure(scoped_refptr<ServiceWorkerContextWrapper> ref_holder,
+ base::OnceClosure task) {
+ std::move(task).Run();
}
+} // namespace
+
// static
bool ServiceWorkerContext::ScopeMatches(const GURL& scope, const GURL& url) {
return ServiceWorkerUtils::ScopeMatches(scope, url);
}
+// static
+void ServiceWorkerContext::RunTask(
+ scoped_refptr<base::SequencedTaskRunner> task_runner,
+ const base::Location& from_here,
+ ServiceWorkerContext* service_worker_context,
+ base::OnceClosure task) {
+ auto ref = base::WrapRefCounted(
+ static_cast<ServiceWorkerContextWrapper*>(service_worker_context));
+ task_runner->PostTask(
+ from_here,
+ base::BindOnce(&RunOnceClosure, std::move(ref), std::move(task)));
+}
+
ServiceWorkerContextWrapper::ServiceWorkerContextWrapper(
BrowserContext* browser_context)
: core_observer_list_(
@@ -262,6 +276,25 @@ void ServiceWorkerContextWrapper::OnRegistrationCompleted(
observer.OnRegistrationCompleted(pattern);
}
+void ServiceWorkerContextWrapper::OnNoControllees(int64_t version_id,
+ const GURL& scope) {
+ for (auto& observer : observer_list_)
+ observer.OnNoControllees(version_id, scope);
+}
+
+void ServiceWorkerContextWrapper::OnVersionStateChanged(
+ int64_t version_id,
+ const GURL& scope,
+ ServiceWorkerVersion::Status status) {
+ if (status == ServiceWorkerVersion::Status::ACTIVATED) {
+ for (auto& observer : observer_list_)
+ observer.OnVersionActivated(version_id, scope);
+ } else if (status == ServiceWorkerVersion::Status::REDUNDANT) {
+ for (auto& observer : observer_list_)
+ observer.OnVersionRedundant(version_id, scope);
+ }
+}
+
void ServiceWorkerContextWrapper::AddObserver(
ServiceWorkerContextObserver* observer) {
observer_list_.AddObserver(observer);
@@ -434,6 +467,84 @@ void ServiceWorkerContextWrapper::StartWorkerForPattern(
std::move(failure_callback)));
}
+void ServiceWorkerContextWrapper::
+ StartServiceWorkerAndDispatchLongRunningMessage(
+ const GURL& pattern,
+ blink::TransferableMessage message,
+ ResultCallback result_callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ if (!base::FeatureList::IsEnabled(
+ features::kServiceWorkerLongRunningMessage)) {
+ std::move(result_callback).Run(false);
+ return;
+ }
+
+ if (!context_core_) {
+ std::move(result_callback).Run(false);
+ return;
+ }
+
+ context_core_->storage()->FindRegistrationForPattern(
+ net::SimplifyUrlForRequest(pattern),
+ base::BindOnce(&ServiceWorkerContextWrapper::
+ DidFindRegistrationForLongRunningMessage,
+ this, std::move(message), pattern,
+ std::move(result_callback)));
+}
+
+void ServiceWorkerContextWrapper::DidFindRegistrationForLongRunningMessage(
+ blink::TransferableMessage message,
+ const GURL& source_origin,
+ ResultCallback result_callback,
+ blink::ServiceWorkerStatusCode service_worker_status,
+ scoped_refptr<ServiceWorkerRegistration> registration) {
+ if (service_worker_status != blink::ServiceWorkerStatusCode::kOk) {
+ LOG(WARNING) << "No registration available, status: "
+ << static_cast<int>(service_worker_status);
+ std::move(result_callback).Run(false);
+ return;
+ }
+ registration->active_version()->StartWorker(
+ ServiceWorkerMetrics::EventType::LONG_RUNNING_MESSAGE,
+ base::BindOnce(&ServiceWorkerContextWrapper::
+ DidStartServiceWorkerForLongRunningMessage,
+ this, std::move(message), source_origin, registration,
+ std::move(result_callback)));
+}
+
+void ServiceWorkerContextWrapper::DidStartServiceWorkerForLongRunningMessage(
+ blink::TransferableMessage message,
+ const GURL& source_origin,
+ scoped_refptr<ServiceWorkerRegistration> registration,
+ ResultCallback result_callback,
+ blink::ServiceWorkerStatusCode status) {
+ if (status != blink::ServiceWorkerStatusCode::kOk) {
+ std::move(result_callback).Run(false);
+ return;
+ }
+
+ scoped_refptr<ServiceWorkerVersion> version = registration->active_version();
+
+ int request_id = version->StartRequestWithCustomTimeout(
+ ServiceWorkerMetrics::EventType::LONG_RUNNING_MESSAGE,
+ base::BindOnce(&MessageFinishedSending, std::move(result_callback)),
+ base::TimeDelta::FromDays(kActiveWorkerTimeoutDays),
+ ServiceWorkerVersion::CONTINUE_ON_TIMEOUT);
+
+ mojom::ExtendableMessageEventPtr event = mojom::ExtendableMessageEvent::New();
+ event->message = std::move(message);
+ event->source_origin = url::Origin::Create(source_origin);
+ event->source_info_for_service_worker =
+ version->provider_host()
+ ->GetOrCreateServiceWorkerObjectHost(version)
+ ->CreateCompleteObjectInfoToSend();
+
+ version->endpoint()->DispatchExtendableMessageEventWithCustomTimeout(
+ std::move(event), base::TimeDelta::FromDays(kActiveWorkerTimeoutDays),
+ version->CreateSimpleEventCallback(request_id));
+}
+
void ServiceWorkerContextWrapper::StartServiceWorkerForNavigationHint(
const GURL& document_url,
StartServiceWorkerForNavigationHintCallback callback) {
@@ -530,20 +641,20 @@ void ServiceWorkerContextWrapper::HasMainFrameProviderHost(
context_core_->HasMainFrameProviderHost(origin, std::move(callback));
}
-std::unique_ptr<std::vector<std::pair<int, int>>>
+std::unique_ptr<std::vector<GlobalFrameRoutingId>>
ServiceWorkerContextWrapper::GetProviderHostIds(const GURL& origin) const {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- std::unique_ptr<std::vector<std::pair<int, int>>> provider_host_ids(
- new std::vector<std::pair<int, int>>());
+ std::unique_ptr<std::vector<GlobalFrameRoutingId>> provider_host_ids(
+ new std::vector<GlobalFrameRoutingId>());
for (std::unique_ptr<ServiceWorkerContextCore::ProviderHostIterator> it =
context_core_->GetClientProviderHostIterator(
origin, false /* include_reserved_clients */);
!it->IsAtEnd(); it->Advance()) {
ServiceWorkerProviderHost* provider_host = it->GetProviderHost();
- provider_host_ids->push_back(
- std::make_pair(provider_host->process_id(), provider_host->frame_id()));
+ provider_host_ids->push_back(GlobalFrameRoutingId(
+ provider_host->process_id(), provider_host->frame_id()));
}
return provider_host_ids;
diff --git a/chromium/content/browser/service_worker/service_worker_context_wrapper.h b/chromium/content/browser/service_worker/service_worker_context_wrapper.h
index f1b9b94c5cc..7766bd2311a 100644
--- a/chromium/content/browser/service_worker/service_worker_context_wrapper.h
+++ b/chromium/content/browser/service_worker/service_worker_context_wrapper.h
@@ -19,6 +19,7 @@
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_context_core_observer.h"
#include "content/common/content_export.h"
+#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/service_worker_context.h"
namespace base {
@@ -101,6 +102,10 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
// ServiceWorkerContextCoreObserver implementation:
void OnRegistrationCompleted(int64_t registration_id,
const GURL& pattern) override;
+ void OnNoControllees(int64_t version_id, const GURL& scope) override;
+ void OnVersionStateChanged(int64_t version_id,
+ const GURL& scope,
+ ServiceWorkerVersion::Status status) override;
// ServiceWorkerContext implementation:
void AddObserver(ServiceWorkerContextObserver* observer) override;
@@ -127,6 +132,10 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
void StartWorkerForPattern(const GURL& pattern,
StartWorkerCallback info_callback,
base::OnceClosure failure_callback) override;
+ void StartServiceWorkerAndDispatchLongRunningMessage(
+ const GURL& pattern,
+ blink::TransferableMessage message,
+ ResultCallback result_callback) override;
void StartServiceWorkerForNavigationHint(
const GURL& document_url,
StartServiceWorkerForNavigationHintCallback callback) override;
@@ -143,10 +152,9 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
void HasMainFrameProviderHost(const GURL& origin,
BoolCallback callback) const;
- // Returns all render process ids and frame ids for the given |origin|.
- std::unique_ptr<
- std::vector<std::pair<int /* render process id */, int /* frame id */>>>
- GetProviderHostIds(const GURL& origin) const;
+ // Returns all frame ids for the given |origin|.
+ std::unique_ptr<std::vector<GlobalFrameRoutingId>> GetProviderHostIds(
+ const GURL& origin) const;
// Returns the registration whose scope longest matches |document_url|. It is
// guaranteed that the returned registration has the activated worker.
@@ -354,6 +362,27 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
base::OnceClosure callback,
scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_callback);
+ void DidFindRegistrationForLongRunningMessage(
+ blink::TransferableMessage message,
+ const GURL& source_origin,
+ ResultCallback result_callback,
+ blink::ServiceWorkerStatusCode service_worker_status,
+ scoped_refptr<ServiceWorkerRegistration> registration);
+
+ void DidStartServiceWorkerForLongRunningMessage(
+ blink::TransferableMessage message,
+ const GURL& source_origin,
+ scoped_refptr<ServiceWorkerRegistration> registration,
+ ServiceWorkerContext::ResultCallback result_callback,
+ blink::ServiceWorkerStatusCode service_worker_status);
+
+ void SendActiveWorkerMessage(
+ blink::TransferableMessage message,
+ const GURL& source_origin,
+ ServiceWorkerContext::ResultCallback result_callback,
+ blink::ServiceWorkerStatusCode status,
+ scoped_refptr<ServiceWorkerRegistration> registration);
+
// The core context is only for use on the IO thread.
// Can be null before/during init, during/after shutdown, and after
// DeleteAndStartOver fails.
@@ -367,7 +396,7 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
// Observers which live outside content's implementation boundary. Observer
// methods will always be dispatched on the UI thread.
- base::ObserverList<ServiceWorkerContextObserver> observer_list_;
+ base::ObserverList<ServiceWorkerContextObserver>::Unchecked observer_list_;
const std::unique_ptr<ServiceWorkerProcessManager> process_manager_;
// Cleared in ShutdownOnIO():
diff --git a/chromium/content/browser/service_worker/service_worker_controllee_request_handler.cc b/chromium/content/browser/service_worker/service_worker_controllee_request_handler.cc
index dc214676e02..8c7859bfbe6 100644
--- a/chromium/content/browser/service_worker/service_worker_controllee_request_handler.cc
+++ b/chromium/content/browser/service_worker/service_worker_controllee_request_handler.cc
@@ -4,9 +4,8 @@
#include "content/browser/service_worker/service_worker_controllee_request_handler.h"
-#include <memory>
#include <set>
-#include <string>
+#include <utility>
#include "base/trace_event/trace_event.h"
#include "components/offline_pages/buildflags/buildflags.h"
@@ -72,13 +71,73 @@ bool ShouldFallbackToLoadOfflinePage(
return false;
}
offline_pages::OfflinePageHeader offline_header(offline_header_value);
- return offline_header.reason ==
- offline_pages::OfflinePageHeader::Reason::DOWNLOAD;
+ return offline_header.reason !=
+ offline_pages::OfflinePageHeader::Reason::NONE &&
+ offline_header.reason !=
+ offline_pages::OfflinePageHeader::Reason::RELOAD;
}
#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES)
} // namespace
+// RAII class that disallows calling SetControllerRegistration() on a provider
+// host.
+class ServiceWorkerControlleeRequestHandler::
+ ScopedDisallowSetControllerRegistration {
+ public:
+ explicit ScopedDisallowSetControllerRegistration(
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host)
+ : provider_host_(std::move(provider_host)) {
+ DCHECK(provider_host_->IsSetControllerRegistrationAllowed())
+ << "The host already disallows using a registration; nested disallow "
+ "is not supported.";
+ provider_host_->AllowSetControllerRegistration(false);
+ }
+
+ ~ScopedDisallowSetControllerRegistration() {
+ if (!provider_host_)
+ return;
+ DCHECK(!provider_host_->IsSetControllerRegistrationAllowed())
+ << "Failed to disallow using a registration.";
+ provider_host_->AllowSetControllerRegistration(true);
+ }
+
+ private:
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedDisallowSetControllerRegistration);
+};
+
+class ServiceWorkerControlleeRequestHandler::MainResourceRequestTracker {
+ public:
+ MainResourceRequestTracker() = default;
+
+ ~MainResourceRequestTracker() {
+ if (recorded_destination_)
+ return;
+ RecordDestination(
+ will_dispatch_fetch_
+ ? ServiceWorkerMetrics::MainResourceRequestDestination::
+ kAbortedWhileDispatchingFetchEvent
+ : ServiceWorkerMetrics::MainResourceRequestDestination::
+ kAbortedWithoutDispatchingFetchEvent);
+ }
+
+ void RecordDestination(
+ ServiceWorkerMetrics::MainResourceRequestDestination destination) {
+ CHECK(!recorded_destination_);
+ recorded_destination_ = true;
+ ServiceWorkerMetrics::RecordMainResourceRequestDestination(destination);
+ }
+
+ void WillDispatchFetchEvent() { will_dispatch_fetch_ = true; }
+
+ private:
+ bool recorded_destination_ = false;
+ bool will_dispatch_fetch_ = false;
+ DISALLOW_COPY_AND_ASSIGN(MainResourceRequestTracker);
+};
+
ServiceWorkerControlleeRequestHandler::ServiceWorkerControlleeRequestHandler(
base::WeakPtr<ServiceWorkerContextCore> context,
base::WeakPtr<ServiceWorkerProviderHost> provider_host,
@@ -92,14 +151,13 @@ ServiceWorkerControlleeRequestHandler::ServiceWorkerControlleeRequestHandler(
RequestContextType request_context_type,
network::mojom::RequestContextFrameType frame_type,
scoped_refptr<network::ResourceRequestBody> body)
- : ServiceWorkerRequestHandler(context,
- provider_host,
- blob_storage_context,
+ : ServiceWorkerRequestHandler(std::move(context),
+ std::move(provider_host),
+ std::move(blob_storage_context),
resource_type),
resource_type_(resource_type),
is_main_resource_load_(
ServiceWorkerUtils::IsMainResourceType(resource_type)),
- is_main_frame_load_(resource_type == RESOURCE_TYPE_MAIN_FRAME),
request_mode_(request_mode),
credentials_mode_(credentials_mode),
redirect_mode_(redirect_mode),
@@ -107,7 +165,7 @@ ServiceWorkerControlleeRequestHandler::ServiceWorkerControlleeRequestHandler(
keepalive_(keepalive),
request_context_type_(request_context_type),
frame_type_(frame_type),
- body_(body),
+ body_(std::move(body)),
force_update_started_(false),
use_network_(false),
weak_factory_(this) {}
@@ -115,13 +173,10 @@ ServiceWorkerControlleeRequestHandler::ServiceWorkerControlleeRequestHandler(
ServiceWorkerControlleeRequestHandler::
~ServiceWorkerControlleeRequestHandler() {
MaybeScheduleUpdate();
-
- if (is_main_resource_load_ && provider_host_)
- provider_host_->SetAllowAssociation(true);
}
void ServiceWorkerControlleeRequestHandler::MaybeScheduleUpdate() {
- if (!provider_host_ || !provider_host_->active_version())
+ if (!provider_host_ || !provider_host_->controller())
return;
if (blink::ServiceWorkerUtils::IsServicificationEnabled()) {
@@ -145,9 +200,9 @@ void ServiceWorkerControlleeRequestHandler::MaybeScheduleUpdate() {
return;
if (is_main_resource_load_)
- provider_host_->active_version()->ScheduleUpdate();
+ provider_host_->controller()->ScheduleUpdate();
else
- provider_host_->active_version()->DeferScheduledUpdate();
+ provider_host_->controller()->DeferScheduledUpdate();
}
net::URLRequestJob* ServiceWorkerControlleeRequestHandler::MaybeCreateJob(
@@ -187,12 +242,11 @@ net::URLRequestJob* ServiceWorkerControlleeRequestHandler::MaybeCreateJob(
#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES)
// It's for original request (A) or redirect case (B-a or B-b).
- std::unique_ptr<ServiceWorkerURLRequestJob> job(
- new ServiceWorkerURLRequestJob(
- request, network_delegate, provider_host_->client_uuid(),
- blob_storage_context_, resource_context, request_mode_,
- credentials_mode_, redirect_mode_, integrity_, keepalive_,
- resource_type_, request_context_type_, frame_type_, body_, this));
+ auto job = std::make_unique<ServiceWorkerURLRequestJob>(
+ request, network_delegate, provider_host_->client_uuid(),
+ blob_storage_context_, resource_context, request_mode_, credentials_mode_,
+ redirect_mode_, integrity_, keepalive_, resource_type_,
+ request_context_type_, frame_type_, body_, this);
url_job_ = std::make_unique<ServiceWorkerURLJobWrapper>(job->GetWeakPtr());
resource_context_ = resource_context;
@@ -220,9 +274,10 @@ net::URLRequestJob* ServiceWorkerControlleeRequestHandler::MaybeCreateJob(
}
void ServiceWorkerControlleeRequestHandler::MaybeCreateLoader(
- const network::ResourceRequest& resource_request,
+ const network::ResourceRequest& tentative_resource_request,
ResourceContext* resource_context,
- LoaderCallback callback) {
+ LoaderCallback callback,
+ FallbackCallback fallback_callback) {
DCHECK(blink::ServiceWorkerUtils::IsServicificationEnabled());
DCHECK(is_main_resource_load_);
ClearJob();
@@ -240,7 +295,13 @@ void ServiceWorkerControlleeRequestHandler::MaybeCreateLoader(
#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
// Fall back for the subsequent offline page interceptor to load the offline
// snapshot of the page if required.
- if (ShouldFallbackToLoadOfflinePage(resource_request.headers)) {
+ //
+ // TODO(crbug.com/876527): Figure out how offline page interception should
+ // interact with URLLoaderThrottles. It might be incorrect to use
+ // |tentative_resource_request.headers| here, since throttles can rewrite
+ // headers between now and when the request handler passed to
+ // |loader_callback_| is invoked.
+ if (ShouldFallbackToLoadOfflinePage(tentative_resource_request.headers)) {
std::move(callback).Run({});
return;
}
@@ -248,13 +309,14 @@ void ServiceWorkerControlleeRequestHandler::MaybeCreateLoader(
url_job_ = std::make_unique<ServiceWorkerURLJobWrapper>(
std::make_unique<ServiceWorkerNavigationLoader>(
- std::move(callback), this, resource_request,
+ std::move(callback), std::move(fallback_callback), this,
+ tentative_resource_request,
base::WrapRefCounted(context_->loader_factory_getter())));
resource_context_ = resource_context;
- PrepareForMainResource(resource_request.url,
- resource_request.site_for_cookies);
+ PrepareForMainResource(tentative_resource_request.url,
+ tentative_resource_request.site_for_cookies);
if (url_job_->ShouldFallbackToNetwork()) {
// We're falling back to the next NavigationLoaderInterceptor, forward
@@ -277,7 +339,7 @@ ServiceWorkerControlleeRequestHandler::MaybeCreateSubresourceLoaderParams() {
// DidLookupRegistrationForMainResource() for the request didn't find
// a matching service worker for this request, and
- // ServiceWorkerProviderHost::AssociateRegistration() was not called.
+ // ServiceWorkerProviderHost::SetControllerRegistration() was not called.
if (!provider_host_ || !provider_host_->controller())
return base::nullopt;
@@ -311,40 +373,46 @@ void ServiceWorkerControlleeRequestHandler::PrepareForMainResource(
DCHECK(!JobWasCanceled());
DCHECK(context_);
DCHECK(provider_host_);
+ tracker_ = std::make_unique<MainResourceRequestTracker>();
+
TRACE_EVENT_ASYNC_BEGIN1(
"ServiceWorker",
"ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
url_job_.get(), "URL", url.spec());
- // The corresponding provider_host may already have associated a registration
- // in redirect case, unassociate it now.
- provider_host_->DisassociateRegistration();
+ // The provider host may already have set a controller in redirect case,
+ // unset it now.
+ provider_host_->SetControllerRegistration(
+ nullptr, false /* notify_controllerchange */);
- // Also prevent a register job from establishing an association to a new
- // registration while we're finding an existing registration.
- provider_host_->SetAllowAssociation(false);
+ // Also prevent a registration from claiming this host while it's not
+ // yet execution ready.
+ auto disallow_controller =
+ std::make_unique<ScopedDisallowSetControllerRegistration>(provider_host_);
stripped_url_ = net::SimplifyUrlForRequest(url);
provider_host_->SetDocumentUrl(stripped_url_);
provider_host_->SetTopmostFrameUrl(site_for_cookies);
context_->storage()->FindRegistrationForDocument(
- stripped_url_, base::BindOnce(&self::DidLookupRegistrationForMainResource,
- weak_factory_.GetWeakPtr()));
+ stripped_url_, base::BindOnce(&ServiceWorkerControlleeRequestHandler::
+ DidLookupRegistrationForMainResource,
+ weak_factory_.GetWeakPtr(),
+ std::move(disallow_controller)));
}
void ServiceWorkerControlleeRequestHandler::
DidLookupRegistrationForMainResource(
+ std::unique_ptr<ScopedDisallowSetControllerRegistration>
+ disallow_controller,
blink::ServiceWorkerStatusCode status,
scoped_refptr<ServiceWorkerRegistration> registration) {
// The job may have been canceled before this was invoked.
if (JobWasCanceled())
return;
- const bool need_to_update = !force_update_started_ && registration &&
- context_->force_update_on_page_load();
-
- if (provider_host_ && !need_to_update)
- provider_host_->SetAllowAssociation(true);
if (status != blink::ServiceWorkerStatusCode::kOk) {
+ tracker_->RecordDestination(
+ ServiceWorkerMetrics::MainResourceRequestDestination::
+ kNetworkBecauseNoRegistration);
url_job_->FallbackToNetwork();
TRACE_EVENT_ASYNC_END1(
"ServiceWorker",
@@ -352,9 +420,12 @@ void ServiceWorkerControlleeRequestHandler::
url_job_.get(), "Status", blink::ServiceWorkerStatusToString(status));
return;
}
- DCHECK(registration.get());
+ DCHECK(registration);
if (!provider_host_) {
+ tracker_->RecordDestination(
+ ServiceWorkerMetrics::MainResourceRequestDestination::
+ kNetworkBecauseNoProvider);
url_job_->FallbackToNetwork();
TRACE_EVENT_ASYNC_END1(
"ServiceWorker",
@@ -362,8 +433,12 @@ void ServiceWorkerControlleeRequestHandler::
url_job_.get(), "Info", "No Provider");
return;
}
+ provider_host_->AddMatchingRegistration(registration.get());
if (!context_) {
+ tracker_->RecordDestination(
+ ServiceWorkerMetrics::MainResourceRequestDestination::
+ kNetworkBecauseNoContext);
url_job_->FallbackToNetwork();
TRACE_EVENT_ASYNC_END1(
"ServiceWorker",
@@ -375,18 +450,23 @@ void ServiceWorkerControlleeRequestHandler::
if (!GetContentClient()->browser()->AllowServiceWorker(
registration->pattern(), provider_host_->topmost_frame_url(),
resource_context_, provider_host_->web_contents_getter())) {
+ tracker_->RecordDestination(
+ ServiceWorkerMetrics::MainResourceRequestDestination::
+ kNetworkBecauseNotAllowed);
url_job_->FallbackToNetwork();
- TRACE_EVENT_ASYNC_END2(
+ TRACE_EVENT_ASYNC_END1(
"ServiceWorker",
"ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
- url_job_.get(), "Status", blink::ServiceWorkerStatusToString(status),
- "Info", "ServiceWorker is blocked");
+ url_job_.get(), "Info", "ServiceWorker is blocked");
return;
}
if (!provider_host_->IsContextSecureForServiceWorker()) {
// TODO(falken): Figure out a way to surface in the page's DevTools
// console that the service worker was blocked for security.
+ tracker_->RecordDestination(
+ ServiceWorkerMetrics::MainResourceRequestDestination::
+ kNetworkBecauseNotSecure);
url_job_->FallbackToNetwork();
TRACE_EVENT_ASYNC_END1(
"ServiceWorker",
@@ -395,13 +475,17 @@ void ServiceWorkerControlleeRequestHandler::
return;
}
+ const bool need_to_update =
+ !force_update_started_ && context_->force_update_on_page_load();
if (need_to_update) {
force_update_started_ = true;
context_->UpdateServiceWorker(
registration.get(), true /* force_bypass_cache */,
true /* skip_script_comparison */,
- base::BindOnce(&self::DidUpdateRegistration, weak_factory_.GetWeakPtr(),
- registration));
+ base::BindOnce(
+ &ServiceWorkerControlleeRequestHandler::DidUpdateRegistration,
+ weak_factory_.GetWeakPtr(), registration,
+ std::move(disallow_controller)));
return;
}
@@ -413,47 +497,117 @@ void ServiceWorkerControlleeRequestHandler::
scoped_refptr<ServiceWorkerVersion> active_version =
registration->active_version();
+ if (!active_version) {
+ tracker_->RecordDestination(
+ ServiceWorkerMetrics::MainResourceRequestDestination::
+ kNetworkBecauseNoActiveVersion);
+ url_job_->FallbackToNetwork();
+ TRACE_EVENT_ASYNC_END1(
+ "ServiceWorker",
+ "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
+ url_job_.get(), "Info",
+ "No active version, so falling back to network");
+ return;
+ }
+ DCHECK(active_version->status() == ServiceWorkerVersion::ACTIVATING ||
+ active_version->status() == ServiceWorkerVersion::ACTIVATED)
+ << ServiceWorkerVersion::VersionStatusToString(active_version->status());
// Wait until it's activated before firing fetch events.
- if (active_version.get() &&
- active_version->status() == ServiceWorkerVersion::ACTIVATING) {
- provider_host_->SetAllowAssociation(false);
- active_version->RegisterStatusChangeCallback(base::BindOnce(
- &self::OnVersionStatusChanged, weak_factory_.GetWeakPtr(), registration,
- active_version));
- TRACE_EVENT_ASYNC_END2(
+ if (active_version->status() == ServiceWorkerVersion::ACTIVATING) {
+ registration->active_version()->RegisterStatusChangeCallback(
+ base::BindOnce(&ServiceWorkerControlleeRequestHandler::
+ ContinueWithInScopeMainResourceRequest,
+ weak_factory_.GetWeakPtr(), registration, active_version,
+ std::move(disallow_controller)));
+ TRACE_EVENT_ASYNC_END1(
"ServiceWorker",
"ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
- url_job_.get(), "Status", blink::ServiceWorkerStatusToString(status),
- "Info", "Wait until finished SW activation");
+ url_job_.get(), "Info", "Wait until finished SW activation");
return;
}
- // TODO(falken): Factor out the rest of this function and
- // OnVersionStatusChanged into the same function.
+ ContinueWithInScopeMainResourceRequest(std::move(registration),
+ std::move(active_version),
+ std::move(disallow_controller));
+}
- // A registration exists, so associate it. Note that the controller is only
- // set if there's an active version. If there's no active version, we should
- // still associate so the provider host can use .ready.
- provider_host_->AssociateRegistration(registration.get(),
- false /* notify_controllerchange */);
+void ServiceWorkerControlleeRequestHandler::
+ ContinueWithInScopeMainResourceRequest(
+ scoped_refptr<ServiceWorkerRegistration> registration,
+ scoped_refptr<ServiceWorkerVersion> active_version,
+ std::unique_ptr<ScopedDisallowSetControllerRegistration>
+ disallow_controller) {
+ // The job may have been canceled before this was invoked. In that
+ // case, |url_job_| can't be used, so return.
+ if (JobWasCanceled()) {
+ tracker_->RecordDestination(
+ ServiceWorkerMetrics::MainResourceRequestDestination::kJobWasCancelled);
+ TRACE_EVENT_ASYNC_END1(
+ "ServiceWorker",
+ "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
+ url_job_.get(), "Info", "The job was canceled");
+ return;
+ }
- if (!active_version.get() ||
- active_version->status() != ServiceWorkerVersion::ACTIVATED) {
+ if (!provider_host_) {
+ tracker_->RecordDestination(
+ ServiceWorkerMetrics::MainResourceRequestDestination::
+ kNetworkBecauseNoProviderAfterContinuing);
+ url_job_->FallbackToNetwork();
+ TRACE_EVENT_ASYNC_END1(
+ "ServiceWorker",
+ "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
+ url_job_.get(), "Info",
+ "The provider host is gone, so falling back to network");
+ return;
+ }
+
+ if (active_version->status() != ServiceWorkerVersion::ACTIVATED) {
+ // TODO(falken): Clean this up and clarify in what cases we come here. I
+ // guess it's:
+ // - strange system error cases where promoting from ACTIVATING to ACTIVATED
+ // failed (shouldn't happen)
+ // - something calling Doom(), etc, making the active_version REDUNDANT
+ // - a version called skipWaiting() during activation so the expected
+ // version is no longer the active one (shouldn't happen: skipWaiting()
+ // waits for the active version to finish activating).
+ // In most cases, it sounds like falling back to network would not be right,
+ // since it's still in-scope. We probably should do:
+ // 1) If the provider host has an active version that is ACTIVATED, just
+ // use that, even if it wasn't the expected one.
+ // 2) If the provider host has an active version that is not ACTIVATED,
+ // just fail the load. The correct thing is probably to re-try
+ // activating that version, but there's a risk of an infinite loop of
+ // retries.
+ // 3) If the provider host does not have an active version, just fail the
+ // load.
+ tracker_->RecordDestination(
+ ServiceWorkerMetrics::MainResourceRequestDestination::
+ kNetworkBecauseNoActiveVersionAfterContinuing);
url_job_->FallbackToNetwork();
TRACE_EVENT_ASYNC_END2(
"ServiceWorker",
"ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
- url_job_.get(), "Status", blink::ServiceWorkerStatusToString(status),
- "Info",
- "ServiceWorkerVersion is not available, so falling back to network");
+ url_job_.get(), "Info",
+ "The expected active version is not ACTIVATED, so falling back to "
+ "network",
+ "Status",
+ ServiceWorkerVersion::VersionStatusToString(active_version->status()));
return;
}
+ disallow_controller.reset();
+ provider_host_->SetControllerRegistration(
+ registration, false /* notify_controllerchange */);
+
+ DCHECK_EQ(active_version, registration->active_version());
+ DCHECK_EQ(active_version, provider_host_->controller());
DCHECK_NE(active_version->fetch_handler_existence(),
ServiceWorkerVersion::FetchHandlerExistence::UNKNOWN);
ServiceWorkerMetrics::CountControlledPageLoad(
- active_version->site_for_uma(), stripped_url_, is_main_frame_load_);
+ active_version->site_for_uma(), stripped_url_,
+ resource_type_ == RESOURCE_TYPE_MAIN_FRAME);
if (blink::ServiceWorkerUtils::IsServicificationEnabled() &&
IsResourceTypeFrame(resource_type_)) {
@@ -461,49 +615,23 @@ void ServiceWorkerControlleeRequestHandler::
}
bool is_forwarded =
MaybeForwardToServiceWorker(url_job_.get(), active_version.get());
-
- TRACE_EVENT_ASYNC_END2(
+ if (!is_forwarded) {
+ tracker_->RecordDestination(
+ ServiceWorkerMetrics::MainResourceRequestDestination::
+ kNetworkBecauseNoFetchEventHandler);
+ }
+ TRACE_EVENT_ASYNC_END1(
"ServiceWorker",
"ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
- url_job_.get(), "Status", blink::ServiceWorkerStatusToString(status),
- "Info",
+ url_job_.get(), "Info",
(is_forwarded) ? "Forwarded to the ServiceWorker"
: "Skipped the ServiceWorker which has no fetch handler");
}
-void ServiceWorkerControlleeRequestHandler::OnVersionStatusChanged(
- scoped_refptr<ServiceWorkerRegistration> registration,
- scoped_refptr<ServiceWorkerVersion> version) {
- // The job may have been canceled before this was invoked.
- if (JobWasCanceled())
- return;
-
- if (provider_host_)
- provider_host_->SetAllowAssociation(true);
- if (version != registration->active_version() ||
- version->status() != ServiceWorkerVersion::ACTIVATED ||
- !provider_host_) {
- url_job_->FallbackToNetwork();
- return;
- }
-
- DCHECK_NE(version->fetch_handler_existence(),
- ServiceWorkerVersion::FetchHandlerExistence::UNKNOWN);
- ServiceWorkerMetrics::CountControlledPageLoad(
- version->site_for_uma(), stripped_url_, is_main_frame_load_);
-
- provider_host_->AssociateRegistration(registration.get(),
- false /* notify_controllerchange */);
-
- if (blink::ServiceWorkerUtils::IsServicificationEnabled() &&
- IsResourceTypeFrame(resource_type_)) {
- provider_host_->AddServiceWorkerToUpdate(version);
- }
- MaybeForwardToServiceWorker(url_job_.get(), version.get());
-}
-
void ServiceWorkerControlleeRequestHandler::DidUpdateRegistration(
- const scoped_refptr<ServiceWorkerRegistration>& original_registration,
+ scoped_refptr<ServiceWorkerRegistration> original_registration,
+ std::unique_ptr<ScopedDisallowSetControllerRegistration>
+ disallow_controller,
blink::ServiceWorkerStatusCode status,
const std::string& status_message,
int64_t registration_id) {
@@ -522,24 +650,28 @@ void ServiceWorkerControlleeRequestHandler::DidUpdateRegistration(
// Update failed. Look up the registration again since the original
// registration was possibly unregistered in the meantime.
context_->storage()->FindRegistrationForDocument(
- stripped_url_,
- base::BindOnce(&self::DidLookupRegistrationForMainResource,
- weak_factory_.GetWeakPtr()));
+ stripped_url_, base::BindOnce(&ServiceWorkerControlleeRequestHandler::
+ DidLookupRegistrationForMainResource,
+ weak_factory_.GetWeakPtr(),
+ std::move(disallow_controller)));
return;
}
DCHECK_EQ(original_registration->id(), registration_id);
- scoped_refptr<ServiceWorkerVersion> new_version =
+ ServiceWorkerVersion* new_version =
original_registration->installing_version();
new_version->ReportForceUpdateToDevTools();
new_version->set_skip_waiting(true);
new_version->RegisterStatusChangeCallback(base::BindOnce(
- &self::OnUpdatedVersionStatusChanged, weak_factory_.GetWeakPtr(),
- original_registration, new_version));
+ &ServiceWorkerControlleeRequestHandler::OnUpdatedVersionStatusChanged,
+ weak_factory_.GetWeakPtr(), std::move(original_registration),
+ base::WrapRefCounted(new_version), std::move(disallow_controller)));
}
void ServiceWorkerControlleeRequestHandler::OnUpdatedVersionStatusChanged(
- const scoped_refptr<ServiceWorkerRegistration>& registration,
- const scoped_refptr<ServiceWorkerVersion>& version) {
+ scoped_refptr<ServiceWorkerRegistration> registration,
+ scoped_refptr<ServiceWorkerVersion> version,
+ std::unique_ptr<ScopedDisallowSetControllerRegistration>
+ disallow_controller) {
// The job may have been canceled before this was invoked.
if (JobWasCanceled())
return;
@@ -554,14 +686,16 @@ void ServiceWorkerControlleeRequestHandler::OnUpdatedVersionStatusChanged(
// continue with the incumbent version.
// In case unregister job may have run, look up the registration again.
context_->storage()->FindRegistrationForDocument(
- stripped_url_,
- base::BindOnce(&self::DidLookupRegistrationForMainResource,
- weak_factory_.GetWeakPtr()));
+ stripped_url_, base::BindOnce(&ServiceWorkerControlleeRequestHandler::
+ DidLookupRegistrationForMainResource,
+ weak_factory_.GetWeakPtr(),
+ std::move(disallow_controller)));
return;
}
- version->RegisterStatusChangeCallback(
- base::BindOnce(&self::OnUpdatedVersionStatusChanged,
- weak_factory_.GetWeakPtr(), registration, version));
+ version->RegisterStatusChangeCallback(base::BindOnce(
+ &ServiceWorkerControlleeRequestHandler::OnUpdatedVersionStatusChanged,
+ weak_factory_.GetWeakPtr(), std::move(registration), version,
+ std::move(disallow_controller)));
}
void ServiceWorkerControlleeRequestHandler::PrepareForSubResource() {
@@ -575,14 +709,13 @@ void ServiceWorkerControlleeRequestHandler::PrepareForSubResource() {
// because a permanent failure occurred when trying to start it.
//
// As this is an exceptional case, just error out.
- // TODO(falken): Figure out if |active_version| can change to |controller| and
- // do it or document the findings.
- if (!provider_host_->active_version()) {
+ ServiceWorkerVersion* controller = provider_host_->controller();
+ if (!controller) {
url_job_->FailDueToLostController();
return;
}
- MaybeForwardToServiceWorker(url_job_.get(), provider_host_->active_version());
+ MaybeForwardToServiceWorker(url_job_.get(), controller);
}
void ServiceWorkerControlleeRequestHandler::OnPrepareToRestart() {
@@ -597,11 +730,11 @@ ServiceWorkerControlleeRequestHandler::GetServiceWorkerVersion(
*result = ServiceWorkerMetrics::REQUEST_JOB_ERROR_NO_PROVIDER_HOST;
return nullptr;
}
- if (!provider_host_->active_version()) {
+ if (!provider_host_->controller()) {
*result = ServiceWorkerMetrics::REQUEST_JOB_ERROR_NO_ACTIVE_VERSION;
return nullptr;
}
- return provider_host_->active_version();
+ return provider_host_->controller();
}
bool ServiceWorkerControlleeRequestHandler::RequestStillValid(
@@ -621,7 +754,25 @@ void ServiceWorkerControlleeRequestHandler::MainResourceLoadFailed() {
provider_host_->NotifyControllerLost();
}
+void ServiceWorkerControlleeRequestHandler::ReportDestination(
+ ServiceWorkerMetrics::MainResourceRequestDestination destination) {
+ DCHECK(is_main_resource_load_);
+ tracker_->RecordDestination(destination);
+}
+
+void ServiceWorkerControlleeRequestHandler::
+ WillDispatchFetchEventForMainResource() {
+ DCHECK(is_main_resource_load_);
+ tracker_->WillDispatchFetchEvent();
+}
+
void ServiceWorkerControlleeRequestHandler::ClearJob() {
+ // Invalidate weak pointers to cancel RegisterStatusChangeCallback().
+ // Otherwise we may end up calling ForwardToServiceWorer()
+ // or FallbackToNetwork() twice on the same |url_job_|.
+ // TODO(bashi): Consider not to reuse this handler when restarting the
+ // request after S13nServiceWorker is shipped.
+ weak_factory_.InvalidateWeakPtrs();
url_job_.reset();
}
diff --git a/chromium/content/browser/service_worker/service_worker_controllee_request_handler.h b/chromium/content/browser/service_worker/service_worker_controllee_request_handler.h
index ed148bea249..0ad6eed9b4b 100644
--- a/chromium/content/browser/service_worker/service_worker_controllee_request_handler.h
+++ b/chromium/content/browser/service_worker/service_worker_controllee_request_handler.h
@@ -6,6 +6,8 @@
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CONTROLLEE_REQUEST_HANDLER_H_
#include <stdint.h>
+#include <memory>
+#include <string>
#include "base/gtest_prod_util.h"
#include "base/macros.h"
@@ -37,8 +39,9 @@ namespace content {
class ServiceWorkerRegistration;
class ServiceWorkerVersion;
-// A request handler derivative used to handle requests from
-// controlled documents.
+// A request handler derivative used to handle requests for,
+// and requests from, controlled documents and shared workers.
+//
// Note that in IsServicificationEnabled cases this is used only for
// main resource fetch during navigation or shared worker creation.
class CONTENT_EXPORT ServiceWorkerControlleeRequestHandler
@@ -77,52 +80,65 @@ class CONTENT_EXPORT ServiceWorkerControlleeRequestHandler
// cases. (In fallback-to-network cases we basically forward the request
// to the request to the next request handler)
// NavigationLoaderInterceptor overrides:
- void MaybeCreateLoader(const network::ResourceRequest& request,
+ void MaybeCreateLoader(const network::ResourceRequest& tentative_request,
ResourceContext* resource_context,
- LoaderCallback callback) override;
+ LoaderCallback callback,
+ FallbackCallback fallback_callback) override;
// Returns params with the ControllerServiceWorkerPtr if we have found
// a matching controller service worker for the |request| that is given
// to MaybeCreateLoader(). Otherwise this returns base::nullopt.
base::Optional<SubresourceLoaderParams> MaybeCreateSubresourceLoaderParams()
override;
+ // Exposed for testing.
+ ServiceWorkerURLJobWrapper* url_job() const { return url_job_.get(); }
+
private:
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerControlleeRequestHandlerTest,
ActivateWaitingVersion);
- typedef ServiceWorkerControlleeRequestHandler self;
+ class ScopedDisallowSetControllerRegistration;
+ class MainResourceRequestTracker;
// For main resource case.
void PrepareForMainResource(const GURL& url, const GURL& site_for_cookies);
void DidLookupRegistrationForMainResource(
+ std::unique_ptr<ScopedDisallowSetControllerRegistration>
+ disallow_controller,
blink::ServiceWorkerStatusCode status,
scoped_refptr<ServiceWorkerRegistration> registration);
- void OnVersionStatusChanged(
+ void ContinueWithInScopeMainResourceRequest(
scoped_refptr<ServiceWorkerRegistration> registration,
- scoped_refptr<ServiceWorkerVersion> version);
+ scoped_refptr<ServiceWorkerVersion> version,
+ std::unique_ptr<ScopedDisallowSetControllerRegistration>
+ disallow_controller);
+ // For forced update.
void DidUpdateRegistration(
- const scoped_refptr<ServiceWorkerRegistration>& original_registration,
+ scoped_refptr<ServiceWorkerRegistration> original_registration,
+ std::unique_ptr<ScopedDisallowSetControllerRegistration>
+ disallow_controller,
blink::ServiceWorkerStatusCode status,
const std::string& status_message,
int64_t registration_id);
void OnUpdatedVersionStatusChanged(
- const scoped_refptr<ServiceWorkerRegistration>& registration,
- const scoped_refptr<ServiceWorkerVersion>& version);
+ scoped_refptr<ServiceWorkerRegistration> registration,
+ scoped_refptr<ServiceWorkerVersion> version,
+ std::unique_ptr<ScopedDisallowSetControllerRegistration>
+ disallow_controller);
// For sub resource case.
void PrepareForSubResource();
// ServiceWorkerURLJobWrapper::Delegate implementation:
-
- // Called just before the request is restarted. Makes sure the next request
- // goes over the network.
void OnPrepareToRestart() override;
-
ServiceWorkerVersion* GetServiceWorkerVersion(
ServiceWorkerMetrics::URLRequestJobResult* result) override;
bool RequestStillValid(
ServiceWorkerMetrics::URLRequestJobResult* result) override;
void MainResourceLoadFailed() override;
+ void ReportDestination(ServiceWorkerMetrics::MainResourceRequestDestination
+ destination) override;
+ void WillDispatchFetchEventForMainResource() override;
// Sets |job_| to nullptr, and clears all extra response info associated with
// that job, except for timing information.
@@ -136,7 +152,6 @@ class CONTENT_EXPORT ServiceWorkerControlleeRequestHandler
const ResourceType resource_type_;
const bool is_main_resource_load_;
- const bool is_main_frame_load_;
std::unique_ptr<ServiceWorkerURLJobWrapper> url_job_;
network::mojom::FetchRequestMode request_mode_;
network::mojom::FetchCredentialsMode credentials_mode_;
@@ -155,6 +170,8 @@ class CONTENT_EXPORT ServiceWorkerControlleeRequestHandler
// next intercept opportunity, for main frame requests.
bool use_network_;
+ std::unique_ptr<MainResourceRequestTracker> tracker_;
+
base::WeakPtrFactory<ServiceWorkerControlleeRequestHandler> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerControlleeRequestHandler);
diff --git a/chromium/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc b/chromium/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
index 5974fee450c..930165c99aa 100644
--- a/chromium/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
@@ -11,6 +11,7 @@
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
#include "components/offline_pages/buildflags/buildflags.h"
#include "content/browser/service_worker/embedded_worker_test_helper.h"
#include "content/browser/service_worker/service_worker_context_core.h"
@@ -33,6 +34,7 @@
#include "services/network/public/cpp/resource_request_body.h"
#include "services/network/public/mojom/request_context_frame_type.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
namespace content {
@@ -40,7 +42,8 @@ namespace service_worker_controllee_request_handler_unittest {
int kMockProviderId = 1;
-class ServiceWorkerControlleeRequestHandlerTest : public testing::Test {
+class ServiceWorkerControlleeRequestHandlerTest
+ : public testing::TestWithParam<bool> {
public:
class ServiceWorkerRequestTestResources {
public:
@@ -51,6 +54,7 @@ class ServiceWorkerControlleeRequestHandlerTest : public testing::Test {
network::mojom::FetchRequestMode fetch_type =
network::mojom::FetchRequestMode::kNoCORS)
: test_(test),
+ resource_type_(type),
request_(test->url_request_context_.CreateRequest(
url,
net::DEFAULT_PRIORITY,
@@ -77,21 +81,57 @@ class ServiceWorkerControlleeRequestHandlerTest : public testing::Test {
return static_cast<ServiceWorkerURLRequestJob*>(job_.get());
}
+ void MaybeCreateLoader() {
+ network::ResourceRequest resource_request;
+ resource_request.url = request_->url();
+ resource_request.resource_type = resource_type_;
+ resource_request.headers = request()->extra_request_headers();
+ handler_->MaybeCreateLoader(resource_request,
+ &test_->mock_resource_context_,
+ base::DoNothing(), base::DoNothing());
+ }
+
+ ServiceWorkerURLJobWrapper* MaybeCreateJobWrapper() {
+ if (test_->IsServiceWorkerServicificationEnabled()) {
+ MaybeCreateLoader();
+ return handler_->url_job();
+ } else {
+ ServiceWorkerURLRequestJob* job = MaybeCreateJob();
+ if (job) {
+ job_wrapper_ =
+ std::make_unique<ServiceWorkerURLJobWrapper>(job->GetWeakPtr());
+ }
+ return job_wrapper_.get();
+ }
+ }
+
void ResetHandler() { handler_.reset(nullptr); }
net::URLRequest* request() const { return request_.get(); }
private:
ServiceWorkerControlleeRequestHandlerTest* test_;
+ const ResourceType resource_type_;
std::unique_ptr<net::URLRequest> request_;
std::unique_ptr<ServiceWorkerControlleeRequestHandler> handler_;
+ // |job_| and |job_wrapper_| are only for non-S13nServiceWorker cases.
+ // When S13nServiceWorker is enabled we use a job wrapper which is owned by
+ // |handler_|.
std::unique_ptr<net::URLRequestJob> job_;
+ std::unique_ptr<ServiceWorkerURLJobWrapper> job_wrapper_;
};
ServiceWorkerControlleeRequestHandlerTest()
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
void SetUp() override {
+ if (IsServiceWorkerServicificationEnabled()) {
+ scoped_feature_list_.InitAndEnableFeature(
+ blink::features::kServiceWorkerServicification);
+ } else {
+ scoped_feature_list_.InitAndDisableFeature(
+ blink::features::kServiceWorkerServicification);
+ }
SetUpWithHelper(new EmbeddedWorkerTestHelper(base::FilePath()));
}
@@ -139,7 +179,19 @@ class ServiceWorkerControlleeRequestHandlerTest : public testing::Test {
ServiceWorkerContextCore* context() const { return helper_->context(); }
+ void SetProviderHostIsSecure(ServiceWorkerProviderHost* host,
+ bool is_secure) {
+ host->info_->is_parent_frame_secure = is_secure;
+ }
+
+ bool IsServiceWorkerServicificationEnabled() { return GetParam(); }
+
protected:
+ // |scoped_feature_list_| must be before |thread_bundle_|, since
+ // the thread bundle's destruction causes service worker-related
+ // objects to destruct, whose destructors need to know whether servicification
+ // is enabled.
+ base::test::ScopedFeatureList scoped_feature_list_;
TestBrowserThreadBundle browser_thread_bundle_;
std::unique_ptr<EmbeddedWorkerTestHelper> helper_;
scoped_refptr<ServiceWorkerRegistration> registration_;
@@ -165,7 +217,7 @@ class ServiceWorkerTestContentBrowserClient : public TestContentBrowserClient {
}
};
-TEST_F(ServiceWorkerControlleeRequestHandlerTest, DisallowServiceWorker) {
+TEST_P(ServiceWorkerControlleeRequestHandlerTest, DisallowServiceWorker) {
ServiceWorkerTestContentBrowserClient test_browser_client;
ContentBrowserClient* old_browser_client =
SetBrowserClientForTesting(&test_browser_client);
@@ -182,7 +234,8 @@ TEST_F(ServiceWorkerControlleeRequestHandlerTest, DisallowServiceWorker) {
// Conduct a main resource load.
ServiceWorkerRequestTestResources test_resources(
this, GURL("https://host/scope/doc"), RESOURCE_TYPE_MAIN_FRAME);
- ServiceWorkerURLRequestJob* sw_job = test_resources.MaybeCreateJob();
+ ServiceWorkerURLJobWrapper* sw_job = test_resources.MaybeCreateJobWrapper();
+ ASSERT_TRUE(sw_job);
EXPECT_FALSE(sw_job->ShouldFallbackToNetwork());
EXPECT_FALSE(sw_job->ShouldForwardToServiceWorker());
@@ -197,7 +250,36 @@ TEST_F(ServiceWorkerControlleeRequestHandlerTest, DisallowServiceWorker) {
SetBrowserClientForTesting(old_browser_client);
}
-TEST_F(ServiceWorkerControlleeRequestHandlerTest, ActivateWaitingVersion) {
+TEST_P(ServiceWorkerControlleeRequestHandlerTest, InsecureContext) {
+ // Store an activated worker.
+ version_->set_fetch_handler_existence(
+ ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ registration_->SetActiveVersion(version_);
+ context()->storage()->StoreRegistration(registration_.get(), version_.get(),
+ base::DoNothing());
+ base::RunLoop().RunUntilIdle();
+
+ SetProviderHostIsSecure(provider_host_.get(), false);
+
+ // Conduct a main resource load.
+ ServiceWorkerRequestTestResources test_resources(
+ this, GURL("https://host/scope/doc"), RESOURCE_TYPE_MAIN_FRAME);
+ ServiceWorkerURLJobWrapper* sw_job = test_resources.MaybeCreateJobWrapper();
+ ASSERT_TRUE(sw_job);
+
+ EXPECT_FALSE(sw_job->ShouldFallbackToNetwork());
+ EXPECT_FALSE(sw_job->ShouldForwardToServiceWorker());
+ EXPECT_FALSE(version_->HasControllee());
+ base::RunLoop().RunUntilIdle();
+
+ // Verify we did not use the worker.
+ EXPECT_TRUE(sw_job->ShouldFallbackToNetwork());
+ EXPECT_FALSE(sw_job->ShouldForwardToServiceWorker());
+ EXPECT_FALSE(version_->HasControllee());
+}
+
+TEST_P(ServiceWorkerControlleeRequestHandlerTest, ActivateWaitingVersion) {
// Store a registration that is installed but not activated yet.
version_->set_fetch_handler_existence(
ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
@@ -210,7 +292,8 @@ TEST_F(ServiceWorkerControlleeRequestHandlerTest, ActivateWaitingVersion) {
// Conduct a main resource load.
ServiceWorkerRequestTestResources test_resources(
this, GURL("https://host/scope/doc"), RESOURCE_TYPE_MAIN_FRAME);
- ServiceWorkerURLRequestJob* sw_job = test_resources.MaybeCreateJob();
+ ServiceWorkerURLJobWrapper* sw_job = test_resources.MaybeCreateJobWrapper();
+ ASSERT_TRUE(sw_job);
EXPECT_FALSE(sw_job->ShouldFallbackToNetwork());
EXPECT_FALSE(sw_job->ShouldForwardToServiceWorker());
@@ -218,19 +301,22 @@ TEST_F(ServiceWorkerControlleeRequestHandlerTest, ActivateWaitingVersion) {
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(ServiceWorkerVersion::ACTIVATED,
- version_->status());
+ EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, version_->status());
EXPECT_FALSE(sw_job->ShouldFallbackToNetwork());
EXPECT_TRUE(sw_job->ShouldForwardToServiceWorker());
EXPECT_TRUE(version_->HasControllee());
- // Navigations should trigger an update too.
test_resources.ResetHandler();
- EXPECT_TRUE(version_->update_timer_.IsRunning());
+ // Navigations should trigger an update too when S13nServiceWorker is
+ // disabled. Note that when S13nServiceWorker is enabled we defer scheduling
+ // update. See the comment on
+ // ServiceWorkerProviderHost::AddServiceWorkerToUpdate() for details.
+ if (!IsServiceWorkerServicificationEnabled())
+ EXPECT_TRUE(version_->update_timer_.IsRunning());
}
// Test that an installing registration is associated with a provider host.
-TEST_F(ServiceWorkerControlleeRequestHandlerTest, InstallingRegistration) {
+TEST_P(ServiceWorkerControlleeRequestHandlerTest, InstallingRegistration) {
// Create an installing registration.
version_->SetStatus(ServiceWorkerVersion::INSTALLING);
version_->set_fetch_handler_existence(
@@ -241,22 +327,22 @@ TEST_F(ServiceWorkerControlleeRequestHandlerTest, InstallingRegistration) {
// Conduct a main resource load.
ServiceWorkerRequestTestResources test_resources(
this, GURL("https://host/scope/doc"), RESOURCE_TYPE_MAIN_FRAME);
- ServiceWorkerURLRequestJob* job = test_resources.MaybeCreateJob();
+ ServiceWorkerURLJobWrapper* job = test_resources.MaybeCreateJobWrapper();
base::RunLoop().RunUntilIdle();
// The handler should have fallen back to network and destroyed the job. The
- // registration should be associated with the provider host, although it is
- // not controlled since there is no active version.
+ // provider host should not be controlled. However it should add the
+ // registration as a matching registration so it can be used for .ready and
+ // claim().
EXPECT_FALSE(job);
- EXPECT_EQ(registration_.get(), provider_host_->associated_registration());
- EXPECT_EQ(version_.get(), provider_host_->installing_version());
EXPECT_FALSE(version_->HasControllee());
EXPECT_FALSE(provider_host_->controller());
+ EXPECT_EQ(registration_.get(), provider_host_->MatchRegistration());
}
// Test to not regress crbug/414118.
-TEST_F(ServiceWorkerControlleeRequestHandlerTest, DeletedProviderHost) {
+TEST_P(ServiceWorkerControlleeRequestHandlerTest, DeletedProviderHost) {
// Store a registration so the call to FindRegistrationForDocument will read
// from the database.
version_->set_fetch_handler_existence(
@@ -272,7 +358,8 @@ TEST_F(ServiceWorkerControlleeRequestHandlerTest, DeletedProviderHost) {
// Conduct a main resource load.
ServiceWorkerRequestTestResources test_resources(
this, GURL("https://host/scope/doc"), RESOURCE_TYPE_MAIN_FRAME);
- ServiceWorkerURLRequestJob* sw_job = test_resources.MaybeCreateJob();
+ ServiceWorkerURLJobWrapper* sw_job = test_resources.MaybeCreateJobWrapper();
+ ASSERT_TRUE(sw_job);
EXPECT_FALSE(sw_job->ShouldFallbackToNetwork());
EXPECT_FALSE(sw_job->ShouldForwardToServiceWorker());
@@ -290,7 +377,14 @@ TEST_F(ServiceWorkerControlleeRequestHandlerTest, DeletedProviderHost) {
// Tests the scenario where a controllee request handler was created
// for a subresource request, but before MaybeCreateJob() is run, the
// controller/active version becomes null.
-TEST_F(ServiceWorkerControlleeRequestHandlerTest, LostActiveVersion) {
+TEST_P(ServiceWorkerControlleeRequestHandlerTest, LostActiveVersion) {
+ // Skip this test when S13nServiceWorker is enabled because we don't use
+ // ServiceWorkerControlleeRequestHandler for subresource loading.
+ // TODO(bashi): Add a test in ServiceWorkerProviderHost to cover this
+ // scenario when S13nServiceWorker is enabled.
+ if (IsServiceWorkerServicificationEnabled())
+ return;
+
// Store an activated worker.
version_->set_fetch_handler_existence(
ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
@@ -307,14 +401,12 @@ TEST_F(ServiceWorkerControlleeRequestHandlerTest, LostActiveVersion) {
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(version_->HasControllee());
EXPECT_EQ(version_, provider_host_->controller());
- EXPECT_EQ(version_, provider_host_->active_version());
// Unset the active version.
provider_host_->NotifyControllerLost();
registration_->SetActiveVersion(nullptr);
EXPECT_FALSE(version_->HasControllee());
EXPECT_FALSE(provider_host_->controller());
- EXPECT_FALSE(provider_host_->active_version());
// Conduct a subresource load.
ServiceWorkerRequestTestResources sub_test_resources(
@@ -327,7 +419,14 @@ TEST_F(ServiceWorkerControlleeRequestHandlerTest, LostActiveVersion) {
sub_job->response_type_);
}
-TEST_F(ServiceWorkerControlleeRequestHandlerTest, FallbackWithNoFetchHandler) {
+TEST_P(ServiceWorkerControlleeRequestHandlerTest, FallbackWithNoFetchHandler) {
+ // Skip this test when S13nServiceWorker is enabled because we don't use
+ // ServiceWorkerControlleeRequestHandler for subresource loading.
+ // TODO(bashi): Add a test in ServiceWorkerProviderHost to cover this
+ // scenario when S13nServiceWorker is enabled.
+ if (IsServiceWorkerServicificationEnabled())
+ return;
+
version_->set_fetch_handler_existence(
ServiceWorkerVersion::FetchHandlerExistence::DOES_NOT_EXIST);
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
@@ -377,7 +476,7 @@ TEST_F(ServiceWorkerControlleeRequestHandlerTest, FallbackWithNoFetchHandler) {
}
#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
-TEST_F(ServiceWorkerControlleeRequestHandlerTest, FallbackWithOfflineHeader) {
+TEST_P(ServiceWorkerControlleeRequestHandlerTest, FallbackWithOfflineHeader) {
version_->set_fetch_handler_existence(
ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
@@ -393,12 +492,12 @@ TEST_F(ServiceWorkerControlleeRequestHandlerTest, FallbackWithOfflineHeader) {
// Sets an offline header to indicate force loading offline page.
test_resources.request()->SetExtraRequestHeaderByName(
"X-Chrome-offline", "reason=download", true);
- ServiceWorkerURLRequestJob* sw_job = test_resources.MaybeCreateJob();
+ ServiceWorkerURLJobWrapper* sw_job = test_resources.MaybeCreateJobWrapper();
EXPECT_FALSE(sw_job);
}
-TEST_F(ServiceWorkerControlleeRequestHandlerTest, FallbackWithNoOfflineHeader) {
+TEST_P(ServiceWorkerControlleeRequestHandlerTest, FallbackWithNoOfflineHeader) {
version_->set_fetch_handler_existence(
ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
@@ -414,11 +513,15 @@ TEST_F(ServiceWorkerControlleeRequestHandlerTest, FallbackWithNoOfflineHeader) {
// Empty offline header value should not cause fallback.
test_resources.request()->SetExtraRequestHeaderByName("X-Chrome-offline", "",
true);
- ServiceWorkerURLRequestJob* sw_job = test_resources.MaybeCreateJob();
+ ServiceWorkerURLJobWrapper* sw_job = test_resources.MaybeCreateJobWrapper();
EXPECT_TRUE(sw_job);
}
-#endif // BUILDFLAG(ENABLE_OFFLINE_PAGE
+#endif // BUILDFLAG(ENABLE_OFFLINE_PAGE)
+
+INSTANTIATE_TEST_CASE_P(IsServiceWorkerServicificationEnabled,
+ ServiceWorkerControlleeRequestHandlerTest,
+ ::testing::Bool(););
} // namespace service_worker_controllee_request_handler_unittest
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_disk_cache.cc b/chromium/content/browser/service_worker/service_worker_disk_cache.cc
index 1369b37841e..27989a034f7 100644
--- a/chromium/content/browser/service_worker/service_worker_disk_cache.cc
+++ b/chromium/content/browser/service_worker/service_worker_disk_cache.cc
@@ -4,6 +4,8 @@
#include "content/browser/service_worker/service_worker_disk_cache.h"
+#include <utility>
+
namespace content {
ServiceWorkerDiskCache::ServiceWorkerDiskCache()
@@ -13,17 +15,17 @@ ServiceWorkerDiskCache::ServiceWorkerDiskCache()
ServiceWorkerResponseReader::ServiceWorkerResponseReader(
int64_t resource_id,
- const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache)
- : AppCacheResponseReader(resource_id, disk_cache) {}
+ base::WeakPtr<AppCacheDiskCacheInterface> disk_cache)
+ : AppCacheResponseReader(resource_id, std::move(disk_cache)) {}
ServiceWorkerResponseWriter::ServiceWorkerResponseWriter(
int64_t resource_id,
- const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache)
- : AppCacheResponseWriter(resource_id, disk_cache) {}
+ base::WeakPtr<AppCacheDiskCacheInterface> disk_cache)
+ : AppCacheResponseWriter(resource_id, std::move(disk_cache)) {}
ServiceWorkerResponseMetadataWriter::ServiceWorkerResponseMetadataWriter(
int64_t resource_id,
- const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache)
- : AppCacheResponseMetadataWriter(resource_id, disk_cache) {}
+ base::WeakPtr<AppCacheDiskCacheInterface> disk_cache)
+ : AppCacheResponseMetadataWriter(resource_id, std::move(disk_cache)) {}
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_disk_cache.h b/chromium/content/browser/service_worker/service_worker_disk_cache.h
index b5ce04cddc5..bfadf688bf3 100644
--- a/chromium/content/browser/service_worker/service_worker_disk_cache.h
+++ b/chromium/content/browser/service_worker/service_worker_disk_cache.h
@@ -18,8 +18,7 @@ namespace content {
// TODO(michaeln): If this reuse sticks, refactor/move the
// resused classes to a more common location.
-class CONTENT_EXPORT ServiceWorkerDiskCache
- : public AppCacheDiskCache {
+class CONTENT_EXPORT ServiceWorkerDiskCache : public AppCacheDiskCache {
public:
ServiceWorkerDiskCache();
};
@@ -32,7 +31,7 @@ class CONTENT_EXPORT ServiceWorkerResponseReader
ServiceWorkerResponseReader(
int64_t resource_id,
- const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache);
+ base::WeakPtr<AppCacheDiskCacheInterface> disk_cache);
};
class CONTENT_EXPORT ServiceWorkerResponseWriter
@@ -43,7 +42,7 @@ class CONTENT_EXPORT ServiceWorkerResponseWriter
ServiceWorkerResponseWriter(
int64_t resource_id,
- const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache);
+ base::WeakPtr<AppCacheDiskCacheInterface> disk_cache);
};
class CONTENT_EXPORT ServiceWorkerResponseMetadataWriter
@@ -54,7 +53,7 @@ class CONTENT_EXPORT ServiceWorkerResponseMetadataWriter
ServiceWorkerResponseMetadataWriter(
int64_t resource_id,
- const base::WeakPtr<AppCacheDiskCacheInterface>& disk_cache);
+ base::WeakPtr<AppCacheDiskCacheInterface> disk_cache);
};
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc b/chromium/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
index fae15052435..7bdd0811226 100644
--- a/chromium/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
@@ -21,7 +21,6 @@
#include "content/browser/service_worker/service_worker_navigation_handle_core.h"
#include "content/browser/service_worker/service_worker_object_host.h"
#include "content/browser/service_worker/service_worker_test_utils.h"
-#include "content/common/service_worker/service_worker_messages.h"
#include "content/common/service_worker/service_worker_utils.h"
#include "content/public/browser/child_process_termination_info.h"
#include "content/public/common/browser_side_navigation_policy.h"
diff --git a/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.cc
index dcc36e82bc0..21e9f3cb7df 100644
--- a/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.cc
+++ b/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -25,7 +25,6 @@
#include "content/browser/service_worker/service_worker_version.h"
#include "content/browser/url_loader_factory_getter.h"
#include "content/common/service_worker/service_worker.mojom.h"
-#include "content/common/service_worker/service_worker_messages.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/browser_side_navigation_policy.h"
@@ -46,61 +45,6 @@ namespace content {
namespace {
-// This class wraps a mojo::AssociatedInterfacePtr<URLLoader>. It also is a
-// URLLoader implementation and delegates URLLoader calls to the wrapped loader.
-class DelegatingURLLoader final : public network::mojom::URLLoader {
- public:
- explicit DelegatingURLLoader(network::mojom::URLLoaderPtr loader)
- : binding_(this), loader_(std::move(loader)) {}
- ~DelegatingURLLoader() override {}
-
- void FollowRedirect(const base::Optional<std::vector<std::string>>&
- to_be_removed_request_headers,
- const base::Optional<net::HttpRequestHeaders>&
- modified_request_headers) override {
- DCHECK(!modified_request_headers.has_value())
- << "Redirect with modified headers was not supported yet. "
- "crbug.com/845683";
- loader_->FollowRedirect(base::nullopt, base::nullopt);
- }
- void ProceedWithResponse() override { NOTREACHED(); }
-
- void SetPriority(net::RequestPriority priority,
- int intra_priority_value) override {
- loader_->SetPriority(priority, intra_priority_value);
- }
-
- void PauseReadingBodyFromNet() override {
- loader_->PauseReadingBodyFromNet();
- }
- void ResumeReadingBodyFromNet() override {
- loader_->ResumeReadingBodyFromNet();
- }
-
- network::mojom::URLLoaderPtr CreateInterfacePtrAndBind() {
- network::mojom::URLLoaderPtr loader;
- binding_.Bind(mojo::MakeRequest(&loader));
- // This unretained pointer is safe, because |binding_| is owned by |this|
- // and the callback will never be called after |this| is destroyed.
- binding_.set_connection_error_handler(
- base::BindOnce(&DelegatingURLLoader::Cancel, base::Unretained(this)));
- return loader;
- }
-
- private:
- // Called when the network::mojom::URLLoaderPtr in the service worker is
- // deleted.
- void Cancel() {
- // Cancel loading as stated in url_loader.mojom.
- loader_ = nullptr;
- }
-
- mojo::Binding<network::mojom::URLLoader> binding_;
- network::mojom::URLLoaderPtr loader_;
-
- DISALLOW_COPY_AND_ASSIGN(DelegatingURLLoader);
-};
-
void NotifyNavigationPreloadRequestSentOnUI(
const network::ResourceRequest& request,
const std::pair<int, int>& worker_id,
@@ -361,11 +305,12 @@ const net::NetworkTrafficAnnotationTag kNavigationPreloadTrafficAnnotation =
// ServiceWorkerVersion::StartRequest*(), and held in pending_requests_
// until FinishRequest() is called.
class ServiceWorkerFetchDispatcher::ResponseCallback
- : public mojom::ServiceWorkerFetchResponseCallback {
+ : public blink::mojom::ServiceWorkerFetchResponseCallback {
public:
- ResponseCallback(mojom::ServiceWorkerFetchResponseCallbackRequest request,
- base::WeakPtr<ServiceWorkerFetchDispatcher> fetch_dispatcher,
- ServiceWorkerVersion* version)
+ ResponseCallback(
+ blink::mojom::ServiceWorkerFetchResponseCallbackRequest request,
+ base::WeakPtr<ServiceWorkerFetchDispatcher> fetch_dispatcher,
+ ServiceWorkerVersion* version)
: binding_(this, std::move(request)),
fetch_dispatcher_(fetch_dispatcher),
version_(version) {}
@@ -377,32 +322,25 @@ class ServiceWorkerFetchDispatcher::ResponseCallback
fetch_event_id_ = id;
}
- // Implements mojom::ServiceWorkerFetchResponseCallback.
- void OnResponse(const ServiceWorkerResponse& response,
+ // Implements blink::mojom::ServiceWorkerFetchResponseCallback.
+ void OnResponse(blink::mojom::FetchAPIResponsePtr response,
base::Time dispatch_event_time) override {
- HandleResponse(fetch_dispatcher_, version_, fetch_event_id_, response,
- nullptr /* body_as_stream */, nullptr /* body_as_blob */,
- FetchEventResult::kGotResponse, dispatch_event_time);
- }
- void OnResponseBlob(const ServiceWorkerResponse& response,
- blink::mojom::BlobPtr body_as_blob,
- base::Time dispatch_event_time) override {
- HandleResponse(fetch_dispatcher_, version_, fetch_event_id_, response,
- nullptr /* body_as_stream */, std::move(body_as_blob),
+ HandleResponse(fetch_dispatcher_, version_, fetch_event_id_,
+ std::move(response), nullptr /* body_as_stream */,
FetchEventResult::kGotResponse, dispatch_event_time);
}
void OnResponseStream(
- const ServiceWorkerResponse& response,
+ blink::mojom::FetchAPIResponsePtr response,
blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream,
base::Time dispatch_event_time) override {
- HandleResponse(fetch_dispatcher_, version_, fetch_event_id_, response,
- std::move(body_as_stream), nullptr /* body_as_blob */,
+ HandleResponse(fetch_dispatcher_, version_, fetch_event_id_,
+ std::move(response), std::move(body_as_stream),
FetchEventResult::kGotResponse, dispatch_event_time);
}
void OnFallback(base::Time dispatch_event_time) override {
HandleResponse(fetch_dispatcher_, version_, fetch_event_id_,
- ServiceWorkerResponse(), nullptr /* body_as_stream */,
- nullptr /* body_as_blob */,
+ blink::mojom::FetchAPIResponse::New(),
+ nullptr /* body_as_stream */,
FetchEventResult::kShouldFallback, dispatch_event_time);
}
@@ -413,9 +351,8 @@ class ServiceWorkerFetchDispatcher::ResponseCallback
base::WeakPtr<ServiceWorkerFetchDispatcher> fetch_dispatcher,
ServiceWorkerVersion* version,
base::Optional<int> fetch_event_id,
- const ServiceWorkerResponse& response,
+ blink::mojom::FetchAPIResponsePtr response,
blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream,
- blink::mojom::BlobPtr body_as_blob,
FetchEventResult fetch_result,
base::Time dispatch_event_time) {
if (!version->FinishRequest(fetch_event_id.value(),
@@ -425,12 +362,11 @@ class ServiceWorkerFetchDispatcher::ResponseCallback
// |fetch_dispatcher| is null if the URLRequest was killed.
if (!fetch_dispatcher)
return;
- fetch_dispatcher->DidFinish(fetch_event_id.value(), fetch_result, response,
- std::move(body_as_stream),
- std::move(body_as_blob));
+ fetch_dispatcher->DidFinish(fetch_event_id.value(), fetch_result,
+ std::move(response), std::move(body_as_stream));
}
- mojo::Binding<mojom::ServiceWorkerFetchResponseCallback> binding_;
+ mojo::Binding<blink::mojom::ServiceWorkerFetchResponseCallback> binding_;
base::WeakPtr<ServiceWorkerFetchDispatcher> fetch_dispatcher_;
// Owns |this| via pending_requests_.
ServiceWorkerVersion* version_;
@@ -449,10 +385,8 @@ class ServiceWorkerFetchDispatcher::URLLoaderAssets
public:
URLLoaderAssets(
std::unique_ptr<network::mojom::URLLoaderFactory> url_loader_factory,
- std::unique_ptr<network::mojom::URLLoader> url_loader,
std::unique_ptr<DelegatingURLLoaderClient> url_loader_client)
: url_loader_factory_(std::move(url_loader_factory)),
- url_loader_(std::move(url_loader)),
url_loader_client_(std::move(url_loader_client)) {}
void MaybeReportToDevTools(std::pair<int, int> worker_id,
@@ -465,7 +399,6 @@ class ServiceWorkerFetchDispatcher::URLLoaderAssets
virtual ~URLLoaderAssets() {}
std::unique_ptr<network::mojom::URLLoaderFactory> url_loader_factory_;
- std::unique_ptr<network::mojom::URLLoader> url_loader_;
std::unique_ptr<DelegatingURLLoaderClient> url_loader_client_;
DISALLOW_COPY_AND_ASSIGN(URLLoaderAssets);
@@ -575,7 +508,7 @@ void ServiceWorkerFetchDispatcher::DispatchFetchEvent() {
net_log_.BeginEvent(net::NetLogEventType::SERVICE_WORKER_FETCH_EVENT);
// Set up for receiving the response.
- mojom::ServiceWorkerFetchResponseCallbackPtr response_callback_ptr;
+ blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback_ptr;
auto response_callback = std::make_unique<ResponseCallback>(
mojo::MakeRequest(&response_callback_ptr), weak_factory_.GetWeakPtr(),
version_.get());
@@ -629,27 +562,25 @@ void ServiceWorkerFetchDispatcher::DidFailToDispatch(
void ServiceWorkerFetchDispatcher::DidFail(
blink::ServiceWorkerStatusCode status) {
DCHECK_NE(blink::ServiceWorkerStatusCode::kOk, status);
- Complete(status, FetchEventResult::kShouldFallback, ServiceWorkerResponse(),
- nullptr /* body_as_stream */, nullptr /* body_as_blob */);
+ Complete(status, FetchEventResult::kShouldFallback,
+ blink::mojom::FetchAPIResponse::New(), nullptr /* body_as_stream */);
}
void ServiceWorkerFetchDispatcher::DidFinish(
int request_id,
FetchEventResult fetch_result,
- const ServiceWorkerResponse& response,
- blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream,
- blink::mojom::BlobPtr body_as_blob) {
+ blink::mojom::FetchAPIResponsePtr response,
+ blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream) {
net_log_.EndEvent(net::NetLogEventType::SERVICE_WORKER_FETCH_EVENT);
- Complete(blink::ServiceWorkerStatusCode::kOk, fetch_result, response,
- std::move(body_as_stream), std::move(body_as_blob));
+ Complete(blink::ServiceWorkerStatusCode::kOk, fetch_result,
+ std::move(response), std::move(body_as_stream));
}
void ServiceWorkerFetchDispatcher::Complete(
blink::ServiceWorkerStatusCode status,
FetchEventResult fetch_result,
- const ServiceWorkerResponse& response,
- blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream,
- blink::mojom::BlobPtr body_as_blob) {
+ blink::mojom::FetchAPIResponsePtr response,
+ blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream) {
DCHECK(fetch_callback_);
did_complete_ = true;
@@ -658,8 +589,8 @@ void ServiceWorkerFetchDispatcher::Complete(
base::Bind(&NetLogFetchEventCallback, status, fetch_result));
std::move(fetch_callback_)
- .Run(status, fetch_result, response, std::move(body_as_stream),
- std::move(body_as_blob), version_);
+ .Run(status, fetch_result, std::move(response), std::move(body_as_stream),
+ version_);
}
// Non-S13nServiceWorker
@@ -679,16 +610,7 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload(
ResourceRequestInfoImpl* original_info =
ResourceRequestInfoImpl::ForRequest(original_request);
ResourceRequesterInfo* requester_info = original_info->requester_info();
- if (IsBrowserSideNavigationEnabled()) {
- DCHECK(requester_info->IsBrowserSideNavigation());
- } else {
- DCHECK(requester_info->IsRenderer());
- if (!requester_info->filter())
- return false;
- }
-
- DCHECK(!url_loader_assets_);
-
+ DCHECK(requester_info->IsBrowserSideNavigation());
auto url_loader_factory = std::make_unique<URLLoaderFactoryImpl>(
ResourceRequesterInfo::CreateForNavigationPreload(requester_info));
@@ -731,30 +653,27 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload(
DCHECK_LT(request_id, -1);
preload_handle_ = blink::mojom::FetchEventPreloadHandle::New();
- network::mojom::URLLoaderClientPtr url_loader_client_ptr;
+ network::mojom::URLLoaderClientPtr inner_url_loader_client;
preload_handle_->url_loader_client_request =
- mojo::MakeRequest(&url_loader_client_ptr);
+ mojo::MakeRequest(&inner_url_loader_client);
auto url_loader_client = std::make_unique<DelegatingURLLoaderClient>(
- std::move(url_loader_client_ptr), std::move(on_response), request);
- network::mojom::URLLoaderClientPtr url_loader_client_ptr_to_pass;
- url_loader_client->Bind(&url_loader_client_ptr_to_pass);
- network::mojom::URLLoaderPtr url_loader_associated_ptr;
+ std::move(inner_url_loader_client), std::move(on_response), request);
+ network::mojom::URLLoaderClientPtr url_loader_client_to_pass;
+ url_loader_client->Bind(&url_loader_client_to_pass);
+ network::mojom::URLLoaderPtr url_loader;
url_loader_factory->CreateLoaderAndStart(
- mojo::MakeRequest(&url_loader_associated_ptr),
- original_info->GetRouteID(), request_id,
+ mojo::MakeRequest(&url_loader), original_info->GetRouteID(), request_id,
network::mojom::kURLLoadOptionNone, request,
- std::move(url_loader_client_ptr_to_pass),
+ std::move(url_loader_client_to_pass),
net::MutableNetworkTrafficAnnotationTag(
original_request->traffic_annotation()));
- auto url_loader = std::make_unique<DelegatingURLLoader>(
- std::move(url_loader_associated_ptr));
- preload_handle_->url_loader =
- url_loader->CreateInterfacePtrAndBind().PassInterface();
+ preload_handle_->url_loader = url_loader.PassInterface();
+
+ DCHECK(!url_loader_assets_);
url_loader_assets_ = base::MakeRefCounted<URLLoaderAssets>(
- std::move(url_loader_factory), std::move(url_loader),
- std::move(url_loader_client));
+ std::move(url_loader_factory), std::move(url_loader_client));
return true;
}
@@ -779,13 +698,11 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreloadWithURLLoader(
resource_request.resource_type = RESOURCE_TYPE_SUB_RESOURCE;
resource_request.skip_service_worker = true;
resource_request.do_not_prompt_for_login = true;
+
DCHECK(net::HttpUtil::IsValidHeaderValue(
version_->navigation_preload_state().header));
- // TODO(crbug/762357): Record header size UMA, but not until *all* the
- // navigation preload metrics are recorded on the S13N path; otherwise the
- // metrics will get unbalanced.
- // ServiceWorkerMetrics::RecordNavigationPreloadRequestHeaderSize(
- // version_->navigation_preload_state().header.length());
+ ServiceWorkerMetrics::RecordNavigationPreloadRequestHeaderSize(
+ version_->navigation_preload_state().header.length());
resource_request.headers.SetHeader(
"Service-Worker-Navigation-Preload",
version_->navigation_preload_state().header);
@@ -794,40 +711,33 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreloadWithURLLoader(
// Create the DelegatingURLLoaderClient, which becomes the
// URLLoaderClient for the navigation preload network request.
- network::mojom::URLLoaderClientPtr url_loader_client_ptr;
+ network::mojom::URLLoaderClientPtr inner_url_loader_client;
preload_handle_->url_loader_client_request =
- mojo::MakeRequest(&url_loader_client_ptr);
+ mojo::MakeRequest(&inner_url_loader_client);
auto url_loader_client = std::make_unique<DelegatingURLLoaderClient>(
- std::move(url_loader_client_ptr), std::move(on_response),
+ std::move(inner_url_loader_client), std::move(on_response),
resource_request);
// Start the network request for the URL using the network loader.
// TODO(falken): What to do about routing_id, request_id?
- network::mojom::URLLoaderClientPtr url_loader_client_ptr_to_pass;
- url_loader_client->Bind(&url_loader_client_ptr_to_pass);
- network::mojom::URLLoaderPtr url_loader_associated_ptr;
+ network::mojom::URLLoaderClientPtr url_loader_client_to_pass;
+ url_loader_client->Bind(&url_loader_client_to_pass);
+ network::mojom::URLLoaderPtr url_loader;
url_loader_factory_getter->GetNetworkFactory()->CreateLoaderAndStart(
- mojo::MakeRequest(&url_loader_associated_ptr), -1 /* routing_id? */,
+ mojo::MakeRequest(&url_loader), -1 /* routing_id? */,
-1 /* request_id? */, network::mojom::kURLLoadOptionNone,
- resource_request, std::move(url_loader_client_ptr_to_pass),
+ resource_request, std::move(url_loader_client_to_pass),
net::MutableNetworkTrafficAnnotationTag(
kNavigationPreloadTrafficAnnotation));
- // Hook the load up to DelegatingURLLoader, which will call our
- // DelegatingURLLoaderClient.
- auto url_loader = std::make_unique<DelegatingURLLoader>(
- std::move(url_loader_associated_ptr));
- preload_handle_->url_loader =
- url_loader->CreateInterfacePtrAndBind().PassInterface();
+ preload_handle_->url_loader = url_loader.PassInterface();
DCHECK(!url_loader_assets_);
// Unlike the non-S13N code path, we don't own the URLLoaderFactory being used
// (it's the generic network factory), so we don't need to pass it to
// URLLoaderAssets to keep it alive.
- std::unique_ptr<network::mojom::URLLoaderFactory> null_factory;
url_loader_assets_ = base::MakeRefCounted<URLLoaderAssets>(
- std::move(null_factory), std::move(url_loader),
- std::move(url_loader_client));
+ nullptr /* url_loader_factory */, std::move(url_loader_client));
return true;
}
diff --git a/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.h b/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.h
index 29c19dca1fe..c8024ab6147 100644
--- a/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.h
+++ b/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.h
@@ -16,7 +16,6 @@
#include "content/browser/service_worker/service_worker_metrics.h"
#include "content/common/content_export.h"
#include "content/common/service_worker/service_worker.mojom.h"
-#include "content/common/service_worker/service_worker_types.h"
#include "content/public/common/resource_type.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "net/log/net_log_with_source.h"
@@ -24,6 +23,7 @@
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
#include "third_party/blink/public/mojom/blob/blob.mojom.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_response.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom.h"
namespace net {
@@ -49,9 +49,8 @@ class CONTENT_EXPORT ServiceWorkerFetchDispatcher {
using FetchCallback =
base::OnceCallback<void(blink::ServiceWorkerStatusCode,
FetchEventResult,
- const ServiceWorkerResponse&,
+ blink::mojom::FetchAPIResponsePtr,
blink::mojom::ServiceWorkerStreamHandlePtr,
- blink::mojom::BlobPtr,
scoped_refptr<ServiceWorkerVersion>)>;
// |request_body_*| and |client_id| are used in non-S13nServiceWorker only.
@@ -98,14 +97,12 @@ class CONTENT_EXPORT ServiceWorkerFetchDispatcher {
void DidFail(blink::ServiceWorkerStatusCode status);
void DidFinish(int request_id,
FetchEventResult fetch_result,
- const ServiceWorkerResponse& response,
- blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream,
- blink::mojom::BlobPtr body_as_blob);
+ blink::mojom::FetchAPIResponsePtr response,
+ blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream);
void Complete(blink::ServiceWorkerStatusCode status,
FetchEventResult fetch_result,
- const ServiceWorkerResponse& response,
- blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream,
- blink::mojom::BlobPtr body_as_blob);
+ blink::mojom::FetchAPIResponsePtr response,
+ blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream);
// The fetch event stays open until all respondWith() and waitUntil() promises
// are settled. This function is called once the renderer signals that
diff --git a/chromium/content/browser/service_worker/service_worker_internals_ui.cc b/chromium/content/browser/service_worker/service_worker_internals_ui.cc
index 3b93dc19aa0..3af388b83b0 100644
--- a/chromium/content/browser/service_worker/service_worker_internals_ui.cc
+++ b/chromium/content/browser/service_worker/service_worker_internals_ui.cc
@@ -261,6 +261,7 @@ class ServiceWorkerInternalsUI::PartitionObserver
Value(base::Int64ToString(version_id)));
}
void OnVersionStateChanged(int64_t version_id,
+ const GURL& scope,
ServiceWorkerVersion::Status) override {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
web_ui_->CallJavascriptFunctionUnsafe(
diff --git a/chromium/content/browser/service_worker/service_worker_job_unittest.cc b/chromium/content/browser/service_worker/service_worker_job_unittest.cc
index 724ffb5a524..9de6ec76b1f 100644
--- a/chromium/content/browser/service_worker/service_worker_job_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_job_unittest.cc
@@ -24,7 +24,6 @@
#include "content/browser/service_worker/service_worker_registration_object_host.h"
#include "content/browser/service_worker/service_worker_registration_status.h"
#include "content/browser/service_worker/service_worker_test_utils.h"
-#include "content/common/service_worker/service_worker_messages.h"
#include "content/common/service_worker/service_worker_utils.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
@@ -862,13 +861,14 @@ void WriteResponse(ServiceWorkerStorage* storage,
std::unique_ptr<ServiceWorkerResponseWriter> writer =
storage->CreateResponseWriter(id);
- std::unique_ptr<net::HttpResponseInfo> info(new net::HttpResponseInfo);
+ std::unique_ptr<net::HttpResponseInfo> info =
+ std::make_unique<net::HttpResponseInfo>();
info->request_time = base::Time::Now();
info->response_time = base::Time::Now();
info->was_cached = false;
info->headers = new net::HttpResponseHeaders(headers);
scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
- new HttpResponseInfoIOBuffer(info.release());
+ base::MakeRefCounted<HttpResponseInfoIOBuffer>(std::move(info));
int rv = -1234;
writer->WriteInfo(info_buffer.get(), base::BindOnce(&OnIOComplete, &rv));
diff --git a/chromium/content/browser/service_worker/service_worker_metrics.cc b/chromium/content/browser/service_worker/service_worker_metrics.cc
index 40bd68cfec9..19d807e0725 100644
--- a/chromium/content/browser/service_worker/service_worker_metrics.cc
+++ b/chromium/content/browser/service_worker/service_worker_metrics.cc
@@ -9,6 +9,7 @@
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
+#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
#include "base/time/time.h"
#include "content/browser/service_worker/embedded_worker_status.h"
@@ -22,7 +23,7 @@ namespace content {
namespace {
-std::string StartSituationToSuffix(
+const char* StartSituationToSuffix(
ServiceWorkerMetrics::StartSituation situation) {
// Don't change these returned strings. They are written (in hashed form) into
// logs.
@@ -44,18 +45,28 @@ std::string StartSituationToSuffix(
}
// TODO(falken): Remove this when the associated UMA are removed.
-std::string StartSituationToDeprecatedSuffix(
+const char* StartSituationToDeprecatedSuffix(
ServiceWorkerMetrics::StartSituation situation) {
// Don't change this returned string. It is written (in hashed form) into
// logs.
- std::string suffix = StartSituationToSuffix(situation);
- // Replace '.' separator with '_'.
- DCHECK(suffix.length() > 1 && suffix[0] == '.');
- suffix[0] = '_';
- return suffix;
+ switch (situation) {
+ case ServiceWorkerMetrics::StartSituation::UNKNOWN:
+ NOTREACHED();
+ return "_Unknown";
+ case ServiceWorkerMetrics::StartSituation::DURING_STARTUP:
+ return "_DuringStartup";
+ case ServiceWorkerMetrics::StartSituation::NEW_PROCESS:
+ return "_NewProcess";
+ case ServiceWorkerMetrics::StartSituation::EXISTING_UNREADY_PROCESS:
+ return "_ExistingUnreadyProcess";
+ case ServiceWorkerMetrics::StartSituation::EXISTING_READY_PROCESS:
+ return "_ExistingReadyProcess";
+ }
+ NOTREACHED() << static_cast<int>(situation);
+ return "_Unknown";
}
-std::string EventTypeToSuffix(ServiceWorkerMetrics::EventType event_type) {
+const char* EventTypeToSuffix(ServiceWorkerMetrics::EventType event_type) {
// Don't change these returned strings. They are written (in hashed form) into
// logs.
switch (event_type) {
@@ -99,8 +110,6 @@ std::string EventTypeToSuffix(ServiceWorkerMetrics::EventType event_type) {
return "_BACKGROUND_FETCH_CLICK";
case ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_FAIL:
return "_BACKGROUND_FETCH_FAIL";
- case ServiceWorkerMetrics::EventType::BACKGROUND_FETCHED:
- return "_BACKGROUND_FETCHED";
case ServiceWorkerMetrics::EventType::NAVIGATION_HINT:
return "_NAVIGATION_HINT";
case ServiceWorkerMetrics::EventType::CAN_MAKE_PAYMENT:
@@ -109,8 +118,10 @@ std::string EventTypeToSuffix(ServiceWorkerMetrics::EventType event_type) {
return "_ABORT_PAYMENT";
case ServiceWorkerMetrics::EventType::COOKIE_CHANGE:
return "_COOKIE_CHANGE";
- case ServiceWorkerMetrics::EventType::NUM_TYPES:
- NOTREACHED() << static_cast<int>(event_type);
+ case ServiceWorkerMetrics::EventType::LONG_RUNNING_MESSAGE:
+ return "_LONG_RUNNING_MESSAGE";
+ case ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_SUCCESS:
+ return "_BACKGROUND_FETCH_SUCCESS";
}
return "_UNKNOWN";
}
@@ -147,12 +158,11 @@ ServiceWorkerMetrics::WorkerPreparationType GetWorkerPreparationType(
return Preparation::UNKNOWN;
}
-std::string GetWorkerPreparationSuffix(
+const char* GetWorkerPreparationSuffix(
ServiceWorkerMetrics::WorkerPreparationType status) {
using Preparation = ServiceWorkerMetrics::WorkerPreparationType;
switch (status) {
case Preparation::UNKNOWN:
- case Preparation::NUM_TYPES:
break;
case Preparation::START_DURING_STARTUP:
return "_StartWorkerDuringStartup";
@@ -173,44 +183,6 @@ std::string GetWorkerPreparationSuffix(
return "_UNKNOWN";
}
-// Use this for histograms with dynamically generated names, which
-// otherwise can't use the UMA_HISTOGRAM macro without code duplication.
-void RecordSuffixedTimeHistogram(const std::string& name,
- const std::string& suffix,
- base::TimeDelta sample) {
- const std::string name_with_suffix = name + suffix;
- // This unrolls UMA_HISTOGRAM_TIMES.
- base::HistogramBase* histogram_pointer = base::Histogram::FactoryTimeGet(
- name_with_suffix, base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromSeconds(10), 50,
- base::HistogramBase::kUmaTargetedHistogramFlag);
- histogram_pointer->AddTime(sample);
-}
-
-// Use this for histograms with dynamically generated names, which
-// otherwise can't use the UMA_MEDIUM_HISTOGRAM macro without code duplication.
-void RecordSuffixedMediumTimeHistogram(const std::string& name,
- const std::string& suffix,
- base::TimeDelta sample) {
- const std::string name_with_suffix = name + suffix;
- // This unrolls UMA_HISTOGRAM_MEDIUM_TIMES.
- base::HistogramBase* histogram_pointer = base::Histogram::FactoryTimeGet(
- name_with_suffix, base::TimeDelta::FromMilliseconds(10),
- base::TimeDelta::FromMinutes(3), 50,
- base::HistogramBase::kUmaTargetedHistogramFlag);
- histogram_pointer->AddTime(sample);
-}
-
-// Use this for histograms with dynamically generated names, which
-// otherwise can't use the UMA_HISTOGRAM macro without code duplication.
-void RecordHistogramEnum(const std::string& name, int value, int max_value) {
- // This unrolls UMA_HISTOGRAM_ENUMERATION.
- base::HistogramBase* histogram_pointer = base::LinearHistogram::FactoryGet(
- name, 1, max_value, max_value + 1,
- base::HistogramBase::kUmaTargetedHistogramFlag);
- histogram_pointer->Add(value);
-}
-
void RecordURLMetricOnUI(const std::string& metric_name, const GURL& url) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
GetContentClient()->browser()->RecordURLMetric(metric_name, url);
@@ -277,8 +249,6 @@ const char* ServiceWorkerMetrics::EventTypeToString(EventType event_type) {
return "Background Fetch Click";
case EventType::BACKGROUND_FETCH_FAIL:
return "Background Fetch Fail";
- case EventType::BACKGROUND_FETCHED:
- return "Background Fetched";
case EventType::NAVIGATION_HINT:
return "Navigation Hint";
case EventType::CAN_MAKE_PAYMENT:
@@ -287,8 +257,10 @@ const char* ServiceWorkerMetrics::EventTypeToString(EventType event_type) {
return "Abort Payment";
case EventType::COOKIE_CHANGE:
return "Cookie Change";
- case EventType::NUM_TYPES:
- break;
+ case EventType::LONG_RUNNING_MESSAGE:
+ return "Long Running Message";
+ case EventType::BACKGROUND_FETCH_SUCCESS:
+ return "Background Fetch Success";
}
NOTREACHED() << "Got unexpected event type: " << static_cast<int>(event_type);
return "error";
@@ -329,7 +301,7 @@ ServiceWorkerMetrics::Site ServiceWorkerMetrics::SiteFromURL(const GURL& url) {
return ServiceWorkerMetrics::Site::NEW_TAB_PAGE;
}
- const std::string host = url.host();
+ const base::StringPiece host = url.host_piece();
if (host == "plus.google.com")
return ServiceWorkerMetrics::Site::PLUS;
if (host == "inbox.google.com")
@@ -403,12 +375,9 @@ void ServiceWorkerMetrics::CountControlledPageLoad(Site site,
const GURL& url,
bool is_main_frame_load) {
DCHECK_NE(site, Site::OTHER);
- UMA_HISTOGRAM_ENUMERATION("ServiceWorker.PageLoad", static_cast<int>(site),
- static_cast<int>(Site::NUM_TYPES));
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.PageLoad", site);
if (is_main_frame_load) {
- UMA_HISTOGRAM_ENUMERATION("ServiceWorker.MainFramePageLoad",
- static_cast<int>(site),
- static_cast<int>(Site::NUM_TYPES));
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.MainFramePageLoad", site);
}
if (ShouldExcludeSiteFromHistogram(site))
return;
@@ -429,16 +398,14 @@ void ServiceWorkerMetrics::RecordStartWorkerStatus(
}
UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.Status", status);
- RecordHistogramEnum(
- std::string("ServiceWorker.StartWorker.StatusByPurpose") +
- EventTypeToSuffix(purpose),
- static_cast<uint32_t>(status),
- static_cast<uint32_t>(blink::ServiceWorkerStatusCode::kMaxValue));
- UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.Purpose", purpose,
- EventType::NUM_TYPES);
+ base::UmaHistogramEnumeration(
+ base::StrCat({"ServiceWorker.StartWorker.StatusByPurpose",
+ EventTypeToSuffix(purpose)}),
+ status);
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.Purpose", purpose);
if (status == blink::ServiceWorkerStatusCode::kErrorTimeout) {
UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.Timeout.StartPurpose",
- purpose, EventType::NUM_TYPES);
+ purpose);
}
}
@@ -455,13 +422,14 @@ void ServiceWorkerMetrics::RecordStartWorkerTime(base::TimeDelta time,
EventType purpose) {
if (is_installed) {
UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.StartWorker.Time", time);
- RecordSuffixedMediumTimeHistogram(
- "ServiceWorker.StartWorker.Time",
- StartSituationToDeprecatedSuffix(start_situation), time);
- RecordSuffixedMediumTimeHistogram(
- "ServiceWorker.StartWorker.Time",
- StartSituationToDeprecatedSuffix(start_situation) +
- EventTypeToSuffix(purpose),
+ base::UmaHistogramMediumTimes(
+ base::StrCat({"ServiceWorker.StartWorker.Time",
+ StartSituationToDeprecatedSuffix(start_situation)}),
+ time);
+ base::UmaHistogramMediumTimes(
+ base::StrCat({"ServiceWorker.StartWorker.Time",
+ StartSituationToDeprecatedSuffix(start_situation),
+ EventTypeToSuffix(purpose)}),
time);
} else {
UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.StartNewWorker.Time", time);
@@ -478,18 +446,15 @@ void ServiceWorkerMetrics::RecordActivatedWorkerPreparationForMainFrame(
WorkerPreparationType preparation =
GetWorkerPreparationType(initial_worker_status, start_situation);
UMA_HISTOGRAM_ENUMERATION(
- "ServiceWorker.ActivatedWorkerPreparationForMainFrame.Type",
- static_cast<int>(preparation),
- static_cast<int>(WorkerPreparationType::NUM_TYPES));
+ "ServiceWorker.ActivatedWorkerPreparationForMainFrame.Type", preparation);
std::string suffix =
GetContentClient()->browser()->GetMetricSuffixForURL(url);
if (!suffix.empty()) {
- RecordHistogramEnum(
- std::string(
- "ServiceWorker.ActivatedWorkerPreparationForMainFrame.Type.") +
- suffix,
- static_cast<int>(preparation),
- static_cast<int>(WorkerPreparationType::NUM_TYPES) - 1);
+ base::UmaHistogramEnumeration(
+ base::StrCat(
+ {"ServiceWorker.ActivatedWorkerPreparationForMainFrame.Type.",
+ suffix}),
+ preparation);
}
if (did_navigation_preload) {
@@ -501,8 +466,7 @@ void ServiceWorkerMetrics::RecordActivatedWorkerPreparationForMainFrame(
UMA_HISTOGRAM_ENUMERATION(
"ServiceWorker.ActivatedWorkerPreparationForMainFrame.Type_"
"NavigationPreloadEnabled",
- static_cast<int>(preparation),
- static_cast<int>(WorkerPreparationType::NUM_TYPES));
+ preparation);
}
// Don't record .Time if S13nServiceWorker is enabled.
@@ -515,9 +479,10 @@ void ServiceWorkerMetrics::RecordActivatedWorkerPreparationForMainFrame(
"ServiceWorker.ActivatedWorkerPreparationForMainFrame.Time", time);
// Record the preparation time using the worker preparation suffix.
- RecordSuffixedMediumTimeHistogram(
- "ServiceWorker.ActivatedWorkerPreparationForMainFrame.Time",
- GetWorkerPreparationSuffix(preparation), time);
+ base::UmaHistogramMediumTimes(
+ base::StrCat({"ServiceWorker.ActivatedWorkerPreparationForMainFrame.Time",
+ GetWorkerPreparationSuffix(preparation)}),
+ time);
// Record the preparation time using the navigation preload suffix.
if (did_navigation_preload) {
@@ -536,9 +501,7 @@ void ServiceWorkerMetrics::RecordActivatedWorkerPreparationForMainFrame(
}
void ServiceWorkerMetrics::RecordWorkerStopped(StopStatus status) {
- UMA_HISTOGRAM_ENUMERATION("ServiceWorker.WorkerStopped",
- static_cast<int>(status),
- static_cast<int>(StopStatus::NUM_TYPES));
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.WorkerStopped", status);
}
void ServiceWorkerMetrics::RecordStopWorkerTime(base::TimeDelta time) {
@@ -565,15 +528,14 @@ void ServiceWorkerMetrics::RecordInstallEventStatus(
void ServiceWorkerMetrics::RecordEventDispatchingDelay(EventType event_type,
base::TimeDelta time) {
- const std::string name = "ServiceWorker.EventDispatchingDelay";
- UMA_HISTOGRAM_TIMES(name, time);
- RecordSuffixedTimeHistogram(name, EventTypeToSuffix(event_type), time);
+ static constexpr char kName[] = "ServiceWorker.EventDispatchingDelay";
+ UMA_HISTOGRAM_TIMES(kName, time);
+ base::UmaHistogramTimes(base::StrCat({kName, EventTypeToSuffix(event_type)}),
+ time);
}
void ServiceWorkerMetrics::RecordEventTimeout(EventType event) {
- UMA_HISTOGRAM_ENUMERATION("ServiceWorker.RequestTimeouts.Count",
- static_cast<int>(event),
- static_cast<int>(EventType::NUM_TYPES));
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.RequestTimeouts.Count", event);
}
void ServiceWorkerMetrics::RecordEventDuration(EventType event,
@@ -653,9 +615,9 @@ void ServiceWorkerMetrics::RecordEventDuration(EventType event,
UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.BackgroundFetchFailEvent.Time",
time);
break;
- case EventType::BACKGROUND_FETCHED:
- UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.BackgroundFetchedEvent.Time",
- time);
+ case EventType::BACKGROUND_FETCH_SUCCESS:
+ UMA_HISTOGRAM_MEDIUM_TIMES(
+ "ServiceWorker.BackgroundFetchSuccessEvent.Time", time);
break;
case EventType::CAN_MAKE_PAYMENT:
UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.CanMakePaymentEvent.Time",
@@ -667,11 +629,14 @@ void ServiceWorkerMetrics::RecordEventDuration(EventType event,
case EventType::COOKIE_CHANGE:
UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.CookieChangeEvent.Time", time);
break;
+ case EventType::LONG_RUNNING_MESSAGE:
+ // Since this event is expected to last indefinitely we don't need to log
+ // how long they actually last.
+ break;
case EventType::NAVIGATION_HINT:
// The navigation hint should not be sent as an event.
case EventType::UNKNOWN:
- case EventType::NUM_TYPES:
NOTREACHED() << "Invalid event type";
break;
}
@@ -743,9 +708,10 @@ void ServiceWorkerMetrics::RecordStartWorkerTiming(const StartTimes& times,
// Total duration.
UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.StartTiming.Duration",
times.local_end - times.local_start);
- RecordSuffixedMediumTimeHistogram("ServiceWorker.StartTiming.Duration",
- StartSituationToSuffix(situation),
- times.local_end - times.local_start);
+ base::UmaHistogramMediumTimes(
+ base::StrCat({"ServiceWorker.StartTiming.Duration",
+ StartSituationToSuffix(situation)}),
+ times.local_end - times.local_start);
// SentStartWorker milestone.
UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.StartTiming.StartToSentStartWorker",
@@ -785,8 +751,7 @@ void ServiceWorkerMetrics::RecordStartWorkerTiming(const StartTimes& times,
void ServiceWorkerMetrics::RecordStartWorkerTimingClockConsistency(
CrossProcessTimeDelta type) {
- UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartTiming.ClockConsistency", type,
- CrossProcessTimeDelta::NUM_TYPES);
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartTiming.ClockConsistency", type);
}
void ServiceWorkerMetrics::RecordStartStatusAfterFailure(
@@ -848,8 +813,7 @@ void ServiceWorkerMetrics::RecordNavigationPreloadResponse(
GetWorkerPreparationType(initial_worker_status, start_situation);
UMA_HISTOGRAM_ENUMERATION(
- "ServiceWorker.NavPreload.WorkerPreparationType_MainFrame", preparation,
- WorkerPreparationType::NUM_TYPES);
+ "ServiceWorker.NavPreload.WorkerPreparationType_MainFrame", preparation);
UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.NavPreload.ResponseTime_MainFrame",
response_start);
UMA_HISTOGRAM_BOOLEAN("ServiceWorker.NavPreload.FinishedFirst_MainFrame",
@@ -887,31 +851,28 @@ void ServiceWorkerMetrics::RecordContextRequestHandlerStatus(
ServiceWorkerContextRequestHandler::CreateJobStatus status,
bool is_installed,
bool is_main_script) {
- const int value = static_cast<int>(status);
- const int max = static_cast<int>(
- ServiceWorkerContextRequestHandler::CreateJobStatus::NUM_TYPES);
if (is_installed) {
if (is_main_script) {
UMA_HISTOGRAM_ENUMERATION(
"ServiceWorker.ContextRequestHandlerStatus.InstalledWorker."
"MainScript",
- value, max);
+ status);
} else {
UMA_HISTOGRAM_ENUMERATION(
"ServiceWorker.ContextRequestHandlerStatus.InstalledWorker."
"ImportedScript",
- value, max);
+ status);
}
} else {
if (is_main_script) {
UMA_HISTOGRAM_ENUMERATION(
"ServiceWorker.ContextRequestHandlerStatus.NewWorker.MainScript",
- value, max);
+ status);
} else {
UMA_HISTOGRAM_ENUMERATION(
"ServiceWorker.ContextRequestHandlerStatus.NewWorker."
"ImportedScript",
- value, max);
+ status);
}
}
}
@@ -942,13 +903,18 @@ void ServiceWorkerMetrics::RecordUninstalledScriptImport(const GURL& url) {
void ServiceWorkerMetrics::RecordStartServiceWorkerForNavigationHintResult(
StartServiceWorkerForNavigationHintResult result) {
- UMA_HISTOGRAM_ENUMERATION(
- "ServiceWorker.StartForNavigationHint.Result", result,
- StartServiceWorkerForNavigationHintResult::NUM_TYPES);
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartForNavigationHint.Result",
+ result);
}
void ServiceWorkerMetrics::RecordRegisteredOriginCount(size_t origin_count) {
UMA_HISTOGRAM_COUNTS_1M("ServiceWorker.RegisteredOriginCount", origin_count);
}
+void ServiceWorkerMetrics::RecordMainResourceRequestDestination(
+ MainResourceRequestDestination destination) {
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.MainResourceRequestDestination",
+ destination);
+}
+
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_metrics.h b/chromium/content/browser/service_worker/service_worker_metrics.h
index d4a4a6bea09..a0898955023 100644
--- a/chromium/content/browser/service_worker/service_worker_metrics.h
+++ b/chromium/content/browser/service_worker/service_worker_metrics.h
@@ -29,6 +29,46 @@ enum class EmbeddedWorkerStatus;
class ServiceWorkerMetrics {
public:
// Used for UMA. Append-only.
+ enum class MainResourceRequestDestination {
+ // The request was routed to the service worker. Fetch event dispatching
+ // possibly succeeded or failed.
+ // ServiceWorker.FetchEvent.MainResource.Status was logged with the result
+ // of the dispatch.
+ kServiceWorker = 0,
+
+ // The request was routed to network for the specified reason.
+ kNetworkBecauseNoActiveVersion = 1,
+ kNetworkBecauseNoActiveVersionAfterContinuing = 2,
+ kNetworkBecauseNoContext = 3,
+ kNetworkBecauseNoFetchEventHandler = 4,
+ kNetworkBecauseNoProvider = 5,
+ kNetworkBecauseNoProviderAfterContinuing = 6,
+ kNetworkBecauseNoRegistration = 7,
+ kNetworkBecauseNotAllowed = 8,
+ kNetworkBecauseNotSecure = 9,
+
+ // The loader couldn't dispatch the fetch event because there was no active
+ // worker.
+ kErrorNoActiveWorkerFromDelegate = 10,
+ // The loader couldn't dispatch the fetch event because the request body
+ // failed.
+ kErrorRequestBodyFailed = 11,
+
+ // The request was being routed to the service worker, but the handler was
+ // destroyed before the result of the fetch event dispatch was received.
+ kAbortedWhileDispatchingFetchEvent = 12,
+ // The handler was destroyed without dispatching a fetch event to the
+ // service
+ // worker.
+ kAbortedWithoutDispatchingFetchEvent = 13,
+
+ // The request was not routed because it was cancelled.
+ kJobWasCancelled = 14,
+
+ kMaxValue = 14,
+ };
+
+ // Used for UMA. Append-only.
enum ReadResponseResult {
READ_OK,
READ_HEADERS_ERROR,
@@ -128,7 +168,7 @@ class ServiceWorkerMetrics {
DETACH_BY_REGISTRY,
TIMEOUT,
// Add new types here.
- NUM_TYPES
+ kMaxValue = TIMEOUT,
};
// Used for UMA. Append-only.
@@ -168,13 +208,15 @@ class ServiceWorkerMetrics {
BACKGROUND_FETCH_ABORT = 23,
BACKGROUND_FETCH_CLICK = 24,
BACKGROUND_FETCH_FAIL = 25,
- BACKGROUND_FETCHED = 26,
+ // BACKGROUND_FETCHED = 26, // Obsolete
NAVIGATION_HINT = 27,
CAN_MAKE_PAYMENT = 28,
ABORT_PAYMENT = 29,
COOKIE_CHANGE = 30,
+ LONG_RUNNING_MESSAGE = 31,
+ BACKGROUND_FETCH_SUCCESS = 32,
// Add new events to record here.
- NUM_TYPES
+ kMaxValue = BACKGROUND_FETCH_SUCCESS,
};
// Used for UMA. Append only.
@@ -187,7 +229,7 @@ class ServiceWorkerMetrics {
PLUS,
INBOX,
DOCS,
- NUM_TYPES
+ kMaxValue = DOCS,
};
// Not used for UMA.
@@ -234,7 +276,7 @@ class ServiceWorkerMetrics {
// existing ready process.
START_IN_EXISTING_READY_PROCESS = 8,
// Add new types here.
- NUM_TYPES
+ kMaxValue = START_IN_EXISTING_READY_PROCESS,
};
// Used for UMA. Append only.
@@ -244,7 +286,7 @@ class ServiceWorkerMetrics {
NEGATIVE,
INACCURATE_CLOCK,
// Add new types here.
- NUM_TYPES
+ kMaxValue = INACCURATE_CLOCK,
};
// These are prefixed with "local" or "remote" to indicate whether the browser
@@ -443,6 +485,9 @@ class ServiceWorkerMetrics {
// Records the number of origins with a registered service worker.
static void RecordRegisteredOriginCount(size_t origin_count);
+ static void RecordMainResourceRequestDestination(
+ MainResourceRequestDestination destination);
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ServiceWorkerMetrics);
};
diff --git a/chromium/content/browser/service_worker/service_worker_navigation_loader.cc b/chromium/content/browser/service_worker/service_worker_navigation_loader.cc
index 24fa5a697bc..79f9270e1c1 100644
--- a/chromium/content/browser/service_worker/service_worker_navigation_loader.cc
+++ b/chromium/content/browser/service_worker/service_worker_navigation_loader.cc
@@ -25,7 +25,7 @@ namespace {
std::string ComposeFetchEventResultString(
ServiceWorkerFetchDispatcher::FetchEventResult result,
- const ServiceWorkerResponse& response) {
+ const blink::mojom::FetchAPIResponse& response) {
if (result == ServiceWorkerFetchDispatcher::FetchEventResult::kShouldFallback)
return "Fallback to network";
std::stringstream stream;
@@ -85,25 +85,31 @@ class ServiceWorkerNavigationLoader::StreamWaiter
ServiceWorkerNavigationLoader::ServiceWorkerNavigationLoader(
NavigationLoaderInterceptor::LoaderCallback callback,
+ NavigationLoaderInterceptor::FallbackCallback fallback_callback,
Delegate* delegate,
- const network::ResourceRequest& resource_request,
+ const network::ResourceRequest& tentative_resource_request,
scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter)
: loader_callback_(std::move(callback)),
+ fallback_callback_(std::move(fallback_callback)),
delegate_(delegate),
- resource_request_(resource_request),
url_loader_factory_getter_(std::move(url_loader_factory_getter)),
binding_(this),
weak_factory_(this) {
TRACE_EVENT_WITH_FLOW1(
"ServiceWorker",
"ServiceWorkerNavigationLoader::ServiceWorkerNavigationloader", this,
- TRACE_EVENT_FLAG_FLOW_OUT, "url", resource_request_.url.spec());
+ TRACE_EVENT_FLAG_FLOW_OUT, "url", tentative_resource_request.url.spec());
+ DCHECK(delegate_);
DCHECK(ServiceWorkerUtils::IsMainResourceType(
- static_cast<ResourceType>(resource_request.resource_type)));
+ static_cast<ResourceType>(tentative_resource_request.resource_type)));
response_head_.load_timing.request_start = base::TimeTicks::Now();
response_head_.load_timing.request_start_time = base::Time::Now();
+
+ // Beware that the final resource request may change due to throttles, so
+ // don't save |tentative_resource_request| here. We'll get the real one in
+ // StartRequest.
}
ServiceWorkerNavigationLoader::~ServiceWorkerNavigationLoader() {
@@ -134,19 +140,26 @@ void ServiceWorkerNavigationLoader::ForwardToServiceWorker() {
"ServiceWorker", "ServiceWorkerNavigationLoader::ForwardToServiceWorker",
this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
response_type_ = ResponseType::FORWARD_TO_SERVICE_WORKER;
- StartRequest();
+
+ std::move(loader_callback_)
+ .Run(base::BindOnce(&ServiceWorkerNavigationLoader::StartRequest,
+ weak_factory_.GetWeakPtr()));
}
bool ServiceWorkerNavigationLoader::ShouldFallbackToNetwork() {
return response_type_ == ResponseType::FALLBACK_TO_NETWORK;
}
+bool ServiceWorkerNavigationLoader::ShouldForwardToServiceWorker() {
+ return response_type_ == ResponseType::FORWARD_TO_SERVICE_WORKER;
+}
+
bool ServiceWorkerNavigationLoader::WasCanceled() const {
return status_ == Status::kCancelled;
}
void ServiceWorkerNavigationLoader::DetachedFromRequest() {
- detached_from_request_ = true;
+ delegate_ = nullptr;
DeleteIfNeeded();
}
@@ -155,7 +168,21 @@ ServiceWorkerNavigationLoader::AsWeakPtr() {
return weak_factory_.GetWeakPtr();
}
-void ServiceWorkerNavigationLoader::StartRequest() {
+void ServiceWorkerNavigationLoader::StartRequest(
+ const network::ResourceRequest& resource_request,
+ network::mojom::URLLoaderRequest request,
+ network::mojom::URLLoaderClientPtr client) {
+ resource_request_ = resource_request;
+
+ DCHECK(delegate_);
+ DCHECK(!binding_.is_bound());
+ DCHECK(!url_loader_client_.is_bound());
+ binding_.Bind(std::move(request));
+ binding_.set_connection_error_handler(
+ base::BindOnce(&ServiceWorkerNavigationLoader::OnConnectionClosed,
+ base::Unretained(this)));
+ url_loader_client_ = std::move(client);
+
DCHECK_EQ(ResponseType::FORWARD_TO_SERVICE_WORKER, response_type_);
DCHECK_EQ(Status::kNotStarted, status_);
status_ = Status::kStarted;
@@ -169,14 +196,18 @@ void ServiceWorkerNavigationLoader::StartRequest() {
ServiceWorkerVersion* active_worker =
delegate_->GetServiceWorkerVersion(&result);
if (!active_worker) {
- ReturnNetworkError();
+ delegate_->ReportDestination(
+ ServiceWorkerMetrics::MainResourceRequestDestination::
+ kErrorNoActiveWorkerFromDelegate);
+ CommitCompleted(net::ERR_FAILED);
return;
}
// ServiceWorkerFetchDispatcher requires a std::unique_ptr<ResourceRequest>
// so make one here.
// TODO(crbug.com/803125): Try to eliminate unnecessary copying?
- auto request = std::make_unique<network::ResourceRequest>(resource_request_);
+ auto resource_request_to_pass =
+ std::make_unique<network::ResourceRequest>(resource_request_);
// Passing the request body over Mojo moves out the DataPipeGetter elements,
// which would mean we should clone the body like
@@ -184,13 +215,15 @@ void ServiceWorkerNavigationLoader::StartRequest() {
// here yet: they are only created by the renderer when converting from a
// Blob, which doesn't happen for navigations. In interest of speed, just
// don't clone until proven necessary.
- DCHECK(BodyHasNoDataPipeGetters(request->request_body.get()))
+ DCHECK(BodyHasNoDataPipeGetters(resource_request_to_pass->request_body.get()))
<< "We assumed there would be no data pipe getter elements here, but "
"there are. Add code here to clone the body before proceeding.";
// Dispatch the fetch event.
+ delegate_->WillDispatchFetchEventForMainResource();
fetch_dispatcher_ = std::make_unique<ServiceWorkerFetchDispatcher>(
- std::move(request), std::string() /* request_body_blob_uuid */,
+ std::move(resource_request_to_pass),
+ std::string() /* request_body_blob_uuid */,
0 /* request_body_blob_size */, nullptr /* request_body_blob */,
std::string() /* client_id */, active_worker,
net::NetLogWithSource() /* TODO(scottmg): net log? */,
@@ -239,19 +272,6 @@ void ServiceWorkerNavigationLoader::CommitCompleted(int error_code) {
network::URLLoaderCompletionStatus(error_code));
}
-void ServiceWorkerNavigationLoader::ReturnNetworkError() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- TRACE_EVENT_WITH_FLOW0(
- "ServiceWorker", "ServiceWorkerNavigationLoader::ReturnNetworkError",
- this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
-
- DCHECK(!url_loader_client_.is_bound());
- DCHECK(loader_callback_);
- std::move(loader_callback_)
- .Run(base::BindOnce(&ServiceWorkerNavigationLoader::StartErrorResponse,
- weak_factory_.GetWeakPtr()));
-}
-
void ServiceWorkerNavigationLoader::DidPrepareFetchEvent(
scoped_refptr<ServiceWorkerVersion> version,
EmbeddedWorkerStatus initial_worker_status) {
@@ -277,9 +297,8 @@ void ServiceWorkerNavigationLoader::DidPrepareFetchEvent(
void ServiceWorkerNavigationLoader::DidDispatchFetchEvent(
blink::ServiceWorkerStatusCode status,
ServiceWorkerFetchDispatcher::FetchEventResult fetch_result,
- const ServiceWorkerResponse& response,
+ blink::mojom::FetchAPIResponsePtr response,
blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream,
- blink::mojom::BlobPtr body_as_blob,
scoped_refptr<ServiceWorkerVersion> version) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -287,26 +306,41 @@ void ServiceWorkerNavigationLoader::DidDispatchFetchEvent(
"ServiceWorker", "ServiceWorkerNavigationLoader::DidDispatchFetchEvent",
this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "status",
blink::ServiceWorkerStatusToString(status), "result",
- ComposeFetchEventResultString(fetch_result, response));
+ ComposeFetchEventResultString(fetch_result, *response));
+
ServiceWorkerMetrics::RecordFetchEventStatus(true /* is_main_resource */,
status);
+ if (delegate_) {
+ delegate_->ReportDestination(
+ ServiceWorkerMetrics::MainResourceRequestDestination::kServiceWorker);
+ }
ServiceWorkerMetrics::URLRequestJobResult result =
ServiceWorkerMetrics::REQUEST_JOB_ERROR_BAD_DELEGATE;
- if (!delegate_->RequestStillValid(&result)) {
- ReturnNetworkError();
+ if (!delegate_ || !delegate_->RequestStillValid(&result)) {
+ // The navigation or shared worker startup is cancelled. Just abort.
+ CommitCompleted(net::ERR_ABORTED);
return;
}
if (status != blink::ServiceWorkerStatusCode::kOk) {
+ // Dispatching the event to the service worker failed. Do a last resort
+ // attempt to load the page via network as if there was no service worker.
+ // It'd be more correct and simpler to remove this path and show an error
+ // page, but the risk is that the user will be stuck if there's a persistent
+ // failure.
delegate_->MainResourceLoadFailed();
- FallbackToNetwork();
+ std::move(fallback_callback_)
+ .Run(true /* reset_subresource_loader_params */);
return;
}
if (fetch_result ==
ServiceWorkerFetchDispatcher::FetchEventResult::kShouldFallback) {
- FallbackToNetwork();
+ // TODO(falken): Propagate the timing info to the renderer somehow, or else
+ // Navigation Timing etc APIs won't know about service worker.
+ std::move(fallback_callback_)
+ .Run(false /* reset_subresource_loader_params */);
return;
}
@@ -315,35 +349,22 @@ void ServiceWorkerNavigationLoader::DidDispatchFetchEvent(
// A response with status code 0 is Blink telling us to respond with
// network error.
- if (response.status_code == 0) {
- ReturnNetworkError();
+ if (response->status_code == 0) {
+ CommitCompleted(net::ERR_FAILED);
return;
}
- std::move(loader_callback_)
- .Run(base::BindOnce(&ServiceWorkerNavigationLoader::StartResponse,
- weak_factory_.GetWeakPtr(), response, version,
- std::move(body_as_stream), std::move(body_as_blob)));
+ StartResponse(std::move(response), std::move(version),
+ std::move(body_as_stream));
}
void ServiceWorkerNavigationLoader::StartResponse(
- const ServiceWorkerResponse& response,
+ blink::mojom::FetchAPIResponsePtr response,
scoped_refptr<ServiceWorkerVersion> version,
- blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream,
- blink::mojom::BlobPtr body_as_blob,
- network::mojom::URLLoaderRequest request,
- network::mojom::URLLoaderClientPtr client) {
- DCHECK(!binding_.is_bound());
- DCHECK(!url_loader_client_.is_bound());
- binding_.Bind(std::move(request));
- binding_.set_connection_error_handler(
- base::BindOnce(&ServiceWorkerNavigationLoader::OnConnectionClosed,
- base::Unretained(this)));
- url_loader_client_ = std::move(client);
-
- ServiceWorkerLoaderHelpers::SaveResponseInfo(response, &response_head_);
+ blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream) {
+ ServiceWorkerLoaderHelpers::SaveResponseInfo(*response, &response_head_);
ServiceWorkerLoaderHelpers::SaveResponseHeaders(
- response.status_code, response.status_text, response.headers,
+ response->status_code, response->status_text, response->headers,
&response_head_);
response_head_.did_service_worker_navigation_preload =
@@ -395,8 +416,9 @@ void ServiceWorkerNavigationLoader::StartResponse(
}
// Handle a blob response body.
- if (body_as_blob) {
- body_as_blob_ = std::move(body_as_blob);
+ if (response->blob) {
+ DCHECK(response->blob->blob.is_valid());
+ body_as_blob_.Bind(std::move(response->blob->blob));
mojo::ScopedDataPipeConsumerHandle data_pipe;
int error = ServiceWorkerLoaderHelpers::ReadBlobResponseBody(
&body_as_blob_, resource_request_.headers,
@@ -426,15 +448,6 @@ void ServiceWorkerNavigationLoader::StartResponse(
CommitCompleted(net::OK);
}
-void ServiceWorkerNavigationLoader::StartErrorResponse(
- network::mojom::URLLoaderRequest request,
- network::mojom::URLLoaderClientPtr client) {
- DCHECK_EQ(Status::kStarted, status_);
- DCHECK(!url_loader_client_.is_bound());
- url_loader_client_ = std::move(client);
- CommitCompleted(net::ERR_FAILED);
-}
-
// URLLoader implementation----------------------------------------
void ServiceWorkerNavigationLoader::FollowRedirect(
@@ -482,7 +495,7 @@ void ServiceWorkerNavigationLoader::OnConnectionClosed() {
}
void ServiceWorkerNavigationLoader::DeleteIfNeeded() {
- if (!binding_.is_bound() && detached_from_request_)
+ if (!binding_.is_bound() && !delegate_)
delete this;
}
diff --git a/chromium/content/browser/service_worker/service_worker_navigation_loader.h b/chromium/content/browser/service_worker/service_worker_navigation_loader.h
index b39480174a3..f31dc270ae8 100644
--- a/chromium/content/browser/service_worker/service_worker_navigation_loader.h
+++ b/chromium/content/browser/service_worker/service_worker_navigation_loader.h
@@ -17,17 +17,16 @@
#include "content/browser/service_worker/service_worker_response_type.h"
#include "content/browser/service_worker/service_worker_url_job_wrapper.h"
#include "content/browser/url_loader_factory_getter.h"
-#include "content/common/service_worker/service_worker_types.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
#include "third_party/blink/public/mojom/blob/blob.mojom.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_response.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_stream_handle.mojom.h"
namespace content {
-struct ServiceWorkerResponse;
class ServiceWorkerVersion;
// S13nServiceWorker:
@@ -60,25 +59,27 @@ class CONTENT_EXPORT ServiceWorkerNavigationLoader
// to the network this will call |loader_callback| with a null
// RequestHandler, which will be then handled by NavigationURLLoaderImpl.
// 2. If it is decided that the request should be sent to the SW,
- // this job dispatches a FetchEvent in StartRequest.
- // 3. In DidDispatchFetchEvent() this job determines the request's
- // final destination, and may still call |loader_callback| with null
- // RequestHandler if it turns out that we need to fallback to the network.
- // 4. Otherwise if the SW returned a stream or blob as a response
- // this job calls |loader_callback| with a RequestHandler bound from
- // StartResponse().
- // 5. Then StartResponse() will be called with a
- // network::mojom::URLLoaderClientPtr that is connected to
- // NavigationURLLoaderImpl (for resource loading for navigation).
- // This forwards the blob/stream data pipe to the NavigationURLLoader if
- // the response body was sent as a blob/stream.
+ // this job calls |loader_callback|, passing StartRequest as the
+ // RequestHandler.
+ // 3. At this point, the NavigationURLLoaderImpl can throttle the request,
+ // and invoke the RequestHandler later with a possibly modified request.
+ // 4. StartRequest is invoked. This dispatches a FetchEvent.
+ // 5. DidDispatchFetchEvent() determines the request's final destination. If
+ // it turns out we need to fallback to network, it calls
+ // |fallback_callback|.
+ // 6. Otherwise if the SW returned a stream or blob as a response
+ // this job passes the response to the network::mojom::URLLoaderClientPtr
+ // connected to NavigationURLLoaderImpl (for resource loading for
+ // navigation), that was given to StartRequest. This forwards the
+ // blob/stream data pipe to the NavigationURLLoader.
//
// Loads for shared workers work similarly, except SharedWorkerScriptLoader
// is used instead of NavigationURLLoaderImpl.
ServiceWorkerNavigationLoader(
NavigationLoaderInterceptor::LoaderCallback loader_callback,
+ NavigationLoaderInterceptor::FallbackCallback fallback_callback,
Delegate* delegate,
- const network::ResourceRequest& resource_request,
+ const network::ResourceRequest& tentative_resource_request,
scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter);
~ServiceWorkerNavigationLoader() override;
@@ -87,6 +88,7 @@ class CONTENT_EXPORT ServiceWorkerNavigationLoader
void FallbackToNetwork();
void ForwardToServiceWorker();
bool ShouldFallbackToNetwork();
+ bool ShouldForwardToServiceWorker();
bool WasCanceled() const;
// The navigation request that was holding this job is
@@ -102,43 +104,27 @@ class CONTENT_EXPORT ServiceWorkerNavigationLoader
class StreamWaiter;
// For FORWARD_TO_SERVICE_WORKER case.
- void StartRequest();
+ void StartRequest(const network::ResourceRequest& resource_request,
+ network::mojom::URLLoaderRequest request,
+ network::mojom::URLLoaderClientPtr client);
void DidPrepareFetchEvent(scoped_refptr<ServiceWorkerVersion> version,
EmbeddedWorkerStatus initial_worker_status);
void DidDispatchFetchEvent(
blink::ServiceWorkerStatusCode status,
ServiceWorkerFetchDispatcher::FetchEventResult fetch_result,
- const ServiceWorkerResponse& response,
+ blink::mojom::FetchAPIResponsePtr response,
blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream,
- blink::mojom::BlobPtr body_as_blob,
scoped_refptr<ServiceWorkerVersion> version);
- // Used as the RequestHandler passed to |loader_callback_| when the service
- // worker chooses to handle a resource request. Returns the response to
- // |client|. |body_as_blob| is kept around until BlobDataHandle is created
- // from blob_uuid just to make sure the blob is kept alive.
- void StartResponse(const ServiceWorkerResponse& response,
+ void StartResponse(blink::mojom::FetchAPIResponsePtr response,
scoped_refptr<ServiceWorkerVersion> version,
- blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream,
- blink::mojom::BlobPtr body_as_blob,
- network::mojom::URLLoaderRequest request,
- network::mojom::URLLoaderClientPtr client);
+ blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream);
- // Used as the RequestHandler passed to |loader_callback_| on error. Returns a
- // network error to |client|.
- void StartErrorResponse(network::mojom::URLLoaderRequest request,
- network::mojom::URLLoaderClientPtr client);
-
- // Calls url_loader_client_->OnReceiveResopnse() with |response_head_|.
+ // Calls url_loader_client_->OnReceiveResponse() with |response_head_|.
void CommitResponseHeaders();
- // Calls url_loader_client_->OnComplete(). Expected to be called after
- // CommitResponseHeaders (i.e. status_ == kSentHeader).
+ // Calls url_loader_client_->OnComplete().
void CommitCompleted(int error_code);
- // Calls |loader_callback_| with StartErrorResponse callback. Must not be
- // called once either StartResponse or StartErrorResponse is called.
- void ReturnNetworkError();
-
// network::mojom::URLLoader:
void FollowRedirect(const base::Optional<std::vector<std::string>>&
to_be_removed_request_headers,
@@ -155,10 +141,22 @@ class CONTENT_EXPORT ServiceWorkerNavigationLoader
void OnConnectionClosed();
void DeleteIfNeeded();
+ void ReportDestination(
+ ServiceWorkerMetrics::MainResourceRequestDestination destination);
+
ResponseType response_type_ = ResponseType::NOT_DETERMINED;
NavigationLoaderInterceptor::LoaderCallback loader_callback_;
+ NavigationLoaderInterceptor::FallbackCallback fallback_callback_;
+
+ // |delegate_| is non-null and owns |this| until DetachedFromRequest() is
+ // called. Once that is called, |delegate_| is reset to null and |this| owns
+ // itself, self-destructing when a connection error on |binding_| occurs.
+ //
+ // Note: A WeakPtr wouldn't be super safe here because the delegate can
+ // conceivably still be alive and used for another loader, after calling
+ // DetachedFromRequest() for this loader.
+ Delegate* delegate_ = nullptr;
- Delegate* delegate_;
network::ResourceRequest resource_request_;
scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter_;
std::unique_ptr<ServiceWorkerFetchDispatcher> fetch_dispatcher_;
@@ -182,8 +180,6 @@ class CONTENT_EXPORT ServiceWorkerNavigationLoader
};
Status status_ = Status::kNotStarted;
- bool detached_from_request_ = false;
-
base::WeakPtrFactory<ServiceWorkerNavigationLoader> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerNavigationLoader);
diff --git a/chromium/content/browser/service_worker/service_worker_navigation_loader_unittest.cc b/chromium/content/browser/service_worker/service_worker_navigation_loader_unittest.cc
index 3b22bc42d71..02010ab2c3e 100644
--- a/chromium/content/browser/service_worker/service_worker_navigation_loader_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_navigation_loader_unittest.cc
@@ -44,6 +44,34 @@ void ReceiveRequestHandler(
*out_handler = std::move(handler);
}
+blink::mojom::FetchAPIResponsePtr OkResponse(
+ blink::mojom::SerializedBlobPtr blob_body) {
+ auto response = blink::mojom::FetchAPIResponse::New();
+ response->status_code = 200;
+ response->status_text = "OK";
+ response->response_type = network::mojom::FetchResponseType::kDefault;
+ response->blob = std::move(blob_body);
+ return response;
+}
+
+blink::mojom::FetchAPIResponsePtr ErrorResponse() {
+ auto response = blink::mojom::FetchAPIResponse::New();
+ response->status_code = 0;
+ response->response_type = network::mojom::FetchResponseType::kDefault;
+ response->error = blink::mojom::ServiceWorkerResponseError::kPromiseRejected;
+ return response;
+}
+
+blink::mojom::FetchAPIResponsePtr RedirectResponse(
+ const std::string& redirect_location_header) {
+ auto response = blink::mojom::FetchAPIResponse::New();
+ response->status_code = 301;
+ response->status_text = "Moved Permanently";
+ response->response_type = network::mojom::FetchResponseType::kDefault;
+ response->headers["Location"] = redirect_location_header;
+ return response;
+}
+
// NavigationPreloadLoaderClient mocks the renderer-side URLLoaderClient for the
// navigation preload network request performed by the browser. In production
// code, this is ServiceWorkerContextClient::NavigationPreloadRequest,
@@ -71,7 +99,7 @@ class NavigationPreloadLoaderClient final
public:
NavigationPreloadLoaderClient(
blink::mojom::FetchEventPreloadHandlePtr preload_handle,
- mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
+ blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
mojom::ServiceWorker::DispatchFetchEventCallback finish_callback)
: url_loader_(std::move(preload_handle->url_loader)),
binding_(this, std::move(preload_handle->url_loader_client_request)),
@@ -102,21 +130,14 @@ class NavigationPreloadLoaderClient final
// Simulate passing the navigation preload response to
// FetchEvent#respondWith.
+ auto response = blink::mojom::FetchAPIResponse::New();
+ response->url_list =
+ std::vector<GURL>(response_head_.url_list_via_service_worker);
+ response->status_code = response_head_.headers->response_code();
+ response->status_text = response_head_.headers->GetStatusText();
+ response->response_type = response_head_.response_type;
response_callback_->OnResponseStream(
- ServiceWorkerResponse(
- std::make_unique<std::vector<GURL>>(
- response_head_.url_list_via_service_worker),
- response_head_.headers->response_code(),
- response_head_.headers->GetStatusText(),
- response_head_.response_type_via_service_worker,
- std::make_unique<ServiceWorkerHeaderMap>(), "" /* blob_uuid */,
- 0 /* blob_size */, nullptr /* blob */,
- blink::mojom::ServiceWorkerResponseError::kUnknown, base::Time(),
- false /* response_is_in_cache_storage */,
- std::string() /* response_cache_storage_cache_name */,
- std::make_unique<
- ServiceWorkerHeaderList>() /* cors_exposed_header_names */),
- std::move(stream_handle), base::Time::Now());
+ std::move(response), std::move(stream_handle), base::Time::Now());
std::move(finish_callback_)
.Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
base::Time::Now());
@@ -142,7 +163,7 @@ class NavigationPreloadLoaderClient final
mojo::ScopedDataPipeConsumerHandle body_;
// Callbacks that complete Helper::OnFetchEvent().
- mojom::ServiceWorkerFetchResponseCallbackPtr response_callback_;
+ blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback_;
mojom::ServiceWorker::DispatchFetchEventCallback finish_callback_;
DISALLOW_COPY_AND_ASSIGN(NavigationPreloadLoaderClient);
@@ -156,7 +177,7 @@ class Helper : public EmbeddedWorkerTestHelper {
~Helper() override = default;
// Tells this helper to respond to fetch events with the specified blob.
- void RespondWithBlob(blink::mojom::BlobPtr blob) {
+ void RespondWithBlob(blink::mojom::SerializedBlobPtr blob) {
response_mode_ = ResponseMode::kBlob;
blob_body_ = std::move(blob);
}
@@ -230,7 +251,7 @@ class Helper : public EmbeddedWorkerTestHelper {
int embedded_worker_id,
const network::ResourceRequest& request,
blink::mojom::FetchEventPreloadHandlePtr preload_handle,
- mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
+ blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
mojom::ServiceWorker::DispatchFetchEventCallback finish_callback)
override {
// Basic checks on DispatchFetchEvent parameters.
@@ -246,35 +267,16 @@ class Helper : public EmbeddedWorkerTestHelper {
std::move(response_callback), std::move(finish_callback));
return;
case ResponseMode::kBlob:
- response_callback->OnResponseBlob(
- ServiceWorkerResponse(
- std::make_unique<std::vector<GURL>>(), 200, "OK",
- network::mojom::FetchResponseType::kDefault,
- std::make_unique<ServiceWorkerHeaderMap>(), "" /* blob_uuid */,
- 0 /* blob_size */, nullptr /* blob */,
- blink::mojom::ServiceWorkerResponseError::kUnknown,
- base::Time(), false /* response_is_in_cache_storage */,
- std::string() /* response_cache_storage_cache_name */,
- std::make_unique<
- ServiceWorkerHeaderList>() /* cors_exposed_header_names */),
- std::move(blob_body_), base::Time::Now());
+ response_callback->OnResponse(OkResponse(std::move(blob_body_)),
+ base::Time::Now());
std::move(finish_callback)
.Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
base::Time::Now());
return;
case ResponseMode::kStream:
- response_callback->OnResponseStream(
- ServiceWorkerResponse(
- std::make_unique<std::vector<GURL>>(), 200, "OK",
- network::mojom::FetchResponseType::kDefault,
- std::make_unique<ServiceWorkerHeaderMap>(), "" /* blob_uuid */,
- 0 /* blob_size */, nullptr /* blob */,
- blink::mojom::ServiceWorkerResponseError::kUnknown,
- base::Time(), false /* response_is_in_cache_storage */,
- std::string() /* response_cache_storage_cache_name */,
- std::make_unique<
- ServiceWorkerHeaderList>() /* cors_exposed_header_names */),
- std::move(stream_handle_), base::Time::Now());
+ response_callback->OnResponseStream(OkResponse(nullptr /* blob_body */),
+ std::move(stream_handle_),
+ base::Time::Now());
std::move(finish_callback)
.Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
base::Time::Now());
@@ -286,19 +288,7 @@ class Helper : public EmbeddedWorkerTestHelper {
base::Time::Now());
return;
case ResponseMode::kErrorResponse:
- response_callback->OnResponse(
- ServiceWorkerResponse(
- std::make_unique<std::vector<GURL>>(), 0 /* status_code */,
- "" /* status_text */,
- network::mojom::FetchResponseType::kDefault,
- std::make_unique<ServiceWorkerHeaderMap>(), "" /* blob_uuid */,
- 0 /* blob_size */, nullptr /* blob */,
- blink::mojom::ServiceWorkerResponseError::kPromiseRejected,
- base::Time(), false /* response_is_in_cache_storage */,
- std::string() /* response_cache_storage_cache_name */,
- std::make_unique<
- ServiceWorkerHeaderList>() /* cors_exposed_header_names */),
- base::Time::Now());
+ response_callback->OnResponse(ErrorResponse(), base::Time::Now());
std::move(finish_callback)
.Run(blink::mojom::ServiceWorkerEventStatus::REJECTED,
base::Time::Now());
@@ -327,34 +317,13 @@ class Helper : public EmbeddedWorkerTestHelper {
return;
case ResponseMode::kEarlyResponse:
finish_callback_ = std::move(finish_callback);
- response_callback->OnResponse(
- ServiceWorkerResponse(
- std::make_unique<std::vector<GURL>>(), 200, "OK",
- network::mojom::FetchResponseType::kDefault,
- std::make_unique<ServiceWorkerHeaderMap>(), "" /* blob_uuid */,
- 0 /* blob_size */, nullptr /* blob */,
- blink::mojom::ServiceWorkerResponseError::kUnknown,
- base::Time(), false /* response_is_in_cache_storage */,
- std::string() /* response_cache_storage_cache_name */,
- std::make_unique<
- ServiceWorkerHeaderList>() /* cors_exposed_header_names */),
- base::Time::Now());
+ response_callback->OnResponse(OkResponse(nullptr /* blob_body */),
+ base::Time::Now());
// Now the caller must call FinishWaitUntil() to finish the event.
return;
case ResponseMode::kRedirect:
- auto headers = std::make_unique<ServiceWorkerHeaderMap>();
- (*headers)["location"] = redirected_url_.spec();
- response_callback->OnResponse(
- ServiceWorkerResponse(
- std::make_unique<std::vector<GURL>>(), 301, "Moved Permanently",
- network::mojom::FetchResponseType::kDefault, std::move(headers),
- "" /* blob_uuid */, 0 /* blob_size */, nullptr /* blob */,
- blink::mojom::ServiceWorkerResponseError::kUnknown,
- base::Time(), false /* response_is_in_cache_storage */,
- std::string() /* response_cache_storage_cache_name */,
- std::make_unique<
- ServiceWorkerHeaderList>() /* cors_exposed_header_names */),
- base::Time::Now());
+ response_callback->OnResponse(RedirectResponse(redirected_url_.spec()),
+ base::Time::Now());
std::move(finish_callback)
.Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
base::Time::Now());
@@ -380,7 +349,7 @@ class Helper : public EmbeddedWorkerTestHelper {
scoped_refptr<network::ResourceRequestBody> request_body_;
// For ResponseMode::kBlob.
- blink::mojom::BlobPtr blob_body_;
+ blink::mojom::SerializedBlobPtr blob_body_;
// For ResponseMode::kStream.
blink::mojom::ServiceWorkerStreamHandlePtr stream_handle_;
@@ -403,8 +372,7 @@ CreateResponseInfoFromServiceWorker() {
head->was_fetched_via_service_worker = true;
head->was_fallback_required_by_service_worker = false;
head->url_list_via_service_worker = std::vector<GURL>();
- head->response_type_via_service_worker =
- network::mojom::FetchResponseType::kDefault;
+ head->response_type = network::mojom::FetchResponseType::kDefault;
head->is_in_cache_storage = false;
head->cache_storage_cache_name = std::string();
head->did_service_worker_navigation_preload = false;
@@ -476,15 +444,19 @@ class ServiceWorkerNavigationLoaderTest
kDidNotHandleRequest,
};
- // Returns whether ServiceWorkerNavigationLoader handled the request. If
- // kHandledRequest was returned, the request is ongoing and the caller can use
- // functions like client_.RunUntilComplete() to wait for completion.
+ // Starts a request. Returns whether ServiceWorkerNavigationLoader handled the
+ // request. If kHandledRequest was returned, the request is ongoing and the
+ // caller can use functions like client_.RunUntilComplete() to wait for
+ // completion.
LoaderResult StartRequest(std::unique_ptr<network::ResourceRequest> request) {
// Start a ServiceWorkerNavigationLoader. It should return a
// RequestHandler.
SingleRequestURLLoaderFactory::RequestHandler handler;
loader_ = std::make_unique<ServiceWorkerNavigationLoader>(
- base::BindOnce(&ReceiveRequestHandler, &handler), this, *request,
+ base::BindOnce(&ReceiveRequestHandler, &handler),
+ base::BindOnce(&ServiceWorkerNavigationLoaderTest::Fallback,
+ base::Unretained(this)),
+ this, *request,
base::WrapRefCounted<URLLoaderFactoryGetter>(
helper_->context()->loader_factory_getter()));
loader_->ForwardToServiceWorker();
@@ -493,12 +465,32 @@ class ServiceWorkerNavigationLoaderTest
return LoaderResult::kDidNotHandleRequest;
// Run the handler. It will load |request.url|.
- std::move(handler).Run(mojo::MakeRequest(&loader_ptr_),
+ std::move(handler).Run(*request, mojo::MakeRequest(&loader_ptr_),
client_.CreateInterfacePtr());
return LoaderResult::kHandledRequest;
}
+ // The |fallback_callback| passed to the ServiceWorkerNavigationLoader in
+ // StartRequest().
+ void Fallback(bool reset_subresource_loader_params) {
+ did_call_fallback_callback_ = true;
+ reset_subresource_loader_params_ = reset_subresource_loader_params;
+ if (quit_closure_for_fallback_callback_)
+ std::move(quit_closure_for_fallback_callback_).Run();
+ }
+
+ // Runs until the ServiceWorkerNavigationLoader created in StartRequest()
+ // calls the |fallback_callback| given to it. The argument passed to
+ // |fallback_callback| is saved in |reset_subresurce_loader_params_|.
+ void RunUntilFallbackCallback() {
+ if (did_call_fallback_callback_)
+ return;
+ base::RunLoop run_loop;
+ quit_closure_for_fallback_callback_ = run_loop.QuitClosure();
+ run_loop.Run();
+ }
+
void ExpectResponseInfo(const network::ResourceResponseHead& info,
const network::ResourceResponseHead& expected_info) {
EXPECT_EQ(expected_info.was_fetched_via_service_worker,
@@ -507,8 +499,7 @@ class ServiceWorkerNavigationLoaderTest
info.was_fallback_required_by_service_worker);
EXPECT_EQ(expected_info.url_list_via_service_worker,
info.url_list_via_service_worker);
- EXPECT_EQ(expected_info.response_type_via_service_worker,
- info.response_type_via_service_worker);
+ EXPECT_EQ(expected_info.response_type, info.response_type);
EXPECT_FALSE(info.service_worker_start_time.is_null());
EXPECT_FALSE(info.service_worker_ready_time.is_null());
EXPECT_LT(info.service_worker_start_time, info.service_worker_ready_time);
@@ -559,6 +550,11 @@ class ServiceWorkerNavigationLoaderTest
bool was_main_resource_load_failed_called_ = false;
std::unique_ptr<ServiceWorkerNavigationLoader> loader_;
network::mojom::URLLoaderPtr loader_ptr_;
+
+ bool did_call_fallback_callback_ = false;
+ bool reset_subresource_loader_params_ = false;
+ base::OnceClosure quit_closure_for_fallback_callback_;
+
base::test::ScopedFeatureList feature_list_;
};
@@ -608,10 +604,9 @@ TEST_F(ServiceWorkerNavigationLoaderTest, RequestBody) {
request->request_body = request_body;
// This test doesn't use the response to the fetch event, so just have the
- // service worker do simple network fallback.
- helper_->RespondWithFallback();
- LoaderResult result = StartRequest(std::move(request));
- EXPECT_EQ(LoaderResult::kDidNotHandleRequest, result);
+ // service worker do the default simple response.
+ StartRequest(std::move(request));
+ client_.RunUntilComplete();
// Verify that the request body was passed to the fetch event.
std::string body;
@@ -626,10 +621,13 @@ TEST_F(ServiceWorkerNavigationLoaderTest, BlobResponse) {
blob_data->AppendData(kResponseBody);
std::unique_ptr<storage::BlobDataHandle> blob_handle =
blob_context_.AddFinishedBlob(std::move(blob_data));
- blink::mojom::BlobPtr blob_ptr;
- blink::mojom::BlobRequest request = mojo::MakeRequest(&blob_ptr);
+
+ auto blob = blink::mojom::SerializedBlob::New();
+ blob->uuid = blob_handle->uuid();
+ blob->size = blob_handle->size();
+ blink::mojom::BlobRequest request = mojo::MakeRequest(&blob->blob);
storage::BlobImpl::Create(std::move(blob_handle), std::move(request));
- helper_->RespondWithBlob(std::move(blob_ptr));
+ helper_->RespondWithBlob(std::move(blob));
// Perform the request.
LoaderResult result = StartRequest(CreateRequest());
@@ -657,10 +655,11 @@ TEST_F(ServiceWorkerNavigationLoaderTest, BrokenBlobResponse) {
std::unique_ptr<storage::BlobDataHandle> blob_handle =
blob_context_.AddBrokenBlob(kBrokenUUID, "", "",
storage::BlobStatus::ERR_OUT_OF_MEMORY);
- blink::mojom::BlobPtr blob_ptr;
- blink::mojom::BlobRequest request = mojo::MakeRequest(&blob_ptr);
+ auto blob = blink::mojom::SerializedBlob::New();
+ blob->uuid = kBrokenUUID;
+ blink::mojom::BlobRequest request = mojo::MakeRequest(&blob->blob);
storage::BlobImpl::Create(std::move(blob_handle), std::move(request));
- helper_->RespondWithBlob(std::move(blob_ptr));
+ helper_->RespondWithBlob(std::move(blob));
// Perform the request.
LoaderResult result = StartRequest(CreateRequest());
@@ -809,7 +808,12 @@ TEST_F(ServiceWorkerNavigationLoaderTest, FallbackResponse) {
// Perform the request.
LoaderResult result = StartRequest(CreateRequest());
- EXPECT_EQ(LoaderResult::kDidNotHandleRequest, result);
+ EXPECT_EQ(LoaderResult::kHandledRequest, result);
+
+ // The fallback callback should be called.
+ RunUntilFallbackCallback();
+ EXPECT_FALSE(reset_subresource_loader_params_);
+ EXPECT_FALSE(was_main_resource_load_failed_called_);
// The request should not be handled by the loader, but it shouldn't be a
// failure.
@@ -842,8 +846,13 @@ TEST_F(ServiceWorkerNavigationLoaderTest, FailFetchDispatch) {
// Perform the request.
LoaderResult result = StartRequest(CreateRequest());
- EXPECT_EQ(LoaderResult::kDidNotHandleRequest, result);
+ EXPECT_EQ(LoaderResult::kHandledRequest, result);
+
+ // The fallback callback should be called.
+ RunUntilFallbackCallback();
+ EXPECT_TRUE(reset_subresource_loader_params_);
EXPECT_TRUE(was_main_resource_load_failed_called_);
+
histogram_tester.ExpectUniqueSample(
kHistogramMainResourceFetchEvent,
blink::ServiceWorkerStatusCode::kErrorFailed, 1);
@@ -886,7 +895,10 @@ TEST_F(ServiceWorkerNavigationLoaderTest, FallbackToNetwork) {
SingleRequestURLLoaderFactory::RequestHandler handler;
auto loader = std::make_unique<ServiceWorkerNavigationLoader>(
- base::BindOnce(&ReceiveRequestHandler, &handler), this, request,
+ base::BindOnce(&ReceiveRequestHandler, &handler),
+ base::BindOnce(&ServiceWorkerNavigationLoaderTest::Fallback,
+ base::Unretained(this)),
+ this, request,
base::WrapRefCounted<URLLoaderFactoryGetter>(
helper_->context()->loader_factory_getter()));
// Ask the loader to fallback to network. In production code,
@@ -983,7 +995,10 @@ TEST_F(ServiceWorkerNavigationLoaderTest, LifetimeAfterFallbackToNetwork) {
SingleRequestURLLoaderFactory::RequestHandler handler;
auto loader = std::make_unique<ServiceWorkerNavigationLoader>(
- base::BindOnce(&ReceiveRequestHandler, &handler), this, request,
+ base::BindOnce(&ReceiveRequestHandler, &handler),
+ base::BindOnce(&ServiceWorkerNavigationLoaderTest::Fallback,
+ base::Unretained(this)),
+ this, request,
base::WrapRefCounted<URLLoaderFactoryGetter>(
helper_->context()->loader_factory_getter()));
base::WeakPtr<ServiceWorkerNavigationLoader> loader_weakptr =
@@ -1000,5 +1015,16 @@ TEST_F(ServiceWorkerNavigationLoaderTest, LifetimeAfterFallbackToNetwork) {
EXPECT_FALSE(loader_weakptr);
}
+TEST_F(ServiceWorkerNavigationLoaderTest, DetachedDuringFetchEvent) {
+ LoaderResult result = StartRequest(CreateRequest());
+ EXPECT_EQ(LoaderResult::kHandledRequest, result);
+
+ // Detach the loader immediately after it started. This results in
+ // DidDispatchFetchEvent() being invoked later with null |delegate_|.
+ loader_.release()->DetachedFromRequest();
+ client_.RunUntilComplete();
+ EXPECT_EQ(net::ERR_ABORTED, client_.completion_status().error_code);
+}
+
} // namespace service_worker_navigation_loader_unittest
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_new_script_loader.cc b/chromium/content/browser/service_worker/service_worker_new_script_loader.cc
index 369f7356f0d..fc38698dff6 100644
--- a/chromium/content/browser/service_worker/service_worker_new_script_loader.cc
+++ b/chromium/content/browser/service_worker/service_worker_new_script_loader.cc
@@ -248,7 +248,7 @@ void ServiceWorkerNewScriptLoader::OnReceiveResponse(
}
WriteHeaders(
- base::MakeRefCounted<HttpResponseInfoIOBuffer>(response_info.release()));
+ base::MakeRefCounted<HttpResponseInfoIOBuffer>(std::move(response_info)));
// Don't pass SSLInfo to the client when the original request doesn't ask
// to send it.
@@ -316,8 +316,6 @@ void ServiceWorkerNewScriptLoader::OnStartLoadingResponseBody(
void ServiceWorkerNewScriptLoader::OnComplete(
const network::URLLoaderCompletionStatus& status) {
- DCHECK(network_loader_state_ == NetworkLoaderState::kWaitingForBody ||
- network_loader_state_ == NetworkLoaderState::kLoadingBody);
NetworkLoaderState previous_state = network_loader_state_;
network_loader_state_ = NetworkLoaderState::kCompleted;
if (status.error_code != net::OK) {
@@ -325,6 +323,9 @@ void ServiceWorkerNewScriptLoader::OnComplete(
return;
}
+ DCHECK(previous_state == NetworkLoaderState::kWaitingForBody ||
+ previous_state == NetworkLoaderState::kLoadingBody);
+
// Response body is empty.
if (previous_state == NetworkLoaderState::kWaitingForBody) {
DCHECK_EQ(WriterState::kNotStarted, body_writer_state_);
diff --git a/chromium/content/browser/service_worker/service_worker_object_host.cc b/chromium/content/browser/service_worker/service_worker_object_host.cc
index 49b037866c3..cd4f6ea5728 100644
--- a/chromium/content/browser/service_worker/service_worker_object_host.cc
+++ b/chromium/content/browser/service_worker/service_worker_object_host.cc
@@ -19,7 +19,7 @@ namespace content {
namespace {
using StatusCallback = base::OnceCallback<void(blink::ServiceWorkerStatusCode)>;
-using SetExtendableMessageEventSourceCallback =
+using PrepareExtendableMessageEventCallback =
base::OnceCallback<bool(mojom::ExtendableMessageEventPtr*)>;
void DispatchExtendableMessageEventAfterStartWorker(
@@ -28,7 +28,7 @@ void DispatchExtendableMessageEventAfterStartWorker(
const url::Origin& source_origin,
const base::Optional<base::TimeDelta>& timeout,
StatusCallback callback,
- SetExtendableMessageEventSourceCallback set_source_callback,
+ PrepareExtendableMessageEventCallback prepare_callback,
blink::ServiceWorkerStatusCode start_worker_status) {
if (start_worker_status != blink::ServiceWorkerStatusCode::kOk) {
std::move(callback).Run(start_worker_status);
@@ -38,7 +38,7 @@ void DispatchExtendableMessageEventAfterStartWorker(
mojom::ExtendableMessageEventPtr event = mojom::ExtendableMessageEvent::New();
event->message = std::move(message);
event->source_origin = source_origin;
- if (!std::move(set_source_callback).Run(&event)) {
+ if (!std::move(prepare_callback).Run(&event)) {
std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorFailed);
return;
}
@@ -62,7 +62,7 @@ void StartWorkerToDispatchExtendableMessageEvent(
const url::Origin& source_origin,
const base::Optional<base::TimeDelta>& timeout,
StatusCallback callback,
- SetExtendableMessageEventSourceCallback set_source_callback) {
+ PrepareExtendableMessageEventCallback prepare_callback) {
// If not enough time is left to actually process the event don't even
// bother starting the worker and sending the event.
if (timeout && *timeout < base::TimeDelta::FromMilliseconds(100)) {
@@ -74,27 +74,42 @@ void StartWorkerToDispatchExtendableMessageEvent(
ServiceWorkerMetrics::EventType::MESSAGE,
base::BindOnce(&DispatchExtendableMessageEventAfterStartWorker, worker,
std::move(message), source_origin, timeout,
- std::move(callback), std::move(set_source_callback)));
+ std::move(callback), std::move(prepare_callback)));
}
-bool SetSourceClientInfo(
+bool PrepareExtendableMessageEventFromClient(
+ base::WeakPtr<ServiceWorkerContextCore> context,
+ int64_t registration_id,
blink::mojom::ServiceWorkerClientInfoPtr source_client_info,
mojom::ExtendableMessageEventPtr* event) {
+ if (!context) {
+ return false;
+ }
DCHECK(source_client_info && !source_client_info->client_uuid.empty());
(*event)->source_info_for_client = std::move(source_client_info);
// Hide the client url if the client has a unique origin.
if ((*event)->source_origin.unique())
(*event)->source_info_for_client->url = GURL();
+
+ // Reset |registration->self_update_delay| iff postMessage is coming from a
+ // client, to prevent workers from postMessage to another version to reset
+ // the delay (https://crbug.com/805496).
+ ServiceWorkerRegistration* registration =
+ context->GetLiveRegistration(registration_id);
+ DCHECK(registration) << "running workers should have a live registration";
+ registration->set_self_update_delay(base::TimeDelta());
+
return true;
}
// The output |event| must be sent over Mojo immediately after this function
// returns. See ServiceWorkerObjectHost::CreateCompleteObjectInfoToSend() for
// details.
-bool SetSourceServiceWorkerInfo(scoped_refptr<ServiceWorkerVersion> worker,
- base::WeakPtr<ServiceWorkerProviderHost>
- source_service_worker_provider_host,
- mojom::ExtendableMessageEventPtr* event) {
+bool PrepareExtendableMessageEventFromServiceWorker(
+ scoped_refptr<ServiceWorkerVersion> worker,
+ base::WeakPtr<ServiceWorkerProviderHost>
+ source_service_worker_provider_host,
+ mojom::ExtendableMessageEventPtr* event) {
// The service worker execution context may have been destroyed by the time we
// get here.
if (!source_service_worker_provider_host)
@@ -121,11 +136,16 @@ bool SetSourceServiceWorkerInfo(scoped_refptr<ServiceWorkerVersion> worker,
}
void DispatchExtendableMessageEventFromClient(
+ base::WeakPtr<ServiceWorkerContextCore> context,
scoped_refptr<ServiceWorkerVersion> worker,
blink::TransferableMessage message,
const url::Origin& source_origin,
StatusCallback callback,
blink::mojom::ServiceWorkerClientInfoPtr source_client_info) {
+ if (!context) {
+ std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorAbort);
+ return;
+ }
// |source_client_info| may be null if a client sent the message but its
// info could not be retrieved.
if (!source_client_info) {
@@ -136,7 +156,8 @@ void DispatchExtendableMessageEventFromClient(
StartWorkerToDispatchExtendableMessageEvent(
worker, std::move(message), source_origin, base::nullopt /* timeout */,
std::move(callback),
- base::BindOnce(&SetSourceClientInfo, std::move(source_client_info)));
+ base::BindOnce(&PrepareExtendableMessageEventFromClient, context,
+ worker->registration_id(), std::move(source_client_info)));
}
void DispatchExtendableMessageEventFromServiceWorker(
@@ -156,7 +177,7 @@ void DispatchExtendableMessageEventFromServiceWorker(
source_service_worker_provider_host->provider_type());
StartWorkerToDispatchExtendableMessageEvent(
worker, std::move(message), source_origin, timeout, std::move(callback),
- base::BindOnce(&SetSourceServiceWorkerInfo, worker,
+ base::BindOnce(&PrepareExtendableMessageEventFromServiceWorker, worker,
source_service_worker_provider_host));
}
@@ -261,8 +282,8 @@ void ServiceWorkerObjectHost::DispatchExtendableMessageEvent(
case blink::mojom::ServiceWorkerProviderType::kForWindow:
service_worker_client_utils::GetClient(
provider_host_,
- base::BindOnce(&DispatchExtendableMessageEventFromClient, version_,
- std::move(message), provider_origin_,
+ base::BindOnce(&DispatchExtendableMessageEventFromClient, context_,
+ version_, std::move(message), provider_origin_,
std::move(callback)));
return;
case blink::mojom::ServiceWorkerProviderType::kForServiceWorker: {
diff --git a/chromium/content/browser/service_worker/service_worker_provider_host.cc b/chromium/content/browser/service_worker/service_worker_provider_host.cc
index f3f335bde5e..1f25d3eb9be 100644
--- a/chromium/content/browser/service_worker/service_worker_provider_host.cc
+++ b/chromium/content/browser/service_worker/service_worker_provider_host.cc
@@ -37,6 +37,7 @@
#include "content/public/common/child_process_host.h"
#include "content/public/common/content_client.h"
#include "content/public/common/origin_util.h"
+#include "mojo/public/cpp/bindings/message.h"
#include "mojo/public/cpp/bindings/strong_associated_binding.h"
#include "net/base/url_util.h"
#include "services/network/public/cpp/resource_request_body.h"
@@ -89,15 +90,19 @@ class ServiceWorkerURLTrackingRequestHandler
return nullptr;
}
- void MaybeCreateLoader(const network::ResourceRequest& resource_request,
- ResourceContext*,
- LoaderCallback callback) override {
+ void MaybeCreateLoader(
+ const network::ResourceRequest& tentative_resource_request,
+ ResourceContext*,
+ LoaderCallback callback,
+ FallbackCallback fallback_callback) override {
// |provider_host_| may have been deleted when the request is resumed.
if (!provider_host_)
return;
- const GURL stripped_url = net::SimplifyUrlForRequest(resource_request.url);
+ const GURL stripped_url =
+ net::SimplifyUrlForRequest(tentative_resource_request.url);
provider_host_->SetDocumentUrl(stripped_url);
- provider_host_->SetTopmostFrameUrl(resource_request.site_for_cookies);
+ provider_host_->SetTopmostFrameUrl(
+ tentative_resource_request.site_for_cookies);
// Fall back to network.
std::move(callback).Run({});
}
@@ -282,7 +287,6 @@ ServiceWorkerProviderHost::ServiceWorkerProviderHost(
render_thread_id_(kDocumentMainThreadId),
info_(std::move(info)),
context_(context),
- allow_association_(true),
binding_(this),
interface_provider_binding_(this) {
DCHECK_NE(blink::mojom::ServiceWorkerProviderType::kUnknown, info_->type);
@@ -322,6 +326,8 @@ ServiceWorkerProviderHost::~ServiceWorkerProviderHost() {
// Remove |this| as an observer of ServiceWorkerRegistrations.
// TODO(falken): Use ScopedObserver instead of this explicit call.
+ controller_.reset();
+ controller_registration_.reset();
RemoveAllMatchingRegistrations();
// Explicitly destroy the ServiceWorkerObjectHosts and
@@ -402,8 +408,6 @@ void ServiceWorkerProviderHost::OnVersionAttributesChanged(
void ServiceWorkerProviderHost::OnRegistrationFailed(
ServiceWorkerRegistration* registration) {
- if (associated_registration_ == registration)
- DisassociateRegistration();
RemoveMatchingRegistration(registration);
}
@@ -414,18 +418,15 @@ void ServiceWorkerProviderHost::OnRegistrationFinishedUninstalling(
void ServiceWorkerProviderHost::OnSkippedWaiting(
ServiceWorkerRegistration* registration) {
- if (associated_registration_ != registration)
+ if (controller_registration_ != registration)
return;
- // A client is "using" a registration if it is controlled by the active
- // worker of the registration. skipWaiting doesn't cause a client to start
- // using the registration.
- if (!controller_)
- return;
- ServiceWorkerVersion* active_version = registration->active_version();
- DCHECK(active_version);
- DCHECK_EQ(active_version->status(), ServiceWorkerVersion::ACTIVATING);
- SetControllerVersionAttribute(active_version,
- true /* notify_controllerchange */);
+
+ DCHECK(controller());
+ ServiceWorkerVersion* active = controller_registration_->active_version();
+ DCHECK(active);
+ DCHECK_NE(active, controller());
+ DCHECK_EQ(active->status(), ServiceWorkerVersion::ACTIVATING);
+ UpdateController(true /* notify_controllerchange */);
}
mojom::ControllerServiceWorkerPtr
@@ -443,6 +444,7 @@ ServiceWorkerProviderHost::GetControllerServiceWorkerPtr() {
void ServiceWorkerProviderHost::SetDocumentUrl(const GURL& url) {
DCHECK(!url.has_ref());
+ DCHECK(!controller());
document_url_ = url;
if (IsProviderForClient())
SyncMatchingRegistrations();
@@ -458,9 +460,10 @@ const GURL& ServiceWorkerProviderHost::topmost_frame_url() const {
return topmost_frame_url_;
}
-void ServiceWorkerProviderHost::SetControllerVersionAttribute(
- ServiceWorkerVersion* version,
- bool notify_controllerchange) {
+void ServiceWorkerProviderHost::UpdateController(bool notify_controllerchange) {
+ ServiceWorkerVersion* version =
+ controller_registration_ ? controller_registration_->active_version()
+ : nullptr;
CHECK(!version || IsContextSecureForServiceWorker());
if (version == controller_.get())
return;
@@ -470,8 +473,7 @@ void ServiceWorkerProviderHost::SetControllerVersionAttribute(
if (version)
version->AddControllee(this);
-
- if (previous_version.get())
+ if (previous_version)
previous_version->RemoveControllee(client_uuid_);
// SetController message should be sent only for clients.
@@ -521,24 +523,21 @@ blink::mojom::ServiceWorkerClientType ServiceWorkerProviderHost::client_type()
return blink::mojom::ServiceWorkerClientType::kWindow;
}
-void ServiceWorkerProviderHost::AssociateRegistration(
- ServiceWorkerRegistration* registration,
+void ServiceWorkerProviderHost::SetControllerRegistration(
+ scoped_refptr<ServiceWorkerRegistration> controller_registration,
bool notify_controllerchange) {
- CHECK(IsContextSecureForServiceWorker());
DCHECK(IsProviderForClient());
- DCHECK(CanAssociateRegistration(registration));
- associated_registration_ = registration;
- AddMatchingRegistration(registration);
- SetControllerVersionAttribute(registration->active_version(),
- notify_controllerchange);
-}
-void ServiceWorkerProviderHost::DisassociateRegistration() {
- DCHECK(IsProviderForClient());
- if (!associated_registration_.get())
- return;
- associated_registration_ = nullptr;
- SetControllerVersionAttribute(nullptr, false /* notify_controllerchange */);
+ if (controller_registration) {
+ CHECK(IsContextSecureForServiceWorker());
+ DCHECK(controller_registration->active_version());
+#if DCHECK_IS_ON()
+ DCHECK(IsMatchingRegistration(controller_registration.get()));
+#endif // DCHECK_IS_ON()
+ }
+
+ controller_registration_ = controller_registration;
+ UpdateController(notify_controllerchange);
}
void ServiceWorkerProviderHost::AddMatchingRegistration(
@@ -557,9 +556,13 @@ void ServiceWorkerProviderHost::AddMatchingRegistration(
void ServiceWorkerProviderHost::RemoveMatchingRegistration(
ServiceWorkerRegistration* registration) {
- size_t key = registration->pattern().spec().size();
- DCHECK(base::ContainsKey(matching_registrations_, key));
+ DCHECK_NE(controller_registration_, registration);
+#if DCHECK_IS_ON()
+ DCHECK(IsMatchingRegistration(registration));
+#endif // DCHECK_IS_ON()
+
registration->RemoveListener(this);
+ size_t key = registration->pattern().spec().size();
matching_registrations_.erase(key);
}
@@ -600,7 +603,7 @@ bool ServiceWorkerProviderHost::AllowServiceWorker(const GURL& scope) {
}
void ServiceWorkerProviderHost::NotifyControllerLost() {
- SetControllerVersionAttribute(nullptr, true /* notify_controllerchange */);
+ SetControllerRegistration(nullptr, true /* notify_controllerchange */);
}
void ServiceWorkerProviderHost::AddServiceWorkerToUpdate(
@@ -675,17 +678,6 @@ ServiceWorkerProviderHost::GetOrCreateServiceWorkerObjectHost(
return service_worker_object_hosts_[version_id]->AsWeakPtr();
}
-bool ServiceWorkerProviderHost::CanAssociateRegistration(
- ServiceWorkerRegistration* registration) {
- if (!context_)
- return false;
- if (running_hosted_version_.get())
- return false;
- if (!registration || associated_registration_.get() || !allow_association_)
- return false;
- return true;
-}
-
void ServiceWorkerProviderHost::PostMessageToClient(
ServiceWorkerVersion* version,
blink::TransferableMessage message) {
@@ -715,15 +707,20 @@ void ServiceWorkerProviderHost::CountFeature(blink::mojom::WebFeature feature) {
}
void ServiceWorkerProviderHost::ClaimedByRegistration(
- ServiceWorkerRegistration* registration) {
+ scoped_refptr<ServiceWorkerRegistration> registration) {
DCHECK(registration->active_version());
- if (registration == associated_registration_) {
- SetControllerVersionAttribute(registration->active_version(),
- true /* notify_controllerchange */);
- } else if (allow_association_) {
- DisassociateRegistration();
- AssociateRegistration(registration, true /* notify_controllerchange */);
+ // TODO(falken): This should just early return, or DCHECK. claim() should have
+ // no effect on a page that's already using the registration.
+ if (registration == controller_registration_) {
+ UpdateController(true /* notify_controllerchange */);
+ return;
}
+
+ // TODO(crbug.com/866353): It shouldn't be necesary to check
+ // |allow_set_controller_registration_|. See the comment for
+ // AllowSetControllerRegistration().
+ if (allow_set_controller_registration_)
+ SetControllerRegistration(registration, true /* notify_controllerchange */);
}
void ServiceWorkerProviderHost::CompleteNavigationInitialized(
@@ -802,6 +799,8 @@ void ServiceWorkerProviderHost::CompleteSharedWorkerPreparation() {
void ServiceWorkerProviderHost::SyncMatchingRegistrations() {
DCHECK(context_);
+ DCHECK(!controller_registration());
+
RemoveAllMatchingRegistrations();
const auto& registrations = context_->GetLiveRegistrations();
for (const auto& key_registration : registrations) {
@@ -813,7 +812,23 @@ void ServiceWorkerProviderHost::SyncMatchingRegistrations() {
}
}
+#if DCHECK_IS_ON()
+bool ServiceWorkerProviderHost::IsMatchingRegistration(
+ ServiceWorkerRegistration* registration) const {
+ std::string spec = registration->pattern().spec();
+ size_t key = spec.size();
+
+ auto iter = matching_registrations_.find(key);
+ if (iter == matching_registrations_.end())
+ return false;
+ if (iter->second.get() != registration)
+ return false;
+ return true;
+}
+#endif // DCHECK_IS_ON()
+
void ServiceWorkerProviderHost::RemoveAllMatchingRegistrations() {
+ DCHECK(!controller_registration());
for (const auto& it : matching_registrations_) {
ServiceWorkerRegistration* registration = it.second.get();
registration->RemoveListener(this);
@@ -858,8 +873,8 @@ void ServiceWorkerProviderHost::SendSetControllerServiceWorker(
return;
}
- DCHECK(associated_registration_);
- DCHECK_EQ(associated_registration_->active_version(), controller_.get());
+ DCHECK(controller_registration());
+ DCHECK_EQ(controller_registration_->active_version(), controller_.get());
controller_info->mode = GetControllerMode();
@@ -885,6 +900,18 @@ void ServiceWorkerProviderHost::SendSetControllerServiceWorker(
notify_controllerchange);
}
+#if DCHECK_IS_ON()
+void ServiceWorkerProviderHost::CheckControllerConsistency() const {
+ if (!controller_) {
+ DCHECK(!controller_registration_);
+ return;
+ }
+ DCHECK(IsProviderForClient());
+ DCHECK(controller_registration_);
+ DCHECK_EQ(controller_->registration_id(), controller_registration_->id());
+}
+#endif
+
void ServiceWorkerProviderHost::Register(
const GURL& script_url,
blink::mojom::ServiceWorkerRegistrationOptionsPtr options,
@@ -894,31 +921,36 @@ void ServiceWorkerProviderHost::Register(
nullptr)) {
return;
}
-
- std::string error_message;
- if (!IsValidRegisterMessage(script_url, *options, &error_message)) {
- mojo::ReportBadMessage(error_message);
+ if (client_type() != blink::mojom::ServiceWorkerClientType::kWindow) {
+ mojo::ReportBadMessage(ServiceWorkerConsts::kBadMessageFromNonWindow);
+ std::move(callback).Run(blink::mojom::ServiceWorkerErrorType::kUnknown,
+ std::string(), nullptr);
+ return;
+ }
+ std::vector<GURL> urls = {document_url(), options->scope, script_url};
+ if (!ServiceWorkerUtils::AllOriginsMatchAndCanAccessServiceWorkers(urls)) {
+ mojo::ReportBadMessage(ServiceWorkerConsts::kBadMessageImproperOrigins);
// ReportBadMessage() will kill the renderer process, but Mojo complains if
// the callback is not run. Just run it with nonsense arguments.
std::move(callback).Run(blink::mojom::ServiceWorkerErrorType::kUnknown,
std::string(), nullptr);
return;
}
-
int64_t trace_id = base::TimeTicks::Now().since_origin().InMicroseconds();
TRACE_EVENT_ASYNC_BEGIN2(
"ServiceWorker", "ServiceWorkerProviderHost::Register", trace_id, "Scope",
options->scope.spec(), "Script URL", script_url.spec());
context_->RegisterServiceWorker(
script_url, *options,
- base::AdaptCallbackForRepeating(
- base::BindOnce(&ServiceWorkerProviderHost::RegistrationComplete,
- AsWeakPtr(), std::move(callback), trace_id)));
+ base::BindOnce(&ServiceWorkerProviderHost::RegistrationComplete,
+ AsWeakPtr(), std::move(callback), trace_id,
+ mojo::GetBadMessageCallback()));
}
void ServiceWorkerProviderHost::RegistrationComplete(
RegisterCallback callback,
int64_t trace_id,
+ mojo::ReportBadMessageCallback bad_message_callback,
blink::ServiceWorkerStatusCode status,
const std::string& status_message,
int64_t registration_id) {
@@ -926,6 +958,16 @@ void ServiceWorkerProviderHost::RegistrationComplete(
trace_id, "Status",
blink::ServiceWorkerStatusToString(status),
"Registration ID", registration_id);
+ // kErrorInvalidArguments means the renderer gave unexpectedly bad arguments,
+ // so terminate it.
+ if (status == blink::ServiceWorkerStatusCode::kErrorInvalidArguments) {
+ std::move(bad_message_callback).Run(status_message);
+ // |bad_message_callback| will kill the renderer process, but Mojo complains
+ // if the callback is not run. Just run it with nonsense arguments.
+ std::move(callback).Run(blink::mojom::ServiceWorkerErrorType::kUnknown,
+ std::string(), nullptr);
+ return;
+ }
if (!IsContextAlive()) {
std::move(callback).Run(
blink::mojom::ServiceWorkerErrorType::kAbort,
@@ -1163,31 +1205,6 @@ void ServiceWorkerProviderHost::HintToUpdateServiceWorker() {
versions_to_update_.clear();
}
-bool ServiceWorkerProviderHost::IsValidRegisterMessage(
- const GURL& script_url,
- const blink::mojom::ServiceWorkerRegistrationOptions& options,
- std::string* out_error) const {
- if (client_type() != blink::mojom::ServiceWorkerClientType::kWindow) {
- *out_error = ServiceWorkerConsts::kBadMessageFromNonWindow;
- return false;
- }
- if (!options.scope.is_valid() || !script_url.is_valid()) {
- *out_error = ServiceWorkerConsts::kBadMessageInvalidURL;
- return false;
- }
- if (ServiceWorkerUtils::ContainsDisallowedCharacter(options.scope, script_url,
- out_error)) {
- return false;
- }
- std::vector<GURL> urls = {document_url(), options.scope, script_url};
- if (!ServiceWorkerUtils::AllOriginsMatchAndCanAccessServiceWorkers(urls)) {
- *out_error = ServiceWorkerConsts::kBadMessageImproperOrigins;
- return false;
- }
-
- return true;
-}
-
bool ServiceWorkerProviderHost::IsValidGetRegistrationMessage(
const GURL& client_url,
std::string* out_error) const {
diff --git a/chromium/content/browser/service_worker/service_worker_provider_host.h b/chromium/content/browser/service_worker/service_worker_provider_host.h
index ded291f894a..2fe3e1ef2b8 100644
--- a/chromium/content/browser/service_worker/service_worker_provider_host.h
+++ b/chromium/content/browser/service_worker/service_worker_provider_host.h
@@ -203,47 +203,21 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
// and if it has a fetch event handler.
blink::mojom::ControllerServiceWorkerMode GetControllerMode() const;
- // Returns this provider's controller. The controller is typically the same as
- // active_version() but can differ in the following cases:
- // (1) The client was created before the registration existed or had an active
- // version (in spec language, it is not "using" the registration).
- // (2) The client had a controller but NotifyControllerLost() was called due
- // to an exceptional circumstance (here also it is not "using" the
- // registration).
- // (3) During algorithms such as the update, skipWaiting(), and claim() steps,
- // the active version and controller may temporarily differ. For example, to
- // perform skipWaiting(), the registration's active version is updated first
- // and then the provider host's controlling version is updated to match it.
+ // For service worker clients. Returns this client's controller.
ServiceWorkerVersion* controller() const {
- // Only clients can have controllers.
- DCHECK(!controller_ || IsProviderForClient());
- return controller_.get();
- }
-
- ServiceWorkerVersion* active_version() const {
- return associated_registration_.get()
- ? associated_registration_->active_version()
- : nullptr;
- }
+#if DCHECK_IS_ON()
+ CheckControllerConsistency();
+#endif // DCHECK_IS_ON()
- ServiceWorkerVersion* waiting_version() const {
- return associated_registration_.get()
- ? associated_registration_->waiting_version()
- : nullptr;
+ return controller_.get();
}
- ServiceWorkerVersion* installing_version() const {
- return associated_registration_.get()
- ? associated_registration_->installing_version()
- : nullptr;
- }
+ ServiceWorkerRegistration* controller_registration() const {
+#if DCHECK_IS_ON()
+ CheckControllerConsistency();
+#endif // DCHECK_IS_ON()
- // Returns the associated registration. The provider host listens to this
- // registration to resolve the .ready promise and set its controller.
- ServiceWorkerRegistration* associated_registration() const {
- // Only clients can have an associated registration.
- DCHECK(!associated_registration_ || IsProviderForClient());
- return associated_registration_.get();
+ return controller_registration_.get();
}
// For service worker execution contexts. The version of the service worker.
@@ -267,10 +241,9 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
//
// - During navigation, right after a request handler for the main resource
// has found the matching registration and has started the worker.
- // - When a controller is updated by SetControllerVersionAttribute() (e.g.
- // by OnSkippedWaiting, {Dis,}AssociateRegistration, NotifyControllerLost
- // or ClaimedByRegistration). In some cases the controller worker may not
- // be started yet.
+ // - When a controller is updated by UpdateController() (e.g.
+ // by OnSkippedWaiting() or SetControllerRegistration()).
+ // In some cases the controller worker may not be started yet.
//
// This may return nullptr if the controller service worker does not have a
// fetch handler, i.e. when the renderer does not need the controller ptr.
@@ -320,15 +293,29 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
// Can only be called when IsProviderForClient() is true.
blink::mojom::ServiceWorkerClientType client_type() const;
- // For service worker clients. Associates to |registration| to listen for its
- // version change events and sets the controller. If |notify_controllerchange|
- // is true, instructs the renderer to dispatch a 'controllerchange' event.
- void AssociateRegistration(ServiceWorkerRegistration* registration,
- bool notify_controllerchange);
+ // For service worker clients. Makes this client be controlled by
+ // |registration|'s active worker, or makes this client be not
+ // controlled if |registration| is null. If |notify_controllerchange| is true,
+ // instructs the renderer to dispatch a 'controllerchange' event.
+ void SetControllerRegistration(
+ scoped_refptr<ServiceWorkerRegistration> controller_registration,
+ bool notify_controllerchange);
- // For service worker clients. Clears the associated registration and stops
- // listening to it.
- void DisassociateRegistration();
+ // For use by the ServiceWorkerControlleeRequestHandler to disallow a
+ // registration claiming this host while its main resource request is
+ // occurring.
+ //
+ // TODO(crbug.com/866353): This should be unneccessary: registration code
+ // already avoids claiming clients that are not execution ready. However
+ // there may be edge cases with shared workers (pre-NetS13nServiceWorker) and
+ // about:blank iframes, since |is_execution_ready_| is initialized true for
+ // them. Try to remove this after S13nServiceWorker.
+ void AllowSetControllerRegistration(bool allow) {
+ allow_set_controller_registration_ = allow;
+ }
+ bool IsSetControllerRegistrationAllowed() {
+ return allow_set_controller_registration_;
+ }
// Returns a handler for a request. May return nullptr if the request doesn't
// require special handling.
@@ -366,14 +353,6 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
base::WeakPtr<ServiceWorkerObjectHost> GetOrCreateServiceWorkerObjectHost(
scoped_refptr<ServiceWorkerVersion> version);
- // Returns true if |registration| can be associated with this provider.
- bool CanAssociateRegistration(ServiceWorkerRegistration* registration);
-
- // For use by the ServiceWorkerControlleeRequestHandler to disallow
- // new registration association while a navigation is occurring and
- // an existing registration is being looked for.
- void SetAllowAssociation(bool allow) { allow_association_ = allow; }
-
// Returns true if the context referred to by this host (i.e. |context_|) is
// still alive.
bool IsContextAlive();
@@ -387,7 +366,8 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
void CountFeature(blink::mojom::WebFeature feature);
// |registration| claims the document to be controlled.
- void ClaimedByRegistration(ServiceWorkerRegistration* registration);
+ void ClaimedByRegistration(
+ scoped_refptr<ServiceWorkerRegistration> registration);
// For service worker clients. Completes initialization of
// provider hosts used for navigation requests.
@@ -419,6 +399,16 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
// After this is called, is_execution_ready() returns true.
void CompleteSharedWorkerPreparation();
+ // For service worker clients. The host keeps track of all the prospective
+ // longest-matching registrations, in order to resolve .ready or respond to
+ // claim() attempts.
+ //
+ // This is subtle: it doesn't keep all registrations (e.g., from storage) in
+ // memory, but just the ones that are possibly the longest-matching one. The
+ // best match from storage is added at load time. That match can't uninstall
+ // while this host is a controllee, so all the other stored registrations can
+ // be ignored. Only a newly installed registration can claim it, and new
+ // installing registrations are added as matches.
void AddMatchingRegistration(ServiceWorkerRegistration* registration);
void RemoveMatchingRegistration(ServiceWorkerRegistration* registration);
@@ -471,6 +461,8 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
friend class ServiceWorkerProviderHostTest;
friend class ServiceWorkerWriteToCacheJobTest;
friend class ServiceWorkerContextRequestHandlerTest;
+ friend class service_worker_controllee_request_handler_unittest::
+ ServiceWorkerControlleeRequestHandlerTest;
friend class service_worker_object_host_unittest::ServiceWorkerObjectHostTest;
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWriteToCacheJobTest, Update_SameScript);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWriteToCacheJobTest,
@@ -509,17 +501,20 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
ServiceWorkerRegistration* registration) override;
void OnSkippedWaiting(ServiceWorkerRegistration* registration) override;
- // Sets the controller field to |version| or if |version| is nullptr, clears
- // the field. If |notify_controllerchange| is true, instructs the renderer to
- // dispatch a 'controller' change event.
- void SetControllerVersionAttribute(ServiceWorkerVersion* version,
- bool notify_controllerchange);
-
- void SendAssociateRegistrationMessage();
+ // Sets the controller to |controller_registration_->active_version()| or null
+ // if there is no associated registration.
+ //
+ // If |notify_controllerchange| is true, instructs the renderer to dispatch a
+ // 'controller' change event.
+ void UpdateController(bool notify_controllerchange);
// Syncs matching registrations with live registrations.
void SyncMatchingRegistrations();
+#if DCHECK_IS_ON()
+ bool IsMatchingRegistration(ServiceWorkerRegistration* registration) const;
+#endif // DCHECK_IS_ON()
+
// Discards all references to matching registrations.
void RemoveAllMatchingRegistrations();
@@ -530,6 +525,10 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
// instructs the renderer to dispatch a 'controllerchange' event.
void SendSetControllerServiceWorker(bool notify_controllerchange);
+#if DCHECK_IS_ON()
+ void CheckControllerConsistency() const;
+#endif // DCHECK_IS_ON()
+
// Implements mojom::ServiceWorkerContainerHost.
void Register(const GURL& script_url,
blink::mojom::ServiceWorkerRegistrationOptionsPtr options,
@@ -550,6 +549,7 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
// Callback for ServiceWorkerContextCore::RegisterServiceWorker().
void RegistrationComplete(RegisterCallback callback,
int64_t trace_id,
+ mojo::ReportBadMessageCallback bad_message_callback,
blink::ServiceWorkerStatusCode status,
const std::string& status_message,
int64_t registration_id);
@@ -572,10 +572,6 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
mojom::ControllerServiceWorkerRequest controller_request,
blink::ServiceWorkerStatusCode status);
- bool IsValidRegisterMessage(
- const GURL& script_url,
- const blink::mojom::ServiceWorkerRegistrationOptions& options,
- std::string* out_error) const;
bool IsValidGetRegistrationMessage(const GURL& client_url,
std::string* out_error) const;
bool IsValidGetRegistrationsMessage(std::string* out_error) const;
@@ -616,14 +612,13 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
GURL document_url_;
GURL topmost_frame_url_;
- scoped_refptr<ServiceWorkerRegistration> associated_registration_;
-
// Keyed by registration scope URL length.
using ServiceWorkerRegistrationMap =
std::map<size_t, scoped_refptr<ServiceWorkerRegistration>>;
// Contains all living registrations whose pattern this document's URL
- // starts with. It is empty if IsContextSecureForServiceWorker() is
- // false.
+ // starts with, used for .ready and claim(). It is empty if
+ // IsContextSecureForServiceWorker() is false. See also
+ // AddMatchingRegistration().
ServiceWorkerRegistrationMap matching_registrations_;
// Contains all ServiceWorkerRegistrationObjectHost instances corresponding to
@@ -651,16 +646,22 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
std::unique_ptr<GetRegistrationForReadyCallback> get_ready_callback_;
// For service worker clients. The controller service worker (i.e.,
- // ServiceWorkerContainer#controller).
+ // ServiceWorkerContainer#controller) and its registration. The controller is
+ // typically the same as the registration's active version, but during
+ // algorithms such as the update, skipWaiting(), and claim() steps, the active
+ // version and controller may temporarily differ. For example, to perform
+ // skipWaiting(), the registration's active version is updated first and then
+ // the provider host's controller is updated to match it.
scoped_refptr<ServiceWorkerVersion> controller_;
+ scoped_refptr<ServiceWorkerRegistration> controller_registration_;
+ bool allow_set_controller_registration_ = true;
+
// For service worker execution contexts. The ServiceWorkerVersion of the
// service worker this is a provider for.
scoped_refptr<ServiceWorkerVersion> running_hosted_version_;
base::WeakPtr<ServiceWorkerContextCore> context_;
- bool allow_association_;
-
// |container_| is the Mojo endpoint to the renderer-side
// ServiceWorkerContainer that |this| is a ServiceWorkerContainerHost for.
mojom::ServiceWorkerContainerAssociatedPtr container_;
diff --git a/chromium/content/browser/service_worker/service_worker_provider_host_unittest.cc b/chromium/content/browser/service_worker/service_worker_provider_host_unittest.cc
index 7cc8b71f605..926cb6bedf1 100644
--- a/chromium/content/browser/service_worker/service_worker_provider_host_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_provider_host_unittest.cc
@@ -19,7 +19,6 @@
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_test_utils.h"
#include "content/browser/service_worker/service_worker_version.h"
-#include "content/common/service_worker/service_worker_messages.h"
#include "content/common/url_schemes.h"
#include "content/public/common/browser_side_navigation_policy.h"
#include "content/public/common/child_process_host.h"
@@ -468,18 +467,18 @@ TEST_P(ServiceWorkerProviderHostTest, Controller) {
// Finish the navigation.
FinishNavigation(host.get(), std::move(info));
- host->AssociateRegistration(registration1_.get(),
- false /* notify_controllerchange */);
+ host->SetControllerRegistration(registration1_,
+ false /* notify_controllerchange */);
base::RunLoop().RunUntilIdle();
// The page should be controlled since there was an active version at the
// time navigation started. The SetController IPC should have been sent.
- EXPECT_TRUE(host->active_version());
- EXPECT_EQ(host->active_version(), host->controller());
+ EXPECT_TRUE(host->controller());
EXPECT_TRUE(container->was_set_controller_called());
+ EXPECT_EQ(registration1_.get(), host->MatchRegistration());
}
-TEST_P(ServiceWorkerProviderHostTest, ActiveIsNotController) {
+TEST_P(ServiceWorkerProviderHostTest, UncontrolledWithMatchingRegistration) {
// Create a host.
base::WeakPtr<ServiceWorkerProviderHost> host =
ServiceWorkerProviderHost::PreCreateNavigationHost(
@@ -498,11 +497,8 @@ TEST_P(ServiceWorkerProviderHostTest, ActiveIsNotController) {
1 /* version_id */, helper_->context()->AsWeakPtr());
registration1_->SetInstallingVersion(version);
-
// Finish the navigation.
FinishNavigation(host.get(), std::move(info));
- host->AssociateRegistration(registration1_.get(),
- false /* notify_controllerchange */);
// Promote the worker to active while navigation is still happening.
registration1_->SetActiveVersion(version);
base::RunLoop().RunUntilIdle();
@@ -510,9 +506,11 @@ TEST_P(ServiceWorkerProviderHostTest, ActiveIsNotController) {
// The page should not be controlled since there was no active version at the
// time navigation started. Furthermore, no SetController IPC should have been
// sent.
- EXPECT_TRUE(host->active_version());
EXPECT_FALSE(host->controller());
EXPECT_FALSE(container->was_set_controller_called());
+ // However, the host should know the registration is its best match, for
+ // .ready and claim().
+ EXPECT_EQ(registration1_.get(), host->MatchRegistration());
}
TEST_P(ServiceWorkerProviderHostTest,
@@ -919,7 +917,7 @@ TEST_P(ServiceWorkerProviderHostTest, DontSetControllerInDestructor) {
// Make the active worker the controller and give it an ongoing request. This
// way when a waiting worker calls SkipWaiting(), activation won't trigger
// until we're ready.
- provider_host1->AssociateRegistration(registration1_.get(), false);
+ provider_host1->SetControllerRegistration(registration1_, false);
EXPECT_EQ(version1.get(), provider_host1->controller());
// The worker must be running to have a request.
version1->StartWorker(ServiceWorkerMetrics::EventType::PUSH,
diff --git a/chromium/content/browser/service_worker/service_worker_read_from_cache_job_unittest.cc b/chromium/content/browser/service_worker/service_worker_read_from_cache_job_unittest.cc
index 4fdb26ad89c..150c6466381 100644
--- a/chromium/content/browser/service_worker/service_worker_read_from_cache_job_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_read_from_cache_job_unittest.cc
@@ -118,13 +118,14 @@ class ServiceWorkerReadFromCacheJobTest : public testing::Test {
std::unique_ptr<ServiceWorkerResponseWriter> writer =
context()->storage()->CreateResponseWriter(resource_id);
- std::unique_ptr<net::HttpResponseInfo> info(new net::HttpResponseInfo);
+ std::unique_ptr<net::HttpResponseInfo> info =
+ std::make_unique<net::HttpResponseInfo>();
info->request_time = base::Time::Now();
info->response_time = base::Time::Now();
info->was_cached = false;
info->headers = new net::HttpResponseHeaders(headers);
scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
- new HttpResponseInfoIOBuffer(info.release());
+ base::MakeRefCounted<HttpResponseInfoIOBuffer>(std::move(info));
{
net::TestCompletionCallback cb;
writer->WriteInfo(info_buffer.get(), cb.callback());
diff --git a/chromium/content/browser/service_worker/service_worker_register_job.cc b/chromium/content/browser/service_worker/service_worker_register_job.cc
index 81b62c81e86..f832ed1c409 100644
--- a/chromium/content/browser/service_worker/service_worker_register_job.cc
+++ b/chromium/content/browser/service_worker/service_worker_register_job.cc
@@ -20,7 +20,6 @@
#include "content/browser/service_worker/service_worker_version.h"
#include "content/browser/service_worker/service_worker_write_to_cache_job.h"
#include "content/common/service_worker/service_worker.mojom.h"
-#include "content/common/service_worker/service_worker_messages.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/common/service_worker/service_worker_utils.h"
#include "content/public/browser/browser_thread.h"
diff --git a/chromium/content/browser/service_worker/service_worker_registration.cc b/chromium/content/browser/service_worker/service_worker_registration.cc
index dec34316469..f215fd804ed 100644
--- a/chromium/content/browser/service_worker/service_worker_registration.cc
+++ b/chromium/content/browser/service_worker/service_worker_registration.cc
@@ -13,7 +13,6 @@
#include "content/browser/service_worker/service_worker_info.h"
#include "content/browser/service_worker/service_worker_metrics.h"
#include "content/browser/service_worker/service_worker_register_job.h"
-#include "content/common/service_worker/service_worker_messages.h"
#include "content/public/browser/browser_thread.h"
#include "third_party/blink/public/common/service_worker/service_worker_utils.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
diff --git a/chromium/content/browser/service_worker/service_worker_registration.h b/chromium/content/browser/service_worker/service_worker_registration.h
index e579f31c727..e41fa4a0af3 100644
--- a/chromium/content/browser/service_worker/service_worker_registration.h
+++ b/chromium/content/browser/service_worker/service_worker_registration.h
@@ -15,6 +15,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
+#include "base/time/time.h"
#include "content/browser/service_worker/service_worker_version.h"
#include "content/common/content_export.h"
#include "content/common/service_worker/service_worker_types.h"
@@ -162,6 +163,13 @@ class CONTENT_EXPORT ServiceWorkerRegistration
base::Time last_update_check() const { return last_update_check_; }
void set_last_update_check(base::Time last) { last_update_check_ = last; }
+ // The delay for self-updating service workers, to prevent them from running
+ // forever (see https://crbug.com/805496).
+ base::TimeDelta self_update_delay() const { return self_update_delay_; }
+ void set_self_update_delay(const base::TimeDelta& delay) {
+ self_update_delay_ = delay;
+ }
+
// Unsets the version and deletes its resources. Also deletes this
// registration from storage if there is no longer a stored version.
void DeleteVersion(const scoped_refptr<ServiceWorkerVersion>& version);
@@ -227,6 +235,7 @@ class CONTENT_EXPORT ServiceWorkerRegistration
bool should_activate_when_ready_;
blink::mojom::NavigationPreloadState navigation_preload_state_;
base::Time last_update_check_;
+ base::TimeDelta self_update_delay_;
int64_t resources_total_size_bytes_;
// This registration is the primary owner of these versions.
@@ -234,7 +243,7 @@ class CONTENT_EXPORT ServiceWorkerRegistration
scoped_refptr<ServiceWorkerVersion> waiting_version_;
scoped_refptr<ServiceWorkerVersion> installing_version_;
- base::ObserverList<Listener> listeners_;
+ base::ObserverList<Listener>::Unchecked listeners_;
std::vector<base::Closure> registration_finished_callbacks_;
base::WeakPtr<ServiceWorkerContextCore> context_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
diff --git a/chromium/content/browser/service_worker/service_worker_registration_object_host.cc b/chromium/content/browser/service_worker/service_worker_registration_object_host.cc
index 4e758bf31af..5466cd6ef11 100644
--- a/chromium/content/browser/service_worker/service_worker_registration_object_host.cc
+++ b/chromium/content/browser/service_worker/service_worker_registration_object_host.cc
@@ -4,11 +4,13 @@
#include "content/browser/service_worker/service_worker_registration_object_host.h"
+#include "base/time/time.h"
#include "content/browser/service_worker/service_worker_consts.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_object_host.h"
#include "content/browser/service_worker/service_worker_provider_host.h"
#include "content/common/service_worker/service_worker_utils.h"
+#include "content/public/browser/browser_thread.h"
#include "net/http/http_util.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
@@ -16,6 +18,9 @@ namespace content {
namespace {
+constexpr base::TimeDelta kSelfUpdateDelay = base::TimeDelta::FromSeconds(30);
+constexpr base::TimeDelta kMaxSelfUpdateDelay = base::TimeDelta::FromMinutes(3);
+
// Returns an object info to send over Mojo. The info must be sent immediately.
// See ServiceWorkerObjectHost::CreateCompleteObjectInfoToSend() for details.
blink::mojom::ServiceWorkerObjectInfoPtr CreateCompleteObjectInfoToSend(
@@ -28,6 +33,45 @@ blink::mojom::ServiceWorkerObjectInfoPtr CreateCompleteObjectInfoToSend(
return service_worker_object_host->CreateCompleteObjectInfoToSend();
}
+void ExecuteUpdate(base::WeakPtr<ServiceWorkerContextCore> context,
+ int64_t registration_id,
+ bool force_bypass_cache,
+ bool skip_script_comparison,
+ ServiceWorkerContextCore::UpdateCallback callback,
+ blink::ServiceWorkerStatusCode status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (status != blink::ServiceWorkerStatusCode::kOk) {
+ // The delay was already very long and update() is rejected immediately.
+ DCHECK_EQ(blink::ServiceWorkerStatusCode::kErrorTimeout, status);
+ std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorTimeout,
+ ServiceWorkerConsts::kUpdateTimeoutErrorMesage,
+ registration_id);
+ return;
+ }
+
+ if (!context) {
+ std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorAbort,
+ ServiceWorkerConsts::kShutdownErrorMessage,
+ registration_id);
+ return;
+ }
+
+ ServiceWorkerRegistration* registration =
+ context->GetLiveRegistration(registration_id);
+ if (!registration) {
+ // The service worker is no longer running, so update() won't be rejected.
+ // We still run the callback so the caller knows.
+ std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorTimeout,
+ ServiceWorkerConsts::kUpdateTimeoutErrorMesage,
+ registration_id);
+ return;
+ }
+
+ context->UpdateServiceWorker(registration, force_bypass_cache,
+ skip_script_comparison, std::move(callback));
+}
+
} // anonymous namespace
ServiceWorkerRegistrationObjectHost::ServiceWorkerRegistrationObjectHost(
@@ -116,14 +160,58 @@ void ServiceWorkerRegistrationObjectHost::Update(UpdateCallback callback) {
return;
}
- context_->UpdateServiceWorker(
- registration_.get(), false /* force_bypass_cache */,
- false /* skip_script_comparison */,
- base::AdaptCallbackForRepeating(
+ DelayUpdate(
+ provider_host_->provider_type(), registration_.get(),
+ provider_host_->running_hosted_version(),
+ base::BindOnce(
+ &ExecuteUpdate, context_, registration_->id(),
+ false /* force_bypass_cache */, false /* skip_script_comparison */,
base::BindOnce(&ServiceWorkerRegistrationObjectHost::UpdateComplete,
weak_ptr_factory_.GetWeakPtr(), std::move(callback))));
}
+void ServiceWorkerRegistrationObjectHost::DelayUpdate(
+ blink::mojom::ServiceWorkerProviderType provider_type,
+ ServiceWorkerRegistration* registration,
+ ServiceWorkerVersion* version,
+ StatusCallback update_function) {
+ DCHECK(registration);
+
+ if (provider_type !=
+ blink::mojom::ServiceWorkerProviderType::kForServiceWorker ||
+ (version && version->HasControllee())) {
+ // Don't delay update() if called by non-workers or by workers with
+ // controllees.
+ std::move(update_function).Run(blink::ServiceWorkerStatusCode::kOk);
+ return;
+ }
+
+ base::TimeDelta delay = registration->self_update_delay();
+ if (delay > kMaxSelfUpdateDelay) {
+ std::move(update_function)
+ .Run(blink::ServiceWorkerStatusCode::kErrorTimeout);
+ return;
+ }
+
+ if (delay < kSelfUpdateDelay) {
+ registration->set_self_update_delay(kSelfUpdateDelay);
+ } else {
+ registration->set_self_update_delay(delay * 2);
+ }
+
+ if (delay < base::TimeDelta::Min()) {
+ // Only enforce the delay of update() iff |delay| exists.
+ std::move(update_function).Run(blink::ServiceWorkerStatusCode::kOk);
+ return;
+ }
+
+ BrowserThread::PostDelayedTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(std::move(update_function),
+ blink::ServiceWorkerStatusCode::kOk),
+ delay);
+}
+
void ServiceWorkerRegistrationObjectHost::Unregister(
UnregisterCallback callback) {
if (!CanServeRegistrationObjectHostMethods(
@@ -302,6 +390,7 @@ void ServiceWorkerRegistrationObjectHost::SetVersionAttributes(
waiting = CreateCompleteObjectInfoToSend(provider_host_, waiting_version);
if (changed_mask.active_changed())
active = CreateCompleteObjectInfoToSend(provider_host_, active_version);
+
DCHECK(remote_registration_);
remote_registration_->SetVersionAttributes(
changed_mask.changed(), std::move(installing), std::move(waiting),
diff --git a/chromium/content/browser/service_worker/service_worker_registration_object_host.h b/chromium/content/browser/service_worker/service_worker_registration_object_host.h
index b96daf0cda7..cfca9b43e02 100644
--- a/chromium/content/browser/service_worker/service_worker_registration_object_host.h
+++ b/chromium/content/browser/service_worker/service_worker_registration_object_host.h
@@ -17,6 +17,9 @@
#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
namespace content {
+namespace service_worker_registration_unittest {
+class ServiceWorkerRegistrationObjectHostTest;
+} // namespace service_worker_registration_unittest
class ServiceWorkerContextCore;
class ServiceWorkerVersion;
@@ -46,6 +49,12 @@ class CONTENT_EXPORT ServiceWorkerRegistrationObjectHost
ServiceWorkerRegistration* registration() { return registration_.get(); }
private:
+ friend class service_worker_registration_unittest::
+ ServiceWorkerRegistrationObjectHostTest;
+
+ using StatusCallback =
+ base::OnceCallback<void(blink::ServiceWorkerStatusCode status)>;
+
// ServiceWorkerRegistration::Listener overrides.
void OnVersionAttributesChanged(
ServiceWorkerRegistration* registration,
@@ -68,6 +77,20 @@ class CONTENT_EXPORT ServiceWorkerRegistrationObjectHost
const std::string& value,
SetNavigationPreloadHeaderCallback callback) override;
+ // Delays an update if it is called by a worker without controllee, to prevent
+ // workers from running forever (see https://crbug.com/805496).
+ // Calls |update_function| with blink::ServiceWorkerStatusCode::kOk if the
+ // update should procceed, and blink::ServiceWorkerStatusCode::kTimeout
+ // otherwise.
+ // If there is no delay, or if the delay is very long, |update_function| is
+ // executed synchronously (before this method returns).
+ //
+ // TODO(falken): See if tests can call |Update| directly, then this separate
+ // function isn't needed.
+ static void DelayUpdate(blink::mojom::ServiceWorkerProviderType provider_type,
+ ServiceWorkerRegistration* registration,
+ ServiceWorkerVersion* version,
+ StatusCallback update_function);
// Called back from ServiceWorkerContextCore when an update is complete.
void UpdateComplete(UpdateCallback callback,
blink::ServiceWorkerStatusCode status,
diff --git a/chromium/content/browser/service_worker/service_worker_registration_status.cc b/chromium/content/browser/service_worker/service_worker_registration_status.cc
index c331293b639..6d154ff4c48 100644
--- a/chromium/content/browser/service_worker/service_worker_registration_status.cc
+++ b/chromium/content/browser/service_worker/service_worker_registration_status.cc
@@ -68,6 +68,7 @@ void GetServiceWorkerErrorTypeForRegistration(
case blink::ServiceWorkerStatusCode::kErrorEventWaitUntilRejected:
case blink::ServiceWorkerStatusCode::kErrorState:
case blink::ServiceWorkerStatusCode::kErrorDiskCache:
+ case blink::ServiceWorkerStatusCode::kErrorInvalidArguments:
// Unexpected, or should have bailed out before calling this, or we don't
// have a corresponding blink error code yet.
break; // Fall through to NOTREACHED().
diff --git a/chromium/content/browser/service_worker/service_worker_registration_unittest.cc b/chromium/content/browser/service_worker/service_worker_registration_unittest.cc
index 35671bbced4..62bf488958e 100644
--- a/chromium/content/browser/service_worker/service_worker_registration_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_registration_unittest.cc
@@ -128,13 +128,27 @@ class MockServiceWorkerRegistrationObject
binding_;
};
+// We need this for NoInflightRequest test. The test expects that a worker
+// will be terminated when SetIdleTimerDelayToZero() is called.
+class RegistrationTestHelper : public EmbeddedWorkerTestHelper {
+ public:
+ RegistrationTestHelper() : EmbeddedWorkerTestHelper(base::FilePath()) {}
+ ~RegistrationTestHelper() override = default;
+
+ protected:
+ void OnSetIdleTimerDelayToZero(int embedded_worker_id) override {
+ GetEmbeddedWorkerInstanceHost(embedded_worker_id)
+ ->RequestTermination(base::DoNothing());
+ }
+};
+
class ServiceWorkerRegistrationTest : public testing::Test {
public:
ServiceWorkerRegistrationTest()
: thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
void SetUp() override {
- helper_.reset(new EmbeddedWorkerTestHelper(base::FilePath()));
+ helper_ = std::make_unique<RegistrationTestHelper>();
context()->storage()->LazyInitializeForTest(base::DoNothing());
base::RunLoop().RunUntilIdle();
@@ -685,6 +699,27 @@ class ServiceWorkerRegistrationObjectHostTest
return error;
}
+ blink::ServiceWorkerStatusCode CallDelayUpdate(
+ blink::mojom::ServiceWorkerProviderType provider_type,
+ ServiceWorkerRegistration* registration,
+ ServiceWorkerVersion* version) {
+ base::Optional<blink::ServiceWorkerStatusCode> status;
+ base::RunLoop run_loop;
+ ServiceWorkerRegistrationObjectHost::DelayUpdate(
+ blink::mojom::ServiceWorkerProviderType::kForServiceWorker,
+ registration, version,
+ base::BindOnce(
+ [](base::Optional<blink::ServiceWorkerStatusCode>* out_status,
+ base::OnceClosure callback,
+ blink::ServiceWorkerStatusCode status) {
+ *out_status = status;
+ std::move(callback).Run();
+ },
+ &status, run_loop.QuitClosure()));
+ run_loop.Run();
+ return status.value();
+ }
+
blink::mojom::ServiceWorkerErrorType CallUnregister(
blink::mojom::ServiceWorkerRegistrationObjectHost* registration_host) {
blink::mojom::ServiceWorkerErrorType error =
@@ -717,21 +752,21 @@ class ServiceWorkerRegistrationObjectHostTest
return status.value();
}
- int64_t SetUpRegistration(const GURL& scope, const GURL& script_url) {
- storage()->LazyInitializeForTest(base::DoNothing());
- base::RunLoop().RunUntilIdle();
-
- // Prepare ServiceWorkerRegistration.
+ scoped_refptr<ServiceWorkerRegistration> CreateRegistration(
+ const GURL& scope) {
blink::mojom::ServiceWorkerRegistrationOptions options;
options.scope = scope;
- scoped_refptr<ServiceWorkerRegistration> registration =
- base::MakeRefCounted<ServiceWorkerRegistration>(
- options, storage()->NewRegistrationId(), context()->AsWeakPtr());
- // Prepare ServiceWorkerVersion.
+ return base::MakeRefCounted<ServiceWorkerRegistration>(
+ options, storage()->NewRegistrationId(), context()->AsWeakPtr());
+ }
+
+ scoped_refptr<ServiceWorkerVersion> CreateVersion(
+ ServiceWorkerRegistration* registration,
+ const GURL& script_url) {
scoped_refptr<ServiceWorkerVersion> version =
- base::MakeRefCounted<ServiceWorkerVersion>(
- registration.get(), script_url, storage()->NewVersionId(),
- context()->AsWeakPtr());
+ base::MakeRefCounted<ServiceWorkerVersion>(registration, script_url,
+ storage()->NewVersionId(),
+ context()->AsWeakPtr());
std::vector<ServiceWorkerDatabase::ResourceRecord> records;
records.push_back(WriteToDiskCacheSync(
storage(), version->script_url(), storage()->NewResourceId(),
@@ -742,13 +777,26 @@ class ServiceWorkerRegistrationObjectHostTest
version->set_fetch_handler_existence(
ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
version->SetStatus(ServiceWorkerVersion::INSTALLING);
+ return version;
+ }
+
+ int64_t SetUpRegistration(const GURL& scope, const GURL& script_url) {
+ storage()->LazyInitializeForTest(base::DoNothing());
+ base::RunLoop().RunUntilIdle();
+
+ // Prepare ServiceWorkerRegistration and ServiceWorkerVersion.
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ CreateRegistration(scope);
+ scoped_refptr<ServiceWorkerVersion> version =
+ CreateVersion(registration.get(), script_url);
+
// Make the registration findable via storage functions.
bool called = false;
blink::ServiceWorkerStatusCode status =
blink::ServiceWorkerStatusCode::kErrorFailed;
- storage()->StoreRegistration(registration.get(), version.get(),
- base::AdaptCallbackForRepeating(base::BindOnce(
- &SaveStatusCallback, &called, &status)));
+ storage()->StoreRegistration(
+ registration.get(), version.get(),
+ base::BindOnce(&SaveStatusCallback, &called, &status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status);
@@ -880,6 +928,102 @@ TEST_F(ServiceWorkerRegistrationObjectHostTest,
SetBrowserClientForTesting(old_browser_client);
}
+TEST_F(ServiceWorkerRegistrationObjectHostTest, Update_NoDelayFromControllee) {
+ const GURL kScope("https://www.example.com/");
+ const GURL kScriptUrl("https://www.example.com/sw.js");
+ int64_t registration_id = SetUpRegistration(kScope, kScriptUrl);
+ const int64_t kProviderId = 99; // Dummy value
+ ServiceWorkerRemoteProviderEndpoint remote_endpoint =
+ PrepareProviderHost(kProviderId, kScope);
+ blink::mojom::ServiceWorkerRegistrationObjectHostAssociatedPtr
+ registration_host_ptr;
+
+ blink::mojom::ServiceWorkerRegistrationObjectInfoPtr info =
+ GetRegistrationFromRemote(remote_endpoint.host_ptr()->get(), kScope);
+ registration_host_ptr.Bind(std::move(info->host_ptr_info));
+ // Ignore the messages to the registration object, otherwise the callbacks
+ // issued from |registration_host_ptr| may wait for receiving the messages to
+ // |info->request|.
+ info->request = nullptr;
+
+ // Get registration and set |self_update_delay| to zero.
+ ServiceWorkerRegistration* registration =
+ context()->GetLiveRegistration(registration_id);
+ ASSERT_TRUE(registration);
+ registration->set_self_update_delay(base::TimeDelta());
+ EXPECT_EQ(base::TimeDelta(), registration->self_update_delay());
+
+ EXPECT_EQ(blink::mojom::ServiceWorkerErrorType::kNone,
+ CallUpdate(registration_host_ptr.get()));
+ EXPECT_EQ(base::TimeDelta(), registration->self_update_delay());
+}
+
+TEST_F(ServiceWorkerRegistrationObjectHostTest,
+ Update_DelayFromWorkerWithoutControllee) {
+ const GURL kScope("https://www.example.com/");
+ const GURL kScriptUrl("https://www.example.com/sw.js");
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ CreateRegistration(kScope);
+ scoped_refptr<ServiceWorkerVersion> version =
+ CreateVersion(registration.get(), kScriptUrl);
+
+ // Initially set |self_update_delay| to zero.
+ registration->set_self_update_delay(base::TimeDelta());
+ EXPECT_EQ(base::TimeDelta(), registration->self_update_delay());
+
+ EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk,
+ CallDelayUpdate(
+ blink::mojom::ServiceWorkerProviderType::kForServiceWorker,
+ registration.get(), version.get()));
+ EXPECT_LT(base::TimeDelta(), registration->self_update_delay());
+
+ // TODO(falken): Add a test verifying that a delayed update will be executed
+ // eventually.
+
+ // Set |self_update_delay| to a time so that update() will reject immediately.
+ registration->set_self_update_delay(base::TimeDelta::FromMinutes(5));
+ EXPECT_EQ(blink::ServiceWorkerStatusCode::kErrorTimeout,
+ CallDelayUpdate(
+ blink::mojom::ServiceWorkerProviderType::kForServiceWorker,
+ registration.get(), version.get()));
+ EXPECT_LE(base::TimeDelta::FromMinutes(5), registration->self_update_delay());
+}
+
+TEST_F(ServiceWorkerRegistrationObjectHostTest,
+ Update_NoDelayFromWorkerWithControllee) {
+ const GURL kScope("https://www.example.com/");
+ const GURL kScriptUrl("https://www.example.com/sw.js");
+ const int64_t kProviderId = 99; // Dummy value
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ CreateRegistration(kScope);
+ scoped_refptr<ServiceWorkerVersion> version =
+ CreateVersion(registration.get(), kScriptUrl);
+ ServiceWorkerRemoteProviderEndpoint remote_endpoint;
+ std::unique_ptr<ServiceWorkerProviderHost> host = CreateProviderHostForWindow(
+ helper_->mock_render_process_id(), kProviderId,
+ true /* is_parent_frame_secure */, context()->AsWeakPtr(),
+ &remote_endpoint);
+ host->SetDocumentUrl(kScope);
+ version->AddControllee(host.get());
+
+ // Initially set |self_update_delay| to zero.
+ registration->set_self_update_delay(base::TimeDelta());
+ EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk,
+ CallDelayUpdate(
+ blink::mojom::ServiceWorkerProviderType::kForServiceWorker,
+ registration.get(), version.get()));
+ EXPECT_EQ(base::TimeDelta(), registration->self_update_delay());
+
+ // Set |self_update_delay| to a time so that update() will reject immediately
+ // if the worker doesn't have at least one controlee.
+ registration->set_self_update_delay(base::TimeDelta::FromMinutes(5));
+ EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk,
+ CallDelayUpdate(
+ blink::mojom::ServiceWorkerProviderType::kForServiceWorker,
+ registration.get(), version.get()));
+ EXPECT_EQ(base::TimeDelta::FromMinutes(5), registration->self_update_delay());
+}
+
TEST_F(ServiceWorkerRegistrationObjectHostTest, Unregister_Success) {
const GURL kScope("https://www.example.com/");
const GURL kScriptUrl("https://www.example.com/sw.js");
diff --git a/chromium/content/browser/service_worker/service_worker_request_handler.cc b/chromium/content/browser/service_worker/service_worker_request_handler.cc
index 15033201505..e72645e490f 100644
--- a/chromium/content/browser/service_worker/service_worker_request_handler.cc
+++ b/chromium/content/browser/service_worker/service_worker_request_handler.cc
@@ -136,7 +136,7 @@ void ServiceWorkerRequestHandler::InitializeForNavigation(
// static
std::unique_ptr<NavigationLoaderInterceptor>
ServiceWorkerRequestHandler::InitializeForNavigationNetworkService(
- const network::ResourceRequest& resource_request,
+ const GURL& url,
ResourceContext* resource_context,
ServiceWorkerNavigationHandleCore* navigation_handle_core,
storage::BlobStorageContext* blob_storage_context,
@@ -152,8 +152,7 @@ ServiceWorkerRequestHandler::InitializeForNavigationNetworkService(
// Create the handler even for insecure HTTP since it's used in the
// case of redirect to HTTPS.
- if (!resource_request.url.SchemeIsHTTPOrHTTPS() &&
- !OriginCanAccessServiceWorkers(resource_request.url)) {
+ if (!url.SchemeIsHTTPOrHTTPS() && !OriginCanAccessServiceWorkers(url)) {
return nullptr;
}
@@ -284,7 +283,7 @@ bool ServiceWorkerRequestHandler::IsControlledByServiceWorker(
ServiceWorkerRequestHandler* handler = GetHandler(request);
if (!handler || !handler->provider_host_)
return false;
- return handler->provider_host_->associated_registration() ||
+ return handler->provider_host_->controller() ||
handler->provider_host_->running_hosted_version();
}
@@ -296,9 +295,10 @@ ServiceWorkerProviderHost* ServiceWorkerRequestHandler::GetProviderHost(
}
void ServiceWorkerRequestHandler::MaybeCreateLoader(
- const network::ResourceRequest& request,
+ const network::ResourceRequest& tentative_request,
ResourceContext* resource_context,
- LoaderCallback callback) {
+ LoaderCallback callback,
+ FallbackCallback fallback_callback) {
NOTREACHED();
std::move(callback).Run({});
}
diff --git a/chromium/content/browser/service_worker/service_worker_request_handler.h b/chromium/content/browser/service_worker/service_worker_request_handler.h
index 5ab4546ffb3..41132905487 100644
--- a/chromium/content/browser/service_worker/service_worker_request_handler.h
+++ b/chromium/content/browser/service_worker/service_worker_request_handler.h
@@ -71,7 +71,7 @@ class CONTENT_EXPORT ServiceWorkerRequestHandler
// just creates a NavigationLoaderInterceptor and returns it.
static std::unique_ptr<NavigationLoaderInterceptor>
InitializeForNavigationNetworkService(
- const network::ResourceRequest& resource_request,
+ const GURL& url,
ResourceContext* resource_context,
ServiceWorkerNavigationHandleCore* navigation_handle_core,
storage::BlobStorageContext* blob_storage_context,
@@ -139,9 +139,10 @@ class CONTENT_EXPORT ServiceWorkerRequestHandler
ResourceContext* context) = 0;
// NavigationLoaderInterceptor overrides.
- void MaybeCreateLoader(const network::ResourceRequest& request,
+ void MaybeCreateLoader(const network::ResourceRequest& tentative_request,
ResourceContext* resource_context,
- LoaderCallback callback) override;
+ LoaderCallback callback,
+ FallbackCallback fallback_callback) override;
protected:
ServiceWorkerRequestHandler(
diff --git a/chromium/content/browser/service_worker/service_worker_request_handler_unittest.cc b/chromium/content/browser/service_worker/service_worker_request_handler_unittest.cc
index 1806fc576cd..2aaa2c7e9ee 100644
--- a/chromium/content/browser/service_worker/service_worker_request_handler_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_request_handler_unittest.cc
@@ -135,6 +135,20 @@ class ServiceWorkerRequestHandlerTest : public testing::Test {
void InitializeHandlerForNavigationSimpleTest(const std::string& url,
bool expected_handler_created) {
+ bool handler_created = false;
+ if (blink::ServiceWorkerUtils::IsServicificationEnabled()) {
+ handler_created = InitializeHandlerForNavigationNetworkService(
+ url, expected_handler_created);
+ } else {
+ handler_created = InitializeHandlerForNavigationNonNetworkService(
+ url, expected_handler_created);
+ }
+ EXPECT_EQ(expected_handler_created, handler_created);
+ }
+
+ bool InitializeHandlerForNavigationNonNetworkService(
+ const std::string& url,
+ bool expected_handler_created) {
std::unique_ptr<ServiceWorkerNavigationHandleCore> navigation_handle_core =
CreateNavigationHandleCore(helper_->context_wrapper());
std::unique_ptr<net::URLRequest> request = CreateRequest(url, "GET");
@@ -142,9 +156,27 @@ class ServiceWorkerRequestHandlerTest : public testing::Test {
request.get(), navigation_handle_core.get(), &blob_storage_context_,
false /* skip_service_worker */, RESOURCE_TYPE_MAIN_FRAME,
REQUEST_CONTEXT_TYPE_HYPERLINK,
- network::mojom::RequestContextFrameType::kTopLevel, true,
- nullptr /* body */, base::RepeatingCallback<WebContents*(void)>());
- EXPECT_EQ(expected_handler_created, !!GetHandler(request.get()));
+ network::mojom::RequestContextFrameType::kTopLevel,
+ true /* is_parent_frame_secure */, nullptr /* body */,
+ base::RepeatingCallback<WebContents*(void)>());
+ return !!GetHandler(request.get());
+ }
+
+ bool InitializeHandlerForNavigationNetworkService(
+ const std::string& url,
+ bool expected_handler_created) {
+ std::unique_ptr<ServiceWorkerNavigationHandleCore> navigation_handle_core =
+ CreateNavigationHandleCore(helper_->context_wrapper());
+ std::unique_ptr<NavigationLoaderInterceptor> interceptor =
+ ServiceWorkerRequestHandler::InitializeForNavigationNetworkService(
+ GURL(url), nullptr /* resource_context */,
+ navigation_handle_core.get(), &blob_storage_context_,
+ false /* skip_service_worker */, RESOURCE_TYPE_MAIN_FRAME,
+ REQUEST_CONTEXT_TYPE_HYPERLINK,
+ network::mojom::RequestContextFrameType::kTopLevel,
+ true /* is_parent_frame_secure */, nullptr /* body */,
+ base::RepeatingCallback<WebContents*(void)>());
+ return !!interceptor.get();
}
TestBrowserThreadBundle browser_thread_bundle_;
diff --git a/chromium/content/browser/service_worker/service_worker_response_info.cc b/chromium/content/browser/service_worker/service_worker_response_info.cc
index 83efc85f19d..e837a8d854a 100644
--- a/chromium/content/browser/service_worker/service_worker_response_info.cc
+++ b/chromium/content/browser/service_worker/service_worker_response_info.cc
@@ -42,8 +42,7 @@ void ServiceWorkerResponseInfo::GetExtraResponseInfo(
response_info->was_fallback_required_by_service_worker =
was_fallback_required_;
response_info->url_list_via_service_worker = url_list_via_service_worker_;
- response_info->response_type_via_service_worker =
- response_type_via_service_worker_;
+ response_info->response_type = response_type_via_service_worker_;
response_info->service_worker_start_time = service_worker_start_time_;
response_info->service_worker_ready_time = service_worker_ready_time_;
response_info->is_in_cache_storage = response_is_in_cache_storage_;
diff --git a/chromium/content/browser/service_worker/service_worker_script_cache_map.cc b/chromium/content/browser/service_worker/service_worker_script_cache_map.cc
index c843ab379f0..09f44ad00a1 100644
--- a/chromium/content/browser/service_worker/service_worker_script_cache_map.cc
+++ b/chromium/content/browser/service_worker/service_worker_script_cache_map.cc
@@ -92,12 +92,18 @@ void ServiceWorkerScriptCacheMap::WriteMetadata(
const GURL& url,
const std::vector<uint8_t>& data,
const net::CompletionCallback& callback) {
+ if (!context_) {
+ callback.Run(net::ERR_ABORTED);
+ return;
+ }
+
ResourceMap::iterator found = resource_map_.find(url);
if (found == resource_map_.end() ||
found->second.resource_id == kInvalidServiceWorkerResourceId) {
callback.Run(net::ERR_FILE_NOT_FOUND);
return;
}
+
scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(data.size()));
if (data.size())
memmove(buffer->data(), &data[0], data.size());
diff --git a/chromium/content/browser/service_worker/service_worker_script_loader_factory.h b/chromium/content/browser/service_worker/service_worker_script_loader_factory.h
index efc08ff62e5..2eb05ea0815 100644
--- a/chromium/content/browser/service_worker/service_worker_script_loader_factory.h
+++ b/chromium/content/browser/service_worker/service_worker_script_loader_factory.h
@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_SCRIPT_LOADER_FACTORY_H_
#include "base/macros.h"
+#include "content/common/content_export.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
@@ -30,7 +31,7 @@ class ServiceWorkerProviderHost;
//
// This factory creates either a ServiceWorkerNewScriptLoader or a
// ServiceWorkerInstalledScriptLoader to load a script.
-class ServiceWorkerScriptLoaderFactory
+class CONTENT_EXPORT ServiceWorkerScriptLoaderFactory
: public network::mojom::URLLoaderFactory {
public:
// |loader_factory| is used to load scripts. Typically
diff --git a/chromium/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc b/chromium/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc
new file mode 100644
index 00000000000..c53cae17369
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc
@@ -0,0 +1,176 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/service_worker/service_worker_script_loader_factory.h"
+
+#include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
+#include "content/browser/service_worker/embedded_worker_test_helper.h"
+#include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/browser/service_worker/service_worker_registration.h"
+#include "content/browser/service_worker/service_worker_test_utils.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/http/http_util.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/network/test/test_url_loader_client.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
+
+namespace content {
+
+namespace {
+
+// A URLLoaderFactory that returns 200 OK with an empty javascript to any
+// request.
+// TODO(bashi): Avoid duplicated MockNetworkURLLoaderFactory. This is almost the
+// same as EmbeddedWorkerTestHelper::MockNetworkURLLoaderFactory.
+class MockNetworkURLLoaderFactory final
+ : public network::mojom::URLLoaderFactory {
+ public:
+ MockNetworkURLLoaderFactory() = default;
+
+ // network::mojom::URLLoaderFactory implementation.
+ void CreateLoaderAndStart(network::mojom::URLLoaderRequest request,
+ int32_t routing_id,
+ int32_t request_id,
+ uint32_t options,
+ const network::ResourceRequest& url_request,
+ network::mojom::URLLoaderClientPtr client,
+ const net::MutableNetworkTrafficAnnotationTag&
+ traffic_annotation) override {
+ const std::string headers =
+ "HTTP/1.1 200 OK\n"
+ "Content-Type: application/javascript\n\n";
+ net::HttpResponseInfo info;
+ info.headers = new net::HttpResponseHeaders(
+ net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.length()));
+ network::ResourceResponseHead response;
+ response.headers = info.headers;
+ response.headers->GetMimeType(&response.mime_type);
+ client->OnReceiveResponse(response);
+
+ const std::string body = "/*this body came from the network*/";
+ uint32_t bytes_written = body.size();
+ mojo::DataPipe data_pipe;
+ data_pipe.producer_handle->WriteData(body.data(), &bytes_written,
+ MOJO_WRITE_DATA_FLAG_ALL_OR_NONE);
+ client->OnStartLoadingResponseBody(std::move(data_pipe.consumer_handle));
+
+ network::URLLoaderCompletionStatus status;
+ status.error_code = net::OK;
+ client->OnComplete(status);
+ }
+
+ void Clone(network::mojom::URLLoaderFactoryRequest request) override {
+ bindings_.AddBinding(this, std::move(request));
+ }
+
+ private:
+ mojo::BindingSet<network::mojom::URLLoaderFactory> bindings_;
+ DISALLOW_COPY_AND_ASSIGN(MockNetworkURLLoaderFactory);
+};
+
+} // namespace
+
+class ServiceWorkerScriptLoaderFactoryTest : public testing::Test {
+ public:
+ ServiceWorkerScriptLoaderFactoryTest()
+ : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
+ ~ServiceWorkerScriptLoaderFactoryTest() override = default;
+
+ void SetUp() override {
+ scoped_feature_list_.InitAndEnableFeature(
+ blink::features::kServiceWorkerServicification);
+
+ helper_ = std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath());
+ ServiceWorkerContextCore* context = helper_->context();
+ context->storage()->LazyInitializeForTest(base::DoNothing());
+ base::RunLoop().RunUntilIdle();
+
+ scope_ = GURL("https://host/scope");
+
+ blink::mojom::ServiceWorkerRegistrationOptions options;
+ options.scope = scope_;
+ registration_ = base::MakeRefCounted<ServiceWorkerRegistration>(
+ options, 1L /* registration_id */, context->AsWeakPtr());
+ version_ = base::MakeRefCounted<ServiceWorkerVersion>(
+ registration_.get(), GURL("https://host/script.js"),
+ context->storage()->NewVersionId(), context->AsWeakPtr());
+
+ provider_host_ = CreateProviderHostForServiceWorkerContext(
+ helper_->mock_render_process_id(), true /* is_parent_frame_secure */,
+ version_.get(), context->AsWeakPtr(), &remote_endpoint_);
+
+ network_loader_factory_ = std::make_unique<MockNetworkURLLoaderFactory>();
+ helper_->SetNetworkFactory(network_loader_factory_.get());
+
+ factory_ = std::make_unique<ServiceWorkerScriptLoaderFactory>(
+ helper_->context()->AsWeakPtr(), provider_host_,
+ helper_->url_loader_factory_getter()->GetNetworkFactory());
+ }
+
+ protected:
+ network::mojom::URLLoaderPtr CreateTestLoaderAndStart(
+ network::TestURLLoaderClient* client) {
+ network::mojom::URLLoaderPtr loader;
+ network::ResourceRequest resource_request;
+ resource_request.url = scope_;
+ resource_request.resource_type = RESOURCE_TYPE_SERVICE_WORKER;
+ factory_->CreateLoaderAndStart(
+ mojo::MakeRequest(&loader), 0 /* routing_id */, 0 /* request_id */,
+ network::mojom::kURLLoadOptionNone, resource_request,
+ client->CreateInterfacePtr(),
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
+ return loader;
+ }
+
+ base::test::ScopedFeatureList scoped_feature_list_;
+ TestBrowserThreadBundle browser_thread_bundle_;
+ std::unique_ptr<EmbeddedWorkerTestHelper> helper_;
+ GURL scope_;
+ scoped_refptr<ServiceWorkerRegistration> registration_;
+ scoped_refptr<ServiceWorkerVersion> version_;
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host_;
+ ServiceWorkerRemoteProviderEndpoint remote_endpoint_;
+ std::unique_ptr<MockNetworkURLLoaderFactory> network_loader_factory_;
+ std::unique_ptr<ServiceWorkerScriptLoaderFactory> factory_;
+};
+
+TEST_F(ServiceWorkerScriptLoaderFactoryTest, Success) {
+ network::TestURLLoaderClient client;
+ network::mojom::URLLoaderPtr loader = CreateTestLoaderAndStart(&client);
+ client.RunUntilComplete();
+ EXPECT_EQ(net::OK, client.completion_status().error_code);
+}
+
+TEST_F(ServiceWorkerScriptLoaderFactoryTest, Redundant) {
+ version_->SetStatus(ServiceWorkerVersion::REDUNDANT);
+
+ network::TestURLLoaderClient client;
+ network::mojom::URLLoaderPtr loader = CreateTestLoaderAndStart(&client);
+ client.RunUntilComplete();
+ EXPECT_EQ(net::ERR_ABORTED, client.completion_status().error_code);
+}
+
+TEST_F(ServiceWorkerScriptLoaderFactoryTest, NoProviderHost) {
+ helper_->context()->RemoveProviderHost(helper_->mock_render_process_id(),
+ provider_host_->provider_id());
+
+ network::TestURLLoaderClient client;
+ network::mojom::URLLoaderPtr loader = CreateTestLoaderAndStart(&client);
+ client.RunUntilComplete();
+ EXPECT_EQ(net::ERR_ABORTED, client.completion_status().error_code);
+}
+
+TEST_F(ServiceWorkerScriptLoaderFactoryTest, ContextDestroyed) {
+ helper_->ShutdownContext();
+ base::RunLoop().RunUntilIdle();
+
+ network::TestURLLoaderClient client;
+ network::mojom::URLLoaderPtr loader = CreateTestLoaderAndStart(&client);
+ client.RunUntilComplete();
+ EXPECT_EQ(net::ERR_ABORTED, client.completion_status().error_code);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_storage.cc b/chromium/content/browser/service_worker/service_worker_storage.cc
index 93a71912a4c..92b13a6c60e 100644
--- a/chromium/content/browser/service_worker/service_worker_storage.cc
+++ b/chromium/content/browser/service_worker/service_worker_storage.cc
@@ -12,8 +12,8 @@
#include "base/files/file_util.h"
#include "base/memory/ptr_util.h"
#include "base/sequenced_task_runner.h"
+#include "base/task/post_task.h"
#include "base/task_runner_util.h"
-#include "base/task_scheduler/post_task.h"
#include "base/trace_event/trace_event.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_disk_cache.h"
diff --git a/chromium/content/browser/service_worker/service_worker_storage_unittest.cc b/chromium/content/browser/service_worker/service_worker_storage_unittest.cc
index babac6c2096..9d1aab24ec6 100644
--- a/chromium/content/browser/service_worker/service_worker_storage_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_storage_unittest.cc
@@ -172,13 +172,14 @@ int WriteResponse(ServiceWorkerStorage* storage,
std::unique_ptr<ServiceWorkerResponseWriter> writer =
storage->CreateResponseWriter(id);
- std::unique_ptr<net::HttpResponseInfo> info(new net::HttpResponseInfo);
+ std::unique_ptr<net::HttpResponseInfo> info =
+ std::make_unique<net::HttpResponseInfo>();
info->request_time = base::Time::Now();
info->response_time = base::Time::Now();
info->was_cached = false;
info->headers = new net::HttpResponseHeaders(headers);
scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
- new HttpResponseInfoIOBuffer(info.release());
+ base::MakeRefCounted<HttpResponseInfoIOBuffer>(std::move(info));
int rv = 0;
{
TestCompletionCallback cb;
diff --git a/chromium/content/browser/service_worker/service_worker_test_utils.cc b/chromium/content/browser/service_worker/service_worker_test_utils.cc
index 384440dc50c..05e9cb72dea 100644
--- a/chromium/content/browser/service_worker/service_worker_test_utils.cc
+++ b/chromium/content/browser/service_worker/service_worker_test_utils.cc
@@ -105,7 +105,7 @@ void WriteBodyToDiskCache(std::unique_ptr<ServiceWorkerResponseWriter> writer,
const std::string& body,
base::OnceClosure callback) {
scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
- base::MakeRefCounted<HttpResponseInfoIOBuffer>(info.release());
+ base::MakeRefCounted<HttpResponseInfoIOBuffer>(std::move(info));
info_buffer->response_data_size = body.size();
ServiceWorkerResponseWriter* writer_rawptr = writer.get();
writer_rawptr->WriteInfo(
diff --git a/chromium/content/browser/service_worker/service_worker_url_job_wrapper.cc b/chromium/content/browser/service_worker/service_worker_url_job_wrapper.cc
index 52fc1fc8fe3..eaf770dc02d 100644
--- a/chromium/content/browser/service_worker/service_worker_url_job_wrapper.cc
+++ b/chromium/content/browser/service_worker/service_worker_url_job_wrapper.cc
@@ -64,6 +64,14 @@ bool ServiceWorkerURLJobWrapper::ShouldFallbackToNetwork() {
}
}
+bool ServiceWorkerURLJobWrapper::ShouldForwardToServiceWorker() {
+ if (url_loader_job_) {
+ return url_loader_job_->ShouldForwardToServiceWorker();
+ } else {
+ return url_request_job_->ShouldForwardToServiceWorker();
+ }
+}
+
void ServiceWorkerURLJobWrapper::FailDueToLostController() {
// This function is only called for subresource requests, so it can't
// be called for |url_loader_job_|, which is for navigations.
diff --git a/chromium/content/browser/service_worker/service_worker_url_job_wrapper.h b/chromium/content/browser/service_worker/service_worker_url_job_wrapper.h
index acaf609c685..c2cc39872ce 100644
--- a/chromium/content/browser/service_worker/service_worker_url_job_wrapper.h
+++ b/chromium/content/browser/service_worker/service_worker_url_job_wrapper.h
@@ -22,7 +22,7 @@ class ServiceWorkerVersion;
// non-S13nServiceWorker). It wraps either a
// ServiceWorkerURLRequestJob or a callback for URLLoader and forwards to the
// underlying implementation.
-class ServiceWorkerURLJobWrapper {
+class CONTENT_EXPORT ServiceWorkerURLJobWrapper {
public:
// A helper used by the ServiceWorkerNavigationLoader or
// ServiceWorkerURLRequestJob.
@@ -51,6 +51,11 @@ class ServiceWorkerURLJobWrapper {
// Called to signal that loading failed, and that the resource being loaded
// was a main resource.
virtual void MainResourceLoadFailed() {}
+
+ virtual void ReportDestination(
+ ServiceWorkerMetrics::MainResourceRequestDestination destination) {}
+
+ virtual void WillDispatchFetchEventForMainResource() {}
};
// Non-S13nServiceWorker.
@@ -72,6 +77,9 @@ class ServiceWorkerURLJobWrapper {
// instead should fallback to the network.
bool ShouldFallbackToNetwork();
+ // Returns true if this job should be forwarded to a service worker.
+ bool ShouldForwardToServiceWorker();
+
// Tells the job to abort with a start error. Currently this is only called
// because the controller was lost. This function could be made more generic
// if needed later.
diff --git a/chromium/content/browser/service_worker/service_worker_url_request_job.cc b/chromium/content/browser/service_worker/service_worker_url_request_job.cc
index c40adc1c9bb..033f55cb8cd 100644
--- a/chromium/content/browser/service_worker/service_worker_url_request_job.cc
+++ b/chromium/content/browser/service_worker/service_worker_url_request_job.cc
@@ -20,7 +20,7 @@
#include "base/location.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/stringprintf.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "content/browser/resource_context_impl.h"
@@ -353,6 +353,7 @@ ServiceWorkerURLRequestJob::~ServiceWorkerURLRequestJob() {
if (!ShouldRecordResult())
return;
+
ServiceWorkerMetrics::URLRequestJobResult result =
ServiceWorkerMetrics::REQUEST_JOB_ERROR_KILLED;
if (response_body_type_ == STREAM)
@@ -558,8 +559,7 @@ ServiceWorkerURLRequestJob::CreateResourceRequest() {
for (net::HttpRequestHeaders::Iterator it(request_->extra_request_headers());
it.GetNext();) {
- if (!ServiceWorkerContext::IsExcludedHeaderNameForFetchEvent(it.name()))
- request->headers.SetHeader(it.name(), it.value());
+ request->headers.SetHeader(it.name(), it.value());
}
request->referrer = GURL(request_->referrer());
@@ -658,9 +658,8 @@ void ServiceWorkerURLRequestJob::DidPrepareFetchEvent(
void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
blink::ServiceWorkerStatusCode status,
ServiceWorkerFetchDispatcher::FetchEventResult fetch_result,
- const ServiceWorkerResponse& response,
+ blink::mojom::FetchAPIResponsePtr response,
blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream,
- blink::mojom::BlobPtr body_as_blob,
scoped_refptr<ServiceWorkerVersion> version) {
// Do not clear |fetch_dispatcher_| if it has dispatched a navigation preload
// request to keep the network::mojom::URLLoader related objects in it,
@@ -669,6 +668,10 @@ void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
if (!did_navigation_preload_) {
fetch_dispatcher_.reset();
}
+ if (IsMainResourceLoad()) {
+ ReportDestination(
+ ServiceWorkerMetrics::MainResourceRequestDestination::kServiceWorker);
+ }
ServiceWorkerMetrics::RecordFetchEventStatus(IsMainResourceLoad(), status);
ServiceWorkerMetrics::URLRequestJobResult result =
@@ -708,9 +711,9 @@ void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
// A response with status code 0 is Blink telling us to respond with network
// error.
- if (response.status_code == 0) {
- RecordStatusZeroResponseError(response.error);
- NotifyStartError(ServiceWorkerResponseErrorToNetStatus(response.error));
+ if (response->status_code == 0) {
+ RecordStatusZeroResponseError(response->error);
+ NotifyStartError(ServiceWorkerResponseErrorToNetStatus(response->error));
return;
}
@@ -730,7 +733,7 @@ void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
// Process stream using Mojo's data pipe.
if (!body_as_stream.is_null()) {
SetResponseBodyType(STREAM);
- SetResponse(response);
+ SetResponse(std::move(response));
data_pipe_reader_.reset(new ServiceWorkerDataPipeReader(
this, version, std::move(body_as_stream)));
data_pipe_reader_->Start();
@@ -738,14 +741,14 @@ void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
}
// Set up a request for reading the blob.
- // |body_as_blob| must be kept around until we call this to ensure that
- // it's alive.
- // TODO(falken): Can we just read |body_as_blob| directly like in
+ // TODO(falken): Can we just read |response->blob->blob| directly like in
// ServiceWorkerNavigationLoader?
- if (!response.blob_uuid.empty() && blob_storage_context_) {
+ if (response->blob && blob_storage_context_) {
+ DCHECK(!response->blob->uuid.empty());
+ DCHECK(response->blob->blob.is_valid());
SetResponseBodyType(BLOB);
std::unique_ptr<storage::BlobDataHandle> blob_data_handle =
- blob_storage_context_->GetBlobDataFromUUID(response.blob_uuid);
+ blob_storage_context_->GetBlobDataFromUUID(response->blob->uuid);
if (!blob_data_handle) {
// The renderer gave us a bad blob UUID.
RecordResult(ServiceWorkerMetrics::REQUEST_JOB_ERROR_BAD_BLOB);
@@ -756,7 +759,7 @@ void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
blob_reader_->Start(std::move(blob_data_handle), request()->context());
}
- SetResponse(response);
+ SetResponse(std::move(response));
if (!blob_reader_) {
RecordResult(ServiceWorkerMetrics::REQUEST_JOB_HEADERS_ONLY_RESPONSE);
CommitResponseHeader();
@@ -764,31 +767,36 @@ void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
}
void ServiceWorkerURLRequestJob::SetResponse(
- const ServiceWorkerResponse& response) {
- response_url_list_ = response.url_list;
- fetch_response_type_ = response.response_type;
- cors_exposed_header_names_ = response.cors_exposed_header_names;
- response_time_ = response.response_time;
- CreateResponseHeader(response.status_code, response.status_text,
- response.headers);
+ blink::mojom::FetchAPIResponsePtr response) {
+ response_url_list_ = std::move(response->url_list);
+ fetch_response_type_ = response->response_type;
+ cors_exposed_header_names_ = std::move(response->cors_exposed_header_names);
+ response_time_ = response->response_time;
+ CreateResponseHeader(response->status_code, response->status_text,
+ std::move(response->headers));
load_timing_info_.receive_headers_end = base::TimeTicks::Now();
- response_is_in_cache_storage_ = response.is_in_cache_storage;
- response_cache_storage_cache_name_ = response.cache_storage_cache_name;
+ response_is_in_cache_storage_ = response->is_in_cache_storage;
+ if (response->cache_storage_cache_name) {
+ response_cache_storage_cache_name_ =
+ std::move(*(response->cache_storage_cache_name));
+ } else {
+ response_cache_storage_cache_name_.clear();
+ }
}
void ServiceWorkerURLRequestJob::CreateResponseHeader(
int status_code,
const std::string& status_text,
- const ServiceWorkerHeaderMap& headers) {
+ ResponseHeaderMap headers) {
// Build a string instead of using HttpResponseHeaders::AddHeader on
// each header, since AddHeader has O(n^2) performance.
std::string buf(base::StringPrintf("HTTP/1.1 %d %s\r\n", status_code,
status_text.c_str()));
- for (const auto& item : headers) {
- buf.append(item.first);
+ for (auto& item : headers) {
+ buf.append(std::move(item.first));
buf.append(": ");
- buf.append(item.second);
+ buf.append(std::move(item.second));
buf.append("\r\n");
}
buf.append("\r\n");
@@ -809,8 +817,8 @@ void ServiceWorkerURLRequestJob::CommitResponseHeader() {
void ServiceWorkerURLRequestJob::DeliverErrorResponse() {
// TODO(falken): Print an error to the console of the ServiceWorker and of
// the requesting page.
- CreateResponseHeader(
- 500, "Service Worker Response Error", ServiceWorkerHeaderMap());
+ CreateResponseHeader(500, "Service Worker Response Error",
+ ResponseHeaderMap());
CommitResponseHeader();
}
@@ -831,7 +839,7 @@ void ServiceWorkerURLRequestJob::FinalizeFallbackToRenderer() {
if (ShouldRecordResult())
RecordResult(ServiceWorkerMetrics::REQUEST_JOB_FALLBACK_FOR_CORS);
CreateResponseHeader(400, "Service Worker Fallback Required",
- ServiceWorkerHeaderMap());
+ ResponseHeaderMap());
response_type_ = ResponseType::FALLBACK_TO_RENDERER;
CommitResponseHeader();
}
@@ -946,6 +954,11 @@ void ServiceWorkerURLRequestJob::RequestBodyFileSizesResolved(bool success) {
if (!success) {
RecordResult(
ServiceWorkerMetrics::REQUEST_JOB_ERROR_REQUEST_BODY_BLOB_FAILED);
+ if (IsMainResourceLoad()) {
+ ReportDestination(ServiceWorkerMetrics::MainResourceRequestDestination::
+ kErrorRequestBodyFailed);
+ }
+
// TODO(falken): This and below should probably be NotifyStartError, not
// DeliverErrorResponse. But changing it causes
// ServiceWorkerURLRequestJobTest.DeletedProviderHostBeforeFetchEvent to
@@ -960,6 +973,10 @@ void ServiceWorkerURLRequestJob::RequestBodyFileSizesResolved(bool success) {
delegate_->GetServiceWorkerVersion(&result);
if (!active_worker) {
RecordResult(result);
+ if (IsMainResourceLoad()) {
+ ReportDestination(ServiceWorkerMetrics::MainResourceRequestDestination::
+ kErrorNoActiveWorkerFromDelegate);
+ }
DeliverErrorResponse();
return;
}
@@ -981,6 +998,8 @@ void ServiceWorkerURLRequestJob::RequestBodyFileSizesResolved(bool success) {
}
DCHECK(!fetch_dispatcher_);
+ if (IsMainResourceLoad())
+ delegate_->WillDispatchFetchEventForMainResource();
fetch_dispatcher_ = std::make_unique<ServiceWorkerFetchDispatcher>(
std::move(resource_request), blob_uuid, blob_size, std::move(blob),
client_id_, base::WrapRefCounted(active_worker), request()->net_log(),
@@ -1006,4 +1025,10 @@ void ServiceWorkerURLRequestJob::OnNavigationPreloadResponse() {
nav_preload_metrics_->ReportNavigationPreloadFinished();
}
+void ServiceWorkerURLRequestJob::ReportDestination(
+ ServiceWorkerMetrics::MainResourceRequestDestination destination) {
+ DCHECK(IsMainResourceLoad());
+ delegate_->ReportDestination(destination);
+}
+
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_url_request_job.h b/chromium/content/browser/service_worker/service_worker_url_request_job.h
index 5c8f00e1ee7..ea2182bae3d 100644
--- a/chromium/content/browser/service_worker/service_worker_url_request_job.h
+++ b/chromium/content/browser/service_worker/service_worker_url_request_job.h
@@ -24,7 +24,6 @@
#include "content/browser/service_worker/service_worker_url_job_wrapper.h"
#include "content/common/content_export.h"
#include "content/common/service_worker/service_worker.mojom.h"
-#include "content/common/service_worker/service_worker_types.h"
#include "content/public/common/request_context_type.h"
#include "content/public/common/resource_type.h"
#include "mojo/public/cpp/system/data_pipe.h"
@@ -37,6 +36,7 @@
#include "services/network/public/mojom/request_context_frame_type.mojom.h"
#include "storage/common/blob_storage/blob_storage_constants.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_response.mojom.h"
#include "url/gurl.h"
namespace net {
@@ -148,6 +148,8 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob : public net::URLRequestJob {
base::WeakPtr<ServiceWorkerURLRequestJob> GetWeakPtr();
private:
+ using ResponseHeaderMap = base::flat_map<std::string, std::string>;
+
class FileSizeResolver;
class NavigationPreloadMetrics;
friend class service_worker_url_request_job_unittest::DelayHelper;
@@ -190,16 +192,15 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob : public net::URLRequestJob {
void DidDispatchFetchEvent(
blink::ServiceWorkerStatusCode status,
ServiceWorkerFetchDispatcher::FetchEventResult fetch_result,
- const ServiceWorkerResponse& response,
+ blink::mojom::FetchAPIResponsePtr response,
blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream,
- blink::mojom::BlobPtr body_as_blob,
scoped_refptr<ServiceWorkerVersion> version);
- void SetResponse(const ServiceWorkerResponse& response);
+ void SetResponse(blink::mojom::FetchAPIResponsePtr response);
// Populates |http_response_headers_|.
void CreateResponseHeader(int status_code,
const std::string& status_text,
- const ServiceWorkerHeaderMap& headers);
+ ResponseHeaderMap headers);
// Creates |http_response_info_| using |http_response_headers_| and calls
// NotifyHeadersComplete.
@@ -251,6 +252,9 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob : public net::URLRequestJob {
void MaybeReportNavigationPreloadMetrics();
+ void ReportDestination(
+ ServiceWorkerMetrics::MainResourceRequestDestination destination);
+
// Not owned.
Delegate* delegate_;
@@ -336,6 +340,9 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob : public net::URLRequestJob {
std::unique_ptr<FileSizeResolver> file_size_resolver_;
+ bool started_fetch_dispatch_ = false;
+ bool reported_destination_ = false;
+
base::WeakPtrFactory<ServiceWorkerURLRequestJob> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerURLRequestJob);
diff --git a/chromium/content/browser/service_worker/service_worker_url_request_job_unittest.cc b/chromium/content/browser/service_worker/service_worker_url_request_job_unittest.cc
index ce237a44d28..fef3544e4ba 100644
--- a/chromium/content/browser/service_worker/service_worker_url_request_job_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_url_request_job_unittest.cc
@@ -15,6 +15,7 @@
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
@@ -30,7 +31,6 @@
#include "content/browser/service_worker/service_worker_response_info.h"
#include "content/browser/service_worker/service_worker_test_utils.h"
#include "content/browser/service_worker/service_worker_version.h"
-#include "content/common/service_worker/service_worker_messages.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/common/service_worker/service_worker_utils.h"
#include "content/public/browser/blob_handle.h"
@@ -60,6 +60,7 @@
#include "storage/browser/blob/blob_url_request_job_factory.h"
#include "storage/common/blob_storage/blob_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
#include "third_party/blink/public/mojom/service_worker/service_worker.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom.h"
@@ -148,14 +149,22 @@ std::unique_ptr<storage::BlobProtocolHandler> CreateMockBlobProtocolHandler(
return std::make_unique<storage::BlobProtocolHandler>(blob_storage_context);
}
-std::unique_ptr<ServiceWorkerHeaderMap> MakeHeaders() {
- auto headers = std::make_unique<ServiceWorkerHeaderMap>();
- (*headers)["Pineapple"] = "Pen";
- (*headers)["Foo"] = "Bar";
- (*headers)["Set-Cookie"] = "CookieCookieCookie";
+base::flat_map<std::string, std::string> MakeHeaders() {
+ base::flat_map<std::string, std::string> headers;
+ headers["Pineapple"] = "Pen";
+ headers["Foo"] = "Bar";
+ headers["Set-Cookie"] = "CookieCookieCookie";
return headers;
}
+blink::mojom::FetchAPIResponsePtr MakeOkResponse() {
+ auto response = blink::mojom::FetchAPIResponse::New();
+ response->status_code = 200;
+ response->status_text = "OK";
+ response->response_type = network::mojom::FetchResponseType::kDefault;
+ return response;
+}
+
void SaveStatusCallback(blink::ServiceWorkerStatusCode* out_status,
blink::ServiceWorkerStatusCode status) {
*out_status = status;
@@ -195,6 +204,10 @@ class ServiceWorkerURLRequestJobTest
~ServiceWorkerURLRequestJobTest() override {}
void SetUp() override {
+ // ServiceWorkerURLRequestJob is a non-S13nServiceWorker specific class
+ // and we don't use it when S13nServiceWorker is enabled.
+ scoped_feature_list_.InitAndDisableFeature(
+ blink::features::kServiceWorkerServicification);
browser_context_.reset(new TestBrowserContext);
InitializeResourceContext(browser_context_.get());
}
@@ -248,8 +261,8 @@ class ServiceWorkerURLRequestJobTest
provider_host_ = provider_host->AsWeakPtr();
provider_host->SetDocumentUrl(GURL("https://example.com/"));
registration_->SetActiveVersion(version_);
- provider_host->AssociateRegistration(registration_.get(),
- false /* notify_controllerchange */);
+ provider_host->SetControllerRegistration(
+ registration_, false /* notify_controllerchange */);
// Set up scaffolding for handling URL requests.
ChromeBlobStorageContext* chrome_blob_storage_context =
@@ -383,11 +396,11 @@ class ServiceWorkerURLRequestJobTest
*result = ServiceWorkerMetrics::REQUEST_JOB_ERROR_NO_PROVIDER_HOST;
return nullptr;
}
- if (!provider_host_->active_version()) {
+ if (!provider_host_->controller()) {
*result = ServiceWorkerMetrics::REQUEST_JOB_ERROR_NO_ACTIVE_VERSION;
return nullptr;
}
- return provider_host_->active_version();
+ return provider_host_->controller();
}
bool RequestStillValid(
@@ -406,6 +419,10 @@ class ServiceWorkerURLRequestJobTest
}
// ---------------------------------------------------------------------------
+ // |scoped_feature_list_| must be before |thread_bundle_|.
+ // See comments in ServiceWorkerProviderHostTest.
+ base::test::ScopedFeatureList scoped_feature_list_;
+
TestBrowserThreadBundle thread_bundle_;
base::SimpleTestTickClock tick_clock_;
@@ -473,18 +490,7 @@ class DelayHelper : public EmbeddedWorkerTestHelper {
}
void Respond() {
- response_callback_->OnResponse(
- ServiceWorkerResponse(
- std::make_unique<std::vector<GURL>>(), 200, "OK",
- network::mojom::FetchResponseType::kDefault,
- std::make_unique<ServiceWorkerHeaderMap>(), std::string(), 0,
- nullptr /* blob */,
- blink::mojom::ServiceWorkerResponseError::kUnknown, base::Time(),
- false /* response_is_in_cache_storage */,
- std::string() /* response_cache_storage_cache_name */,
- std::make_unique<
- ServiceWorkerHeaderList>() /* cors_exposed_header_names */),
- base::Time::Now());
+ response_callback_->OnResponse(MakeOkResponse(), base::Time::Now());
std::move(finish_callback_)
.Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
base::Time::Now());
@@ -519,7 +525,7 @@ class DelayHelper : public EmbeddedWorkerTestHelper {
int embedded_worker_id,
const network::ResourceRequest& /* request */,
blink::mojom::FetchEventPreloadHandlePtr preload_handle,
- mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
+ blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
mojom::ServiceWorker::DispatchFetchEventCallback finish_callback)
override {
embedded_worker_id_ = embedded_worker_id;
@@ -540,7 +546,7 @@ class DelayHelper : public EmbeddedWorkerTestHelper {
mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info_;
blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info_;
int embedded_worker_id_ = 0;
- mojom::ServiceWorkerFetchResponseCallbackPtr response_callback_;
+ blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback_;
blink::mojom::FetchEventPreloadHandlePtr preload_handle_;
mojom::ServiceWorker::DispatchFetchEventCallback finish_callback_;
ServiceWorkerURLRequestJobTest* test_;
@@ -697,22 +703,11 @@ class ProviderDeleteHelper : public EmbeddedWorkerTestHelper {
int /* embedded_worker_id */,
const network::ResourceRequest& /* request */,
blink::mojom::FetchEventPreloadHandlePtr /* preload_handle */,
- mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
+ blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
mojom::ServiceWorker::DispatchFetchEventCallback finish_callback)
override {
context()->RemoveProviderHost(mock_render_process_id(), kProviderID);
- response_callback->OnResponse(
- ServiceWorkerResponse(
- std::make_unique<std::vector<GURL>>(), 200, "OK",
- network::mojom::FetchResponseType::kDefault,
- std::make_unique<ServiceWorkerHeaderMap>(), std::string(), 0,
- nullptr /* blob */,
- blink::mojom::ServiceWorkerResponseError::kUnknown, base::Time(),
- false /* response_is_in_cache_storage */,
- std::string() /* response_cache_storage_cache_name */,
- std::make_unique<
- ServiceWorkerHeaderList>() /* cors_exposed_header_names */),
- base::Time::Now());
+ response_callback->OnResponse(MakeOkResponse(), base::Time::Now());
std::move(finish_callback)
.Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
base::Time::Now());
@@ -787,20 +782,19 @@ class BlobResponder : public EmbeddedWorkerTestHelper {
int /* embedded_worker_id */,
const network::ResourceRequest& /* request */,
blink::mojom::FetchEventPreloadHandlePtr /* preload_handle */,
- mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
+ blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
mojom::ServiceWorker::DispatchFetchEventCallback finish_callback)
override {
- response_callback->OnResponse(
- ServiceWorkerResponse(
- std::make_unique<std::vector<GURL>>(), 200, "OK",
- network::mojom::FetchResponseType::kDefault, MakeHeaders(),
- blob_uuid_, blob_size_, nullptr /* blob */,
- blink::mojom::ServiceWorkerResponseError::kUnknown, base::Time(),
- false /* response_is_in_cache_storage */,
- std::string() /* response_cache_storage_cache_name */,
- std::make_unique<
- ServiceWorkerHeaderList>() /* cors_exposed_header_names */),
- base::Time::Now());
+ blink::mojom::FetchAPIResponsePtr response = MakeOkResponse();
+ response->headers = MakeHeaders();
+ response->blob = blink::mojom::SerializedBlob::New();
+ response->blob->uuid = blob_uuid_;
+ response->blob->size = blob_size_;
+ // As |response->blob->blob| must have a non-null value to be passed via
+ // Mojo, we give it a dummy value.
+ auto dummy_request = mojo::MakeRequest(&response->blob->blob);
+
+ response_callback->OnResponse(std::move(response), base::Time::Now());
std::move(finish_callback)
.Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
base::Time::Now());
@@ -888,21 +882,14 @@ class StreamResponder : public EmbeddedWorkerTestHelper {
int /* embedded_worker_id */,
const network::ResourceRequest& /* request */,
blink::mojom::FetchEventPreloadHandlePtr /* preload_handle */,
- mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
+ blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
mojom::ServiceWorker::DispatchFetchEventCallback finish_callback)
override {
ASSERT_FALSE(stream_handle_.is_null());
+ blink::mojom::FetchAPIResponsePtr response = MakeOkResponse();
+ response->headers = MakeHeaders();
response_callback->OnResponseStream(
- ServiceWorkerResponse(
- std::make_unique<std::vector<GURL>>(), 200, "OK",
- network::mojom::FetchResponseType::kDefault, MakeHeaders(), "", 0,
- nullptr /* blob */,
- blink::mojom::ServiceWorkerResponseError::kUnknown, base::Time(),
- false /* response_is_in_cache_storage */,
- std::string() /* response_cache_storage_cache_name */,
- std::make_unique<
- ServiceWorkerHeaderList>() /* cors_exposed_header_names */),
- std::move(stream_handle_), base::Time::Now());
+ std::move(response), std::move(stream_handle_), base::Time::Now());
std::move(finish_callback)
.Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
base::Time::Now());
@@ -1278,7 +1265,8 @@ class FailFetchHelper : public EmbeddedWorkerTestHelper {
int embedded_worker_id,
const network::ResourceRequest& /* request */,
blink::mojom::FetchEventPreloadHandlePtr /* preload_handle */,
- mojom::ServiceWorkerFetchResponseCallbackPtr /* response_callback */,
+ blink::mojom::
+ ServiceWorkerFetchResponseCallbackPtr /* response_callback */,
mojom::ServiceWorker::DispatchFetchEventCallback finish_callback)
override {
SimulateWorkerStopped(embedded_worker_id);
@@ -1371,22 +1359,11 @@ class EarlyResponseHelper : public EmbeddedWorkerTestHelper {
int /* embedded_worker_id */,
const network::ResourceRequest& /* request */,
blink::mojom::FetchEventPreloadHandlePtr /* preload_handle */,
- mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
+ blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
mojom::ServiceWorker::DispatchFetchEventCallback finish_callback)
override {
finish_callback_ = std::move(finish_callback);
- response_callback->OnResponse(
- ServiceWorkerResponse(
- std::make_unique<std::vector<GURL>>(), 200, "OK",
- network::mojom::FetchResponseType::kDefault,
- std::make_unique<ServiceWorkerHeaderMap>(), std::string(), 0,
- nullptr /* blob */,
- blink::mojom::ServiceWorkerResponseError::kUnknown, base::Time(),
- false /* response_is_in_cache_storage */,
- std::string() /* response_cache_storage_cache_name */,
- std::make_unique<
- ServiceWorkerHeaderList>() /* cors_exposed_header_names */),
- base::Time::Now());
+ response_callback->OnResponse(MakeOkResponse(), base::Time::Now());
}
private:
diff --git a/chromium/content/browser/service_worker/service_worker_version.cc b/chromium/content/browser/service_worker/service_worker_version.cc
index 8d58920080e..5d8213494b9 100644
--- a/chromium/content/browser/service_worker/service_worker_version.cc
+++ b/chromium/content/browser/service_worker/service_worker_version.cc
@@ -31,7 +31,6 @@
#include "content/browser/service_worker/service_worker_installed_scripts_sender.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/common/service_worker/embedded_worker.mojom.h"
-#include "content/common/service_worker/service_worker_messages.h"
#include "content/common/service_worker/service_worker_utils.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
@@ -113,25 +112,6 @@ void ClearTick(base::TimeTicks* time) {
*time = base::TimeTicks();
}
-std::string VersionStatusToString(ServiceWorkerVersion::Status status) {
- switch (status) {
- case ServiceWorkerVersion::NEW:
- return "new";
- case ServiceWorkerVersion::INSTALLING:
- return "installing";
- case ServiceWorkerVersion::INSTALLED:
- return "installed";
- case ServiceWorkerVersion::ACTIVATING:
- return "activating";
- case ServiceWorkerVersion::ACTIVATED:
- return "activated";
- case ServiceWorkerVersion::REDUNDANT:
- return "redundant";
- }
- NOTREACHED() << status;
- return std::string();
-}
-
const int kInvalidTraceId = -1;
int NextTraceId() {
@@ -499,8 +479,8 @@ void ServiceWorkerVersion::ScheduleUpdate() {
// and soon no one might hold a reference to us.
context_->ProtectVersion(base::WrapRefCounted(this));
update_timer_.Start(FROM_HERE, kUpdateDelay,
- base::Bind(&ServiceWorkerVersion::StartUpdate,
- weak_factory_.GetWeakPtr()));
+ base::BindOnce(&ServiceWorkerVersion::StartUpdate,
+ weak_factory_.GetWeakPtr()));
}
void ServiceWorkerVersion::StartUpdate() {
@@ -535,10 +515,36 @@ int ServiceWorkerVersion::StartRequestWithCustomTimeout(
event_type == ServiceWorkerMetrics::EventType::ACTIVATE ||
event_type == ServiceWorkerMetrics::EventType::MESSAGE ||
event_type == ServiceWorkerMetrics::EventType::EXTERNAL_REQUEST ||
+ event_type == ServiceWorkerMetrics::EventType::LONG_RUNNING_MESSAGE ||
status() == ACTIVATED)
<< "Event of type " << static_cast<int>(event_type)
<< " can only be dispatched to an active worker: " << status();
+ // |context_| is needed for some bookkeeping. If there's no context, the
+ // request will be aborted soon, so don't bother aborting the request directly
+ // here, and just skip this bookkeeping.
+ if (context_) {
+ if (event_type == ServiceWorkerMetrics::EventType::LONG_RUNNING_MESSAGE) {
+ context_->embedded_worker_registry()->AbortLifetimeTracking(
+ embedded_worker_->embedded_worker_id());
+ }
+
+ if (event_type != ServiceWorkerMetrics::EventType::INSTALL &&
+ event_type != ServiceWorkerMetrics::EventType::ACTIVATE &&
+ event_type != ServiceWorkerMetrics::EventType::MESSAGE) {
+ // Reset the self-update delay iff this is not an event that can triggered
+ // by a service worker itself. Otherwise, service workers can use update()
+ // to keep running forever via install and activate events, or
+ // postMessage() between themselves to reset the delay via message event.
+ // postMessage() resets the delay in ServiceWorkerObjectHost, iff it
+ // didn't come from a service worker.
+ ServiceWorkerRegistration* registration =
+ context_->GetLiveRegistration(registration_id_);
+ DCHECK(registration) << "running workers should have a live registration";
+ registration->set_self_update_delay(base::TimeDelta());
+ }
+ }
+
auto request = std::make_unique<InflightRequest>(
std::move(error_callback), clock_->Now(), tick_clock_->NowTicks(),
event_type);
@@ -670,6 +676,12 @@ void ServiceWorkerVersion::AddControllee(
RestartTick(&idle_time_);
ClearTick(&no_controllees_time_);
+ ServiceWorkerRegistration* registration =
+ context_->GetLiveRegistration(registration_id_);
+ if (registration) {
+ registration->set_self_update_delay(base::TimeDelta());
+ }
+
// Notify observers asynchronously for consistency with RemoveControllee.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
@@ -735,6 +747,10 @@ void ServiceWorkerVersion::SetStartWorkerStatusCode(
}
void ServiceWorkerVersion::Doom() {
+ // Protect |this| because NotifyControllerLost() and Stop() callees
+ // may drop references to |this|.
+ scoped_refptr<ServiceWorkerVersion> protect(this);
+
// Tell controllees that this version is dead. Each controllee will call
// ServiceWorkerVersion::RemoveControllee(), so be careful with iterators.
auto iter = controllee_map_.begin();
@@ -1211,7 +1227,7 @@ void ServiceWorkerVersion::NavigateClient(const std::string& client_uuid,
binding_.Close();
return;
}
- if (provider_host->active_version() != this) {
+ if (provider_host->controller() != this) {
std::move(callback).Run(
false /* success */, nullptr /* client */,
std::string(
@@ -1345,6 +1361,7 @@ void ServiceWorkerVersion::CountFeature(blink::mojom::WebFeature feature) {
provider_host_by_uuid.second->CountFeature(feature);
}
+// static
bool ServiceWorkerVersion::IsInstalled(ServiceWorkerVersion::Status status) {
switch (status) {
case ServiceWorkerVersion::NEW:
@@ -1360,6 +1377,27 @@ bool ServiceWorkerVersion::IsInstalled(ServiceWorkerVersion::Status status) {
return false;
}
+// static
+std::string ServiceWorkerVersion::VersionStatusToString(
+ ServiceWorkerVersion::Status status) {
+ switch (status) {
+ case ServiceWorkerVersion::NEW:
+ return "new";
+ case ServiceWorkerVersion::INSTALLING:
+ return "installing";
+ case ServiceWorkerVersion::INSTALLED:
+ return "installed";
+ case ServiceWorkerVersion::ACTIVATING:
+ return "activating";
+ case ServiceWorkerVersion::ACTIVATED:
+ return "activated";
+ case ServiceWorkerVersion::REDUNDANT:
+ return "redundant";
+ }
+ NOTREACHED() << status;
+ return std::string();
+}
+
void ServiceWorkerVersion::IncrementPendingUpdateHintCount() {
DCHECK(blink::ServiceWorkerUtils::IsServicificationEnabled());
pending_update_hint_count_++;
diff --git a/chromium/content/browser/service_worker/service_worker_version.h b/chromium/content/browser/service_worker/service_worker_version.h
index 8549a667e3c..166f9093530 100644
--- a/chromium/content/browser/service_worker/service_worker_version.h
+++ b/chromium/content/browser/service_worker/service_worker_version.h
@@ -94,6 +94,7 @@ FORWARD_DECLARE_TEST(ServiceWorkerVersionTest, StaleUpdate_FreshWorker);
FORWARD_DECLARE_TEST(ServiceWorkerVersionTest, StaleUpdate_NonActiveWorker);
FORWARD_DECLARE_TEST(ServiceWorkerVersionTest, StaleUpdate_RunningWorker);
FORWARD_DECLARE_TEST(ServiceWorkerVersionTest, StaleUpdate_StartWorker);
+FORWARD_DECLARE_TEST(ServiceWorkerVersionTest, StartRequestWithNullContext);
} // namespace service_worker_version_unittest
namespace service_worker_registration_unittest {
@@ -490,6 +491,7 @@ class CONTENT_EXPORT ServiceWorkerVersion
}
static bool IsInstalled(ServiceWorkerVersion::Status status);
+ static std::string VersionStatusToString(ServiceWorkerVersion::Status status);
// For scheduling Soft Update after main resource requests. We schedule
// a Soft Update to happen "soon" after each main resource request, attempting
@@ -551,6 +553,9 @@ class CONTENT_EXPORT ServiceWorkerVersion
service_worker_version_unittest::ServiceWorkerVersionTest,
StaleUpdate_DoNotDeferTimer);
FRIEND_TEST_ALL_PREFIXES(
+ service_worker_version_unittest::ServiceWorkerVersionTest,
+ StartRequestWithNullContext);
+ FRIEND_TEST_ALL_PREFIXES(
service_worker_version_unittest::ServiceWorkerRequestTimeoutTest,
RequestTimeout);
FRIEND_TEST_ALL_PREFIXES(
@@ -840,7 +845,7 @@ class CONTENT_EXPORT ServiceWorkerVersion
std::map<std::string, ServiceWorkerProviderHost*> controllee_map_;
// Will be null while shutting down.
base::WeakPtr<ServiceWorkerContextCore> context_;
- base::ObserverList<Observer> observers_;
+ base::ObserverList<Observer>::Unchecked observers_;
ServiceWorkerScriptCacheMap script_cache_map_;
base::OneShotTimer update_timer_;
diff --git a/chromium/content/browser/service_worker/service_worker_version_unittest.cc b/chromium/content/browser/service_worker/service_worker_version_unittest.cc
index 2b3f97091de..fddd9d4ccef 100644
--- a/chromium/content/browser/service_worker/service_worker_version_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_version_unittest.cc
@@ -559,7 +559,7 @@ TEST_F(ServiceWorkerVersionTest, Doom) {
true /* is_parent_frame_secure */, helper_->context()->AsWeakPtr(),
&remote_endpoint);
host->SetDocumentUrl(registration_->pattern());
- host->AssociateRegistration(registration_.get(), false);
+ host->SetControllerRegistration(registration_, false);
EXPECT_TRUE(version_->HasControllee());
EXPECT_TRUE(host->controller());
@@ -773,6 +773,51 @@ TEST_F(ServiceWorkerVersionTest, StaleUpdate_DoNotDeferTimer) {
EXPECT_EQ(run_time, version_->update_timer_.desired_run_time());
}
+TEST_F(ServiceWorkerVersionTest, StartRequestWithNullContext) {
+ StartWorker(version_.get(), ServiceWorkerMetrics::EventType::UNKNOWN);
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ version_->context_ = nullptr;
+ version_->StartRequest(ServiceWorkerMetrics::EventType::PUSH,
+ base::DoNothing());
+ // Test passes if it doesn't crash.
+}
+
+// Tests the delay mechanism for self-updating service workers, to prevent
+// them from running forever (see https://crbug.com/805496).
+TEST_F(ServiceWorkerVersionTest, ResetUpdateDelay) {
+ const base::TimeDelta kMinute = base::TimeDelta::FromMinutes(1);
+ const base::TimeDelta kNoDelay = base::TimeDelta();
+
+ // Initialize the delay.
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ registration_->SetActiveVersion(version_);
+ registration_->set_self_update_delay(kMinute);
+
+ // Events that can be triggered by a worker should not reset the delay.
+ // See the comment in ServiceWorkerVersion::StartRequestWithCustomTimeout.
+ SimulateDispatchEvent(ServiceWorkerMetrics::EventType::INSTALL);
+ SimulateDispatchEvent(ServiceWorkerMetrics::EventType::ACTIVATE);
+ SimulateDispatchEvent(ServiceWorkerMetrics::EventType::MESSAGE);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(kMinute, registration_->self_update_delay());
+
+ // Events that can only be triggered externally reset the delay.
+ // Repeat the test for several such events.
+ SimulateDispatchEvent(ServiceWorkerMetrics::EventType::SYNC);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(kNoDelay, registration_->self_update_delay());
+
+ registration_->set_self_update_delay(kMinute);
+ SimulateDispatchEvent(ServiceWorkerMetrics::EventType::NOTIFICATION_CLICK);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(kNoDelay, registration_->self_update_delay());
+
+ registration_->set_self_update_delay(kMinute);
+ SimulateDispatchEvent(ServiceWorkerMetrics::EventType::PUSH);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(kNoDelay, registration_->self_update_delay());
+}
+
TEST_F(ServiceWorkerVersionTest, UpdateCachedMetadata) {
CachedMetadataUpdateListener listener;
version_->AddObserver(&listener);
diff --git a/chromium/content/browser/service_worker/service_worker_write_to_cache_job.cc b/chromium/content/browser/service_worker/service_worker_write_to_cache_job.cc
index 25c0d8f11e2..33975df1026 100644
--- a/chromium/content/browser/service_worker/service_worker_write_to_cache_job.cc
+++ b/chromium/content/browser/service_worker/service_worker_write_to_cache_job.cc
@@ -353,10 +353,12 @@ void ServiceWorkerWriteToCacheJob::OnResponseStarted(net::URLRequest* request,
version_->embedded_worker()->OnNetworkAccessedForScriptLoad();
}
- http_info_.reset(new net::HttpResponseInfo(net_request_->response_info()));
+ http_info_ =
+ std::make_unique<net::HttpResponseInfo>(net_request_->response_info());
scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
- new HttpResponseInfoIOBuffer(
- new net::HttpResponseInfo(net_request_->response_info()));
+ base::MakeRefCounted<HttpResponseInfoIOBuffer>(
+ std::make_unique<net::HttpResponseInfo>(
+ net_request_->response_info()));
net::Error error = cache_writer_->MaybeWriteHeaders(
info_buffer.get(),
base::BindOnce(&ServiceWorkerWriteToCacheJob::OnWriteHeadersComplete,
diff --git a/chromium/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc b/chromium/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
index 516c5b96b1a..bf253b43748 100644
--- a/chromium/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
@@ -38,8 +38,12 @@
#include "services/network/public/mojom/request_context_frame_type.mojom.h"
#include "storage/browser/blob/blob_storage_context.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/service_worker/service_worker_utils.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
+// Note for S13nServiceWorker: All tests are skipped as we don't use
+// ServiceWorkerWriteToCacheJob when S13nServiceWorker is enabled.
+
namespace content {
namespace service_worker_write_to_cache_job_unittest {
@@ -446,6 +450,9 @@ class ServiceWorkerWriteToCacheJobTest : public testing::Test {
};
TEST_F(ServiceWorkerWriteToCacheJobTest, Normal) {
+ if (blink::ServiceWorkerUtils::IsServicificationEnabled())
+ return;
+
mock_protocol_handler_->SetCreateJobCallback(
base::Bind(&CreateNormalURLRequestJob));
request_->Start();
@@ -456,6 +463,9 @@ TEST_F(ServiceWorkerWriteToCacheJobTest, Normal) {
}
TEST_F(ServiceWorkerWriteToCacheJobTest, InvalidMimeType) {
+ if (blink::ServiceWorkerUtils::IsServicificationEnabled())
+ return;
+
mock_protocol_handler_->SetCreateJobCallback(
base::Bind(&CreateInvalidMimeTypeJob));
request_->Start();
@@ -467,6 +477,9 @@ TEST_F(ServiceWorkerWriteToCacheJobTest, InvalidMimeType) {
}
TEST_F(ServiceWorkerWriteToCacheJobTest, SSLCertificateError) {
+ if (blink::ServiceWorkerUtils::IsServicificationEnabled())
+ return;
+
mock_protocol_handler_->SetCreateJobCallback(
base::Bind(&CreateSSLCertificateErrorJob));
request_->Start();
@@ -488,6 +501,9 @@ class ServiceWorkerWriteToCacheLocalhostTest
TEST_F(ServiceWorkerWriteToCacheLocalhostTest,
SSLCertificateError_AllowInsecureLocalhost) {
+ if (blink::ServiceWorkerUtils::IsServicificationEnabled())
+ return;
+
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kAllowInsecureLocalhost);
@@ -502,6 +518,9 @@ TEST_F(ServiceWorkerWriteToCacheLocalhostTest,
}
TEST_F(ServiceWorkerWriteToCacheLocalhostTest, SSLCertificateError) {
+ if (blink::ServiceWorkerUtils::IsServicificationEnabled())
+ return;
+
mock_protocol_handler_->SetCreateJobCallback(
base::Bind(&CreateSSLCertificateErrorJob));
request_->Start();
@@ -514,6 +533,9 @@ TEST_F(ServiceWorkerWriteToCacheLocalhostTest, SSLCertificateError) {
TEST_F(ServiceWorkerWriteToCacheLocalhostTest,
CertStatusError_AllowInsecureLocalhost) {
+ if (blink::ServiceWorkerUtils::IsServicificationEnabled())
+ return;
+
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kAllowInsecureLocalhost);
@@ -528,6 +550,9 @@ TEST_F(ServiceWorkerWriteToCacheLocalhostTest,
}
TEST_F(ServiceWorkerWriteToCacheLocalhostTest, CertStatusError) {
+ if (blink::ServiceWorkerUtils::IsServicificationEnabled())
+ return;
+
mock_protocol_handler_->SetCreateJobCallback(
base::Bind(&CreateCertStatusErrorJob));
request_->Start();
@@ -539,6 +564,9 @@ TEST_F(ServiceWorkerWriteToCacheLocalhostTest, CertStatusError) {
}
TEST_F(ServiceWorkerWriteToCacheJobTest, CertStatusError) {
+ if (blink::ServiceWorkerUtils::IsServicificationEnabled())
+ return;
+
mock_protocol_handler_->SetCreateJobCallback(
base::Bind(&CreateCertStatusErrorJob));
request_->Start();
@@ -550,6 +578,9 @@ TEST_F(ServiceWorkerWriteToCacheJobTest, CertStatusError) {
}
TEST_F(ServiceWorkerWriteToCacheJobTest, Update_SameScript) {
+ if (blink::ServiceWorkerUtils::IsServicificationEnabled())
+ return;
+
std::string response = GenerateLongResponse();
CreateIncumbent(response);
scoped_refptr<ServiceWorkerVersion> version = UpdateScript(response);
@@ -557,6 +588,9 @@ TEST_F(ServiceWorkerWriteToCacheJobTest, Update_SameScript) {
}
TEST_F(ServiceWorkerWriteToCacheJobTest, Update_SameSizeScript) {
+ if (blink::ServiceWorkerUtils::IsServicificationEnabled())
+ return;
+
std::string response = GenerateLongResponse();
CreateIncumbent(response);
@@ -592,6 +626,9 @@ TEST_F(ServiceWorkerWriteToCacheJobTest, Update_SameSizeScript) {
}
TEST_F(ServiceWorkerWriteToCacheJobTest, Update_TruncatedScript) {
+ if (blink::ServiceWorkerUtils::IsServicificationEnabled())
+ return;
+
std::string response = GenerateLongResponse();
CreateIncumbent(response);
@@ -621,6 +658,9 @@ TEST_F(ServiceWorkerWriteToCacheJobTest, Update_TruncatedScript) {
}
TEST_F(ServiceWorkerWriteToCacheJobTest, Update_ElongatedScript) {
+ if (blink::ServiceWorkerUtils::IsServicificationEnabled())
+ return;
+
std::string original_response = GenerateLongResponse();
CreateIncumbent(original_response);
@@ -644,6 +684,9 @@ TEST_F(ServiceWorkerWriteToCacheJobTest, Update_ElongatedScript) {
}
TEST_F(ServiceWorkerWriteToCacheJobTest, Update_EmptyScript) {
+ if (blink::ServiceWorkerUtils::IsServicificationEnabled())
+ return;
+
// Create empty incumbent.
CreateIncumbent(std::string());
@@ -664,6 +707,9 @@ TEST_F(ServiceWorkerWriteToCacheJobTest, Update_EmptyScript) {
}
TEST_F(ServiceWorkerWriteToCacheJobTest, Error) {
+ if (blink::ServiceWorkerUtils::IsServicificationEnabled())
+ return;
+
mock_protocol_handler_->SetCreateJobCallback(
base::Bind(&CreateFailedURLRequestJob));
request_->Start();
@@ -675,6 +721,9 @@ TEST_F(ServiceWorkerWriteToCacheJobTest, Error) {
}
TEST_F(ServiceWorkerWriteToCacheJobTest, FailedWriteHeadersToCache) {
+ if (blink::ServiceWorkerUtils::IsServicificationEnabled())
+ return;
+
mock_protocol_handler_->SetCreateJobCallback(
base::Bind(&CreateNormalURLRequestJob));
DisableCache();
diff --git a/chromium/content/browser/session_history_browsertest.cc b/chromium/content/browser/session_history_browsertest.cc
index d07ea196aa2..561ac719fc5 100644
--- a/chromium/content/browser/session_history_browsertest.cc
+++ b/chromium/content/browser/session_history_browsertest.cc
@@ -487,23 +487,15 @@ IN_PROC_BROWSER_TEST_F(SessionHistoryScrollAnchorTest,
// http://code.google.com/p/chromium/issues/detail?id=56267
IN_PROC_BROWSER_TEST_F(SessionHistoryTest, HistoryLength) {
- int length;
- ASSERT_TRUE(ExecuteScriptAndExtractInt(
- shell(), "domAutomationController.send(history.length)", &length));
- EXPECT_EQ(1, length);
-
+ EXPECT_EQ(1, EvalJs(shell(), "history.length"));
NavigateToURL(shell(), GetURL("title1.html"));
- ASSERT_TRUE(ExecuteScriptAndExtractInt(
- shell(), "domAutomationController.send(history.length)", &length));
- EXPECT_EQ(2, length);
+ EXPECT_EQ(2, EvalJs(shell(), "history.length"));
// Now test that history.length is updated when the navigation is committed.
NavigateToURL(shell(), GetURL("record_length.html"));
- ASSERT_TRUE(ExecuteScriptAndExtractInt(
- shell(), "domAutomationController.send(history.length)", &length));
- EXPECT_EQ(3, length);
+ EXPECT_EQ(3, EvalJs(shell(), "history.length"));
GoBack();
GoBack();
@@ -511,9 +503,7 @@ IN_PROC_BROWSER_TEST_F(SessionHistoryTest, HistoryLength) {
// Ensure history.length is properly truncated.
NavigateToURL(shell(), GetURL("title2.html"));
- ASSERT_TRUE(ExecuteScriptAndExtractInt(
- shell(), "domAutomationController.send(history.length)", &length));
- EXPECT_EQ(2, length);
+ EXPECT_EQ(2, EvalJs(shell(), "history.length"));
}
// Test that verifies that a cross-process transfer doesn't lose session
@@ -537,8 +527,7 @@ IN_PROC_BROWSER_TEST_F(SessionHistoryTest, GoBackToCrossSitePostWithRedirect) {
// Submit the form.
TestNavigationObserver form_post_observer(shell()->web_contents(), 1);
- EXPECT_TRUE(
- ExecuteScript(shell(), "document.getElementById('text-form').submit();"));
+ EXPECT_TRUE(ExecJs(shell(), "document.getElementById('text-form').submit()"));
form_post_observer.Wait();
// Verify that we arrived at the expected, redirected location.
@@ -547,13 +536,9 @@ IN_PROC_BROWSER_TEST_F(SessionHistoryTest, GoBackToCrossSitePostWithRedirect) {
// Verify that POST body got preserved by 307 redirect. This expectation
// comes from: https://tools.ietf.org/html/rfc7231#section-6.4.7
- std::string body;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- shell(),
- "window.domAutomationController.send("
- "document.getElementsByTagName('pre')[0].innerText);",
- &body));
- EXPECT_EQ("text=value\n", body);
+ EXPECT_EQ(
+ "text=value\n",
+ EvalJs(shell(), "document.getElementsByTagName('pre')[0].innerText"));
// Navigate to a page from yet another site.
EXPECT_TRUE(NavigateToURL(shell(), page_to_go_back_from));
@@ -568,13 +553,9 @@ IN_PROC_BROWSER_TEST_F(SessionHistoryTest, GoBackToCrossSitePostWithRedirect) {
shell()->web_contents()->GetLastCommittedURL());
// Again verify that POST body got preserved by 307 redirect.
- std::string body_after_back_navigation;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- shell(),
- "window.domAutomationController.send("
- "document.getElementsByTagName('pre')[0].innerText);",
- &body_after_back_navigation));
- EXPECT_EQ("text=value\n", body_after_back_navigation);
+ EXPECT_EQ(
+ "text=value\n",
+ EvalJs(shell(), "document.getElementsByTagName('pre')[0].innerText"));
}
} // namespace content
diff --git a/chromium/content/browser/shared_worker/mock_shared_worker.cc b/chromium/content/browser/shared_worker/mock_shared_worker.cc
index 829d18dce64..b23879ffa4d 100644
--- a/chromium/content/browser/shared_worker/mock_shared_worker.cc
+++ b/chromium/content/browser/shared_worker/mock_shared_worker.cc
@@ -99,9 +99,11 @@ void MockSharedWorkerFactory::CreateSharedWorker(
bool pause_on_start,
const base::UnguessableToken& devtools_worker_token,
const RendererPreferences& renderer_preferences,
+ mojom::RendererPreferenceWatcherRequest preference_watcher_request,
blink::mojom::WorkerContentSettingsProxyPtr content_settings,
mojom::ServiceWorkerProviderInfoForSharedWorkerPtr
service_worker_provider_info,
+ int appcache_host_id,
network::mojom::URLLoaderFactoryAssociatedPtrInfo
script_loader_factory_ptr_info,
std::unique_ptr<URLLoaderFactoryBundleInfo> subresource_loaders,
diff --git a/chromium/content/browser/shared_worker/mock_shared_worker.h b/chromium/content/browser/shared_worker/mock_shared_worker.h
index 7d99113c488..954fbad4b54 100644
--- a/chromium/content/browser/shared_worker/mock_shared_worker.h
+++ b/chromium/content/browser/shared_worker/mock_shared_worker.h
@@ -68,9 +68,11 @@ class MockSharedWorkerFactory : public mojom::SharedWorkerFactory {
bool pause_on_start,
const base::UnguessableToken& devtools_worker_token,
const RendererPreferences& renderer_preferences,
+ mojom::RendererPreferenceWatcherRequest preference_watcher_request,
blink::mojom::WorkerContentSettingsProxyPtr content_settings,
mojom::ServiceWorkerProviderInfoForSharedWorkerPtr
service_worker_provider_info,
+ int appcache_host_id,
network::mojom::URLLoaderFactoryAssociatedPtrInfo
script_loader_factory_ptr_info,
std::unique_ptr<URLLoaderFactoryBundleInfo> subresource_loaders,
diff --git a/chromium/content/browser/shared_worker/shared_worker_host.cc b/chromium/content/browser/shared_worker/shared_worker_host.cc
index 407310cc763..a2f6eea00a8 100644
--- a/chromium/content/browser/shared_worker/shared_worker_host.cc
+++ b/chromium/content/browser/shared_worker/shared_worker_host.cc
@@ -9,6 +9,7 @@
#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "base/unguessable_token.h"
+#include "content/browser/appcache/appcache_navigation_handle.h"
#include "content/browser/devtools/shared_worker_devtools_manager.h"
#include "content/browser/interface_provider_filtering.h"
#include "content/browser/renderer_interface_binders.h"
@@ -22,8 +23,10 @@
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/content_client.h"
+#include "content/public/common/renderer_preference_watcher.mojom.h"
#include "services/network/public/cpp/features.h"
#include "third_party/blink/public/common/message_port/message_port_channel.h"
+#include "third_party/blink/public/common/service_worker/service_worker_utils.h"
#include "third_party/blink/public/platform/web_feature.mojom.h"
#include "third_party/blink/public/web/worker_content_settings_proxy.mojom.h"
@@ -39,7 +42,7 @@ void AllowFileSystemOnIOThreadResponse(base::OnceCallback<void(bool)> callback,
void AllowFileSystemOnIOThread(const GURL& url,
ResourceContext* resource_context,
- std::vector<std::pair<int, int>> render_frames,
+ std::vector<GlobalFrameRoutingId> render_frames,
base::OnceCallback<void(bool)> callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
GetContentClient()->browser()->AllowWorkerFileSystem(
@@ -50,7 +53,7 @@ void AllowFileSystemOnIOThread(const GURL& url,
bool AllowIndexedDBOnIOThread(const GURL& url,
const base::string16& name,
ResourceContext* resource_context,
- std::vector<std::pair<int, int>> render_frames) {
+ std::vector<GlobalFrameRoutingId> render_frames) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
return GetContentClient()->browser()->AllowWorkerIndexedDB(
url, name, resource_context, render_frames);
@@ -125,8 +128,9 @@ void SharedWorkerHost::Start(
mojom::SharedWorkerFactoryPtr factory,
mojom::ServiceWorkerProviderInfoForSharedWorkerPtr
service_worker_provider_info,
- network::mojom::URLLoaderFactoryAssociatedPtrInfo script_loader_factory,
- std::unique_ptr<URLLoaderFactoryBundleInfo> factory_bundle) {
+ network::mojom::URLLoaderFactoryAssociatedPtrInfo
+ main_script_loader_factory,
+ std::unique_ptr<URLLoaderFactoryBundleInfo> subresource_loader_factories) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
AdvanceTo(Phase::kStarted);
@@ -146,6 +150,14 @@ void SharedWorkerHost::Start(
RenderProcessHost::FromID(process_id_)->GetBrowserContext(),
&renderer_preferences);
+ // Create a RendererPreferenceWatcher to observe updates in the preferences.
+ mojom::RendererPreferenceWatcherPtr watcher_ptr;
+ mojom::RendererPreferenceWatcherRequest preference_watcher_request =
+ mojo::MakeRequest(&watcher_ptr);
+ GetContentClient()->browser()->RegisterRendererPreferenceWatcherForWorkers(
+ RenderProcessHost::FromID(process_id_)->GetBrowserContext(),
+ std::move(watcher_ptr));
+
// Set up content settings interface.
blink::mojom::WorkerContentSettingsProxyPtr content_settings;
content_settings_ = std::make_unique<SharedWorkerContentSettingsProxyImpl>(
@@ -161,37 +173,43 @@ void SharedWorkerHost::Start(
mojom::kNavigation_SharedWorkerSpec, process_id_,
mojo::MakeRequest(&interface_provider)));
- // Add the network factory to the bundle to pass to the renderer. The bundle
- // is only provided (along with |script_loader_factory|) if
- // NetworkService/S13nSW is enabled.
- DCHECK(!script_loader_factory || factory_bundle);
- if (factory_bundle) {
- network::mojom::URLLoaderFactoryPtrInfo network_factory_info;
+ // Add the default factory to the bundle for subresource loading to pass to
+ // the renderer. The bundle is only provided if
+ // NetworkService/S13nServiceWorker is enabled.
+ // TODO(nhiroki): We might need to set the default factory to AppCache
+ // instead, as we do for frames, if requests from this shared worker are
+ // supposed to go through AppCache. Currently, we set the default factory to a
+ // direct network.
+ if (blink::ServiceWorkerUtils::IsServicificationEnabled()) {
+ DCHECK(subresource_loader_factories);
+ DCHECK(!subresource_loader_factories->default_factory_info());
if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
- // NetworkService is on: Use the network service.
+ network::mojom::URLLoaderFactoryPtrInfo network_factory_info;
CreateNetworkFactory(mojo::MakeRequest(&network_factory_info));
+ subresource_loader_factories->default_factory_info() =
+ std::move(network_factory_info);
} else {
- // NetworkService is off: RenderProcessHost gives us a non-NetworkService
- // network factory.
+ // Use the non-NetworkService network factory for the process when
+ // NetworkService is off.
+ network::mojom::URLLoaderFactoryPtr default_factory;
RenderProcessHost::FromID(process_id_)
- ->CreateURLLoaderFactory(mojo::MakeRequest(&network_factory_info));
+ ->CreateURLLoaderFactory(mojo::MakeRequest(&default_factory));
+ subresource_loader_factories->default_factory_info() =
+ default_factory.PassInterface();
}
- DCHECK(!factory_bundle->default_factory_info());
- factory_bundle->default_factory_info() = std::move(network_factory_info);
-
- // TODO(falken): We might need to set the default factory to AppCache
- // instead, as we do for frames, if requests from this shared worker are
- // supposed to go through AppCache.
}
// Send the CreateSharedWorker message.
factory_ = std::move(factory);
factory_->CreateSharedWorker(
std::move(info), pause_on_start, devtools_worker_token,
- renderer_preferences, std::move(content_settings),
- std::move(service_worker_provider_info), std::move(script_loader_factory),
- std::move(factory_bundle), std::move(host), std::move(worker_request_),
- std::move(interface_provider));
+ renderer_preferences, std::move(preference_watcher_request),
+ std::move(content_settings), std::move(service_worker_provider_info),
+ appcache_handle_ ? appcache_handle_->appcache_host_id()
+ : kAppCacheNoHostId,
+ std::move(main_script_loader_factory),
+ std::move(subresource_loader_factories), std::move(host),
+ std::move(worker_request_), std::move(interface_provider));
// Monitor the lifetime of the worker.
worker_.set_connection_error_handler(base::BindOnce(
@@ -366,11 +384,12 @@ void SharedWorkerHost::OnFeatureUsed(blink::mojom::WebFeature feature) {
info.client->OnFeatureUsed(feature);
}
-std::vector<std::pair<int, int>>
+std::vector<GlobalFrameRoutingId>
SharedWorkerHost::GetRenderFrameIDsForWorker() {
- std::vector<std::pair<int, int>> result;
+ std::vector<GlobalFrameRoutingId> result;
+ result.reserve(clients_.size());
for (const ClientInfo& info : clients_)
- result.push_back(std::make_pair(info.process_id, info.frame_id));
+ result.push_back(GlobalFrameRoutingId(info.process_id, info.frame_id));
return result;
}
@@ -416,6 +435,12 @@ void SharedWorkerHost::BindDevToolsAgent(
worker_->BindDevToolsAgent(std::move(request));
}
+void SharedWorkerHost::SetAppCacheHandle(
+ std::unique_ptr<AppCacheNavigationHandle> appcache_handle) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ appcache_handle_ = std::move(appcache_handle);
+}
+
void SharedWorkerHost::OnClientConnectionLost() {
// We'll get a notification for each dropped connection.
for (auto it = clients_.begin(); it != clients_.end(); ++it) {
diff --git a/chromium/content/browser/shared_worker/shared_worker_host.h b/chromium/content/browser/shared_worker/shared_worker_host.h
index 95f9f2c26fd..c75d9920a90 100644
--- a/chromium/content/browser/shared_worker/shared_worker_host.h
+++ b/chromium/content/browser/shared_worker/shared_worker_host.h
@@ -21,6 +21,7 @@
#include "content/common/shared_worker/shared_worker_client.mojom.h"
#include "content/common/shared_worker/shared_worker_factory.mojom.h"
#include "content/common/shared_worker/shared_worker_host.mojom.h"
+#include "content/public/browser/global_routing_id.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "services/service_manager/public/mojom/interface_provider.mojom.h"
@@ -33,6 +34,8 @@ class MessagePortChannel;
}
namespace content {
+
+class AppCacheNavigationHandle;
class SharedWorkerContentSettingsProxyImpl;
class SharedWorkerInstance;
class SharedWorkerServiceImpl;
@@ -59,16 +62,24 @@ class CONTENT_EXPORT SharedWorkerHost
// supporting the shared worker as a service worker client.
//
// S13nServiceWorker:
- // |script_loader_factory| is sent to the renderer process and is to be used
- // to request the shared worker's script. Currently it's only non-null when
- // S13nServiceWorker is enabled, to allow service worker machinery to observe
- // the request, but other web platform features may also use it someday.
+ // |main_script_loader_factory| is sent to the renderer process and is to be
+ // used to request the shared worker's main script. Currently it's only
+ // non-null when S13nServiceWorker is enabled, to allow service worker
+ // machinery to observe the request, but other web platform features may also
+ // use it someday.
+ //
+ // NetworkService:
+ // |subresource_loader_factories| is sent to the renderer process and is to be
+ // used to request subresources where applicable. For example, this allows the
+ // shared worker to load chrome-extension:// URLs which the renderer's default
+ // loader factory can't load.
void Start(
mojom::SharedWorkerFactoryPtr factory,
mojom::ServiceWorkerProviderInfoForSharedWorkerPtr
service_worker_provider_info,
- network::mojom::URLLoaderFactoryAssociatedPtrInfo script_loader_factory,
- std::unique_ptr<URLLoaderFactoryBundleInfo> factory_bundle);
+ network::mojom::URLLoaderFactoryAssociatedPtrInfo
+ main_script_loader_factory,
+ std::unique_ptr<URLLoaderFactoryBundleInfo> subresource_loader_factories);
void AllowFileSystem(const GURL& url,
base::OnceCallback<void(bool)> callback);
@@ -86,6 +97,9 @@ class CONTENT_EXPORT SharedWorkerHost
void BindDevToolsAgent(blink::mojom::DevToolsAgentAssociatedRequest request);
+ void SetAppCacheHandle(
+ std::unique_ptr<AppCacheNavigationHandle> appcache_handle);
+
SharedWorkerInstance* instance() { return instance_.get(); }
int process_id() const { return process_id_; }
bool IsAvailable() const;
@@ -127,8 +141,8 @@ class CONTENT_EXPORT SharedWorkerHost
void OnScriptLoadFailed() override;
void OnFeatureUsed(blink::mojom::WebFeature feature) override;
- // Return a vector of all the render process/render frame IDs.
- std::vector<std::pair<int, int>> GetRenderFrameIDsForWorker();
+ // Returns the frame ids of this worker's clients.
+ std::vector<GlobalFrameRoutingId> GetRenderFrameIDsForWorker();
void AllowFileSystemResponse(base::OnceCallback<void(bool)> callback,
bool allowed);
@@ -172,6 +186,11 @@ class CONTENT_EXPORT SharedWorkerHost
mojo::Binding<service_manager::mojom::InterfaceProvider>
interface_provider_binding_;
+ // NetworkService:
+ // The handle owns the precreated AppCacheHost until it's claimed by the
+ // renderer after main script loading finishes.
+ std::unique_ptr<AppCacheNavigationHandle> appcache_handle_;
+
Phase phase_ = Phase::kInitial;
base::WeakPtrFactory<SharedWorkerHost> weak_factory_;
diff --git a/chromium/content/browser/shared_worker/shared_worker_host_unittest.cc b/chromium/content/browser/shared_worker/shared_worker_host_unittest.cc
index f90a0342ef7..c5043d87b0f 100644
--- a/chromium/content/browser/shared_worker/shared_worker_host_unittest.cc
+++ b/chromium/content/browser/shared_worker/shared_worker_host_unittest.cc
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
+#include "content/browser/appcache/chrome_appcache_service.h"
#include "content/browser/shared_worker/mock_shared_worker.h"
#include "content/browser/shared_worker/shared_worker_connector_impl.h"
#include "content/browser/shared_worker/shared_worker_instance.h"
@@ -34,7 +35,9 @@ class SharedWorkerHostTest : public testing::Test {
public:
SharedWorkerHostTest()
: mock_render_process_host_(&browser_context_),
- service_(&storage_partition_, nullptr /* service_worker_context */) {
+ service_(&storage_partition_,
+ nullptr /* service_worker_context */,
+ nullptr /* appcache_service */) {
storage_partition_.set_network_context(&network_context_);
}
@@ -64,8 +67,8 @@ class SharedWorkerHostTest : public testing::Test {
void StartWorker(SharedWorkerHost* host,
mojom::SharedWorkerFactoryPtr factory) {
host->Start(std::move(factory), nullptr /* service_worker_provider_info */,
- {} /* script_loader_factory_info */,
- nullptr /* factory_bundle */);
+ {} /* main_script_loader_factory */,
+ nullptr /* subresource_loader_factories */);
}
MessagePortChannel AddClient(SharedWorkerHost* host,
@@ -195,8 +198,8 @@ TEST_F(SharedWorkerHostTest, TerminateAfterStarting) {
// Start the worker.
host->Start(std::move(factory), nullptr /* service_worker_provider_info */,
- {} /* script_loader_factory_info */,
- nullptr /* factory_bundle */);
+ {} /* main_script_loader_factory */,
+ nullptr /* subresource_loader_factories */);
// Add a client.
MockSharedWorkerClient client;
diff --git a/chromium/content/browser/shared_worker/shared_worker_script_loader.cc b/chromium/content/browser/shared_worker/shared_worker_script_loader.cc
index 81fb3763c49..0ded2f6fabd 100644
--- a/chromium/content/browser/shared_worker/shared_worker_script_loader.cc
+++ b/chromium/content/browser/shared_worker/shared_worker_script_loader.cc
@@ -4,7 +4,9 @@
#include "content/browser/shared_worker/shared_worker_script_loader.h"
+#include "content/browser/appcache/appcache_request_handler.h"
#include "content/browser/loader/navigation_loader_interceptor.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/service_worker/service_worker_provider_host.h"
#include "content/public/browser/resource_context.h"
#include "net/url_request/redirect_util.h"
@@ -14,16 +16,19 @@
namespace content {
SharedWorkerScriptLoader::SharedWorkerScriptLoader(
+ int process_id,
int32_t routing_id,
int32_t request_id,
uint32_t options,
const network::ResourceRequest& resource_request,
network::mojom::URLLoaderClientPtr client,
base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host,
+ base::WeakPtr<AppCacheHost> appcache_host,
ResourceContext* resource_context,
scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
- : routing_id_(routing_id),
+ : process_id_(process_id),
+ routing_id_(routing_id),
request_id_(request_id),
options_(options),
resource_request_(resource_request),
@@ -37,9 +42,19 @@ SharedWorkerScriptLoader::SharedWorkerScriptLoader(
DCHECK(blink::ServiceWorkerUtils::IsServicificationEnabled());
if (service_worker_provider_host_) {
- service_worker_interceptor_ =
+ std::unique_ptr<NavigationLoaderInterceptor> service_worker_interceptor =
ServiceWorkerRequestHandler::InitializeForSharedWorker(
resource_request_, service_worker_provider_host_);
+ if (service_worker_interceptor)
+ interceptors_.push_back(std::move(service_worker_interceptor));
+ }
+
+ if (appcache_host) {
+ std::unique_ptr<NavigationLoaderInterceptor> appcache_interceptor =
+ AppCacheRequestHandler::InitializeForMainResourceNetworkService(
+ resource_request_, appcache_host, default_loader_factory_);
+ if (appcache_interceptor)
+ interceptors_.push_back(std::move(appcache_interceptor));
}
Start();
@@ -48,21 +63,33 @@ SharedWorkerScriptLoader::SharedWorkerScriptLoader(
SharedWorkerScriptLoader::~SharedWorkerScriptLoader() = default;
void SharedWorkerScriptLoader::Start() {
- if (service_worker_interceptor_) {
- service_worker_interceptor_->MaybeCreateLoader(
+ if (interceptor_index_ < interceptors_.size()) {
+ auto* interceptor = interceptors_[interceptor_index_++].get();
+ interceptor->MaybeCreateLoader(
resource_request_, resource_context_,
base::BindOnce(&SharedWorkerScriptLoader::MaybeStartLoader,
- weak_factory_.GetWeakPtr(),
- service_worker_interceptor_.get()));
+ weak_factory_.GetWeakPtr(), interceptor),
+ base::BindOnce(&SharedWorkerScriptLoader::LoadFromNetwork,
+ weak_factory_.GetWeakPtr()));
return;
}
- LoadFromNetwork();
+ LoadFromNetwork(false);
}
void SharedWorkerScriptLoader::MaybeStartLoader(
NavigationLoaderInterceptor* interceptor,
SingleRequestURLLoaderFactory::RequestHandler single_request_handler) {
+ DCHECK(interceptor);
+
+ // TODO(nhiroki): Create SubresourceLoaderParams for intercepting subresource
+ // requests and populating the "controller" field in ServiceWorkerContainer,
+ // and send the params to the renderer when we create the SharedWorker.
+ // Note that we shouldn't try the next interceptor if this interceptor
+ // provides SubresourceLoaderParams. See comments on
+ // NavigationLoaderInterceptor::MaybeCreateSubresourceLoaderParams() for
+ // details.
+
if (single_request_handler) {
// The interceptor elected to handle the request. Use it.
network::mojom::URLLoaderClientPtr client;
@@ -76,11 +103,15 @@ void SharedWorkerScriptLoader::MaybeStartLoader(
return;
}
- LoadFromNetwork();
+ // Continue until all the interceptors are tried.
+ Start();
}
-void SharedWorkerScriptLoader::LoadFromNetwork() {
+void SharedWorkerScriptLoader::LoadFromNetwork(
+ bool reset_subresource_loader_params) {
network::mojom::URLLoaderClientPtr client;
+ if (url_loader_client_binding_)
+ url_loader_client_binding_.Unbind();
url_loader_client_binding_.Bind(mojo::MakeRequest(&client));
url_loader_factory_ = default_loader_factory_;
url_loader_factory_->CreateLoaderAndStart(
@@ -117,8 +148,15 @@ void SharedWorkerScriptLoader::FollowRedirect(
resource_request_.referrer_policy = redirect_info_->new_referrer_policy;
// Restart the request.
+ interceptor_index_ = 0;
url_loader_client_binding_.Unbind();
redirect_info_.reset();
+
+ // Cancel the request on ResourceDispatcherHost so that we can fall back
+ // to network again.
+ DCHECK(ResourceDispatcherHostImpl::Get());
+ ResourceDispatcherHostImpl::Get()->CancelRequest(process_id_, request_id_);
+
Start();
}
diff --git a/chromium/content/browser/shared_worker/shared_worker_script_loader.h b/chromium/content/browser/shared_worker/shared_worker_script_loader.h
index e7eb646e6a3..e8a876e5ca7 100644
--- a/chromium/content/browser/shared_worker/shared_worker_script_loader.h
+++ b/chromium/content/browser/shared_worker/shared_worker_script_loader.h
@@ -17,6 +17,8 @@ class SharedURLLoaderFactory;
} // namespace network
namespace content {
+
+class AppCacheHost;
class NavigationLoaderInterceptor;
class ResourceContext;
class ServiceWorkerProviderHost;
@@ -41,12 +43,14 @@ class SharedWorkerScriptLoader : public network::mojom::URLLoader,
// non-NetworkService factories used for non-http(s) URLs, e.g., a
// chrome-extension:// URL.
SharedWorkerScriptLoader(
+ int process_id,
int32_t routing_id,
int32_t request_id,
uint32_t options,
const network::ResourceRequest& resource_request,
network::mojom::URLLoaderClientPtr client,
base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host,
+ base::WeakPtr<AppCacheHost> appcache_host,
ResourceContext* resource_context,
scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation);
@@ -83,11 +87,14 @@ class SharedWorkerScriptLoader : public network::mojom::URLLoader,
void MaybeStartLoader(
NavigationLoaderInterceptor* interceptor,
SingleRequestURLLoaderFactory::RequestHandler single_request_handler);
- void LoadFromNetwork();
+ void LoadFromNetwork(bool reset_subresource_loader_params);
- // TODO(falken): Add other interceptors like in NavigationURLLoaderImpl.
- std::unique_ptr<NavigationLoaderInterceptor> service_worker_interceptor_;
+ // The order of the interceptors is important. The former interceptor can
+ // preferentially get a chance to intercept a network request.
+ std::vector<std::unique_ptr<NavigationLoaderInterceptor>> interceptors_;
+ size_t interceptor_index_ = 0;
+ const int process_id_;
const int32_t routing_id_;
const int32_t request_id_;
const uint32_t options_;
diff --git a/chromium/content/browser/shared_worker/shared_worker_script_loader_factory.cc b/chromium/content/browser/shared_worker/shared_worker_script_loader_factory.cc
index 6a21c378c48..74eaef69a4b 100644
--- a/chromium/content/browser/shared_worker/shared_worker_script_loader_factory.cc
+++ b/chromium/content/browser/shared_worker/shared_worker_script_loader_factory.cc
@@ -10,6 +10,7 @@
#include "content/browser/service_worker/service_worker_provider_host.h"
#include "content/browser/service_worker/service_worker_version.h"
#include "content/browser/shared_worker/shared_worker_script_loader.h"
+#include "content/public/browser/browser_thread.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/network/public/cpp/resource_response.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -19,19 +20,26 @@
namespace content {
SharedWorkerScriptLoaderFactory::SharedWorkerScriptLoaderFactory(
+ int process_id,
ServiceWorkerContextWrapper* context,
base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host,
+ base::WeakPtr<AppCacheHost> appcache_host,
ResourceContext* resource_context,
scoped_refptr<network::SharedURLLoaderFactory> loader_factory)
- : service_worker_provider_host_(service_worker_provider_host),
+ : process_id_(process_id),
+ service_worker_provider_host_(std::move(service_worker_provider_host)),
+ appcache_host_(std::move(appcache_host)),
resource_context_(resource_context),
loader_factory_(std::move(loader_factory)) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(blink::ServiceWorkerUtils::IsServicificationEnabled());
DCHECK_EQ(service_worker_provider_host_->provider_type(),
blink::mojom::ServiceWorkerProviderType::kForSharedWorker);
}
-SharedWorkerScriptLoaderFactory::~SharedWorkerScriptLoaderFactory() {}
+SharedWorkerScriptLoaderFactory::~SharedWorkerScriptLoaderFactory() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+}
void SharedWorkerScriptLoaderFactory::CreateLoaderAndStart(
network::mojom::URLLoaderRequest request,
@@ -41,6 +49,8 @@ void SharedWorkerScriptLoaderFactory::CreateLoaderAndStart(
const network::ResourceRequest& resource_request,
network::mojom::URLLoaderClientPtr client,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
// Handle only the main script (RESOURCE_TYPE_SHARED_WORKER). Import scripts
// should go to the network loader or controller.
if (resource_request.resource_type != RESOURCE_TYPE_SHARED_WORKER) {
@@ -53,9 +63,9 @@ void SharedWorkerScriptLoaderFactory::CreateLoaderAndStart(
// Create a SharedWorkerScriptLoader to load the script.
mojo::MakeStrongBinding(
std::make_unique<SharedWorkerScriptLoader>(
- routing_id, request_id, options, resource_request, std::move(client),
- service_worker_provider_host_, resource_context_, loader_factory_,
- traffic_annotation),
+ process_id_, routing_id, request_id, options, resource_request,
+ std::move(client), service_worker_provider_host_, appcache_host_,
+ resource_context_, loader_factory_, traffic_annotation),
std::move(request));
}
diff --git a/chromium/content/browser/shared_worker/shared_worker_script_loader_factory.h b/chromium/content/browser/shared_worker/shared_worker_script_loader_factory.h
index 2e42cfaafa6..f54949bad5b 100644
--- a/chromium/content/browser/shared_worker/shared_worker_script_loader_factory.h
+++ b/chromium/content/browser/shared_worker/shared_worker_script_loader_factory.h
@@ -14,6 +14,7 @@ class SharedURLLoaderFactory;
namespace content {
+class AppCacheHost;
class ServiceWorkerContextWrapper;
class ServiceWorkerProviderHost;
class ResourceContext;
@@ -36,8 +37,10 @@ class SharedWorkerScriptLoaderFactory
// the NetworkService. However, it may internally contain non-NetworkService
// factories used for non-http(s) URLs, e.g., a chrome-extension:// URL.
SharedWorkerScriptLoaderFactory(
+ int process_id,
ServiceWorkerContextWrapper* context,
base::WeakPtr<ServiceWorkerProviderHost> provider_host,
+ base::WeakPtr<AppCacheHost> appcache_host,
ResourceContext* resource_context,
scoped_refptr<network::SharedURLLoaderFactory> loader_factory);
~SharedWorkerScriptLoaderFactory() override;
@@ -54,7 +57,9 @@ class SharedWorkerScriptLoaderFactory
void Clone(network::mojom::URLLoaderFactoryRequest request) override;
private:
+ const int process_id_;
base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host_;
+ base::WeakPtr<AppCacheHost> appcache_host_;
ResourceContext* resource_context_ = nullptr;
scoped_refptr<network::SharedURLLoaderFactory> loader_factory_;
diff --git a/chromium/content/browser/shared_worker/shared_worker_service_impl.cc b/chromium/content/browser/shared_worker/shared_worker_service_impl.cc
index 0727104684b..51f91bdd7e2 100644
--- a/chromium/content/browser/shared_worker/shared_worker_service_impl.cc
+++ b/chromium/content/browser/shared_worker/shared_worker_service_impl.cc
@@ -10,9 +10,12 @@
#include <iterator>
#include "base/callback.h"
+#include "base/feature_list.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
+#include "content/browser/appcache/appcache_navigation_handle.h"
+#include "content/browser/appcache/appcache_navigation_handle_core.h"
#include "content/browser/file_url_loader_factory.h"
#include "content/browser/shared_worker/shared_worker_host.h"
#include "content/browser/shared_worker/shared_worker_instance.h"
@@ -30,6 +33,7 @@
#include "content/public/common/bind_interface_helpers.h"
#include "mojo/public/cpp/bindings/strong_associated_binding.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/network/public/cpp/features.h"
#include "third_party/blink/public/common/message_port/message_port_channel.h"
#include "third_party/blink/public/common/service_worker/service_worker_utils.h"
#include "url/origin.h"
@@ -71,7 +75,7 @@ std::unique_ptr<URLLoaderFactoryBundleInfo> CreateFactoryBundle(
auto file_factory = std::make_unique<FileURLLoaderFactory>(
storage_partition->browser_context()->GetPath(),
base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::BACKGROUND,
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
network::mojom::URLLoaderFactoryPtr file_factory_ptr;
mojo::MakeStrongBinding(std::move(file_factory),
@@ -79,15 +83,16 @@ std::unique_ptr<URLLoaderFactoryBundleInfo> CreateFactoryBundle(
factory_bundle->factories_info().emplace(url::kFileScheme,
file_factory_ptr.PassInterface());
}
+
return factory_bundle;
}
void CreateScriptLoaderOnIO(
scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter,
std::unique_ptr<URLLoaderFactoryBundleInfo> factory_bundle_for_browser_info,
- std::unique_ptr<URLLoaderFactoryBundleInfo>
- factory_bundle_for_renderer_info,
+ std::unique_ptr<URLLoaderFactoryBundleInfo> subresource_loader_factories,
scoped_refptr<ServiceWorkerContextWrapper> context,
+ AppCacheNavigationHandleCore* appcache_handle_core,
std::unique_ptr<network::SharedURLLoaderFactoryInfo>
blob_url_loader_factory_info,
int process_id,
@@ -111,48 +116,67 @@ void CreateScriptLoaderOnIO(
url_loader_factory = network::SharedURLLoaderFactory::Create(
std::move(blob_url_loader_factory_info));
} else {
+ // Add the default factory to the bundle for browser.
+ DCHECK(!factory_bundle_for_browser_info->default_factory_info());
+
// Create a factory bundle to use.
scoped_refptr<URLLoaderFactoryBundle> factory_bundle =
base::MakeRefCounted<URLLoaderFactoryBundle>(
std::move(factory_bundle_for_browser_info));
- url_loader_factory = factory_bundle;
- // Add the network factory to the bundle. The factory from
- // CloneNetworkFactory() doesn't support reconnection to the network service
- // after a crash, but it's OK since it's used for a single shared worker
- // startup.
+ // Get the direct network factory from |loader_factory_getter|. When
+ // NetworkService is enabled, it returns a factory that doesn't support
+ // reconnection to the network service after a crash, but it's OK since it's
+ // used for a single shared worker startup.
network::mojom::URLLoaderFactoryPtr network_factory_ptr;
loader_factory_getter->CloneNetworkFactory(
mojo::MakeRequest(&network_factory_ptr));
factory_bundle->SetDefaultFactory(std::move(network_factory_ptr));
+
+ url_loader_factory = factory_bundle;
}
+ // It's safe for |appcache_handle_core| to be a raw pointer. The core is owned
+ // by AppCacheNavigationHandle on the UI thread, which posts a task to delete
+ // the core on the IO thread on destruction, which must happen after this
+ // task.
+ base::WeakPtr<AppCacheHost> appcache_host =
+ appcache_handle_core ? appcache_handle_core->host()->GetWeakPtr()
+ : nullptr;
+
// Create the SharedWorkerScriptLoaderFactory.
- network::mojom::URLLoaderFactoryAssociatedPtrInfo script_loader_factory;
+ network::mojom::URLLoaderFactoryAssociatedPtrInfo main_script_loader_factory;
mojo::MakeStrongAssociatedBinding(
std::make_unique<SharedWorkerScriptLoaderFactory>(
- context.get(), host->AsWeakPtr(), context->resource_context(),
+ process_id, context.get(), host->AsWeakPtr(),
+ std::move(appcache_host), context->resource_context(),
std::move(url_loader_factory)),
- mojo::MakeRequest(&script_loader_factory));
+ mojo::MakeRequest(&main_script_loader_factory));
// We continue in StartWorker.
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::BindOnce(std::move(callback), std::move(provider_info),
- std::move(script_loader_factory),
- std::move(factory_bundle_for_renderer_info)));
+ std::move(main_script_loader_factory),
+ std::move(subresource_loader_factories)));
}
} // namespace
SharedWorkerServiceImpl::SharedWorkerServiceImpl(
StoragePartition* storage_partition,
- scoped_refptr<ServiceWorkerContextWrapper> service_worker_context)
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
+ scoped_refptr<ChromeAppCacheService> appcache_service)
: storage_partition_(storage_partition),
service_worker_context_(std::move(service_worker_context)),
- weak_factory_(this) {}
+ appcache_service_(std::move(appcache_service)),
+ weak_factory_(this) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+}
-SharedWorkerServiceImpl::~SharedWorkerServiceImpl() {}
+SharedWorkerServiceImpl::~SharedWorkerServiceImpl() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+}
bool SharedWorkerServiceImpl::TerminateWorker(
const GURL& url,
@@ -285,11 +309,11 @@ void SharedWorkerServiceImpl::CreateWorker(
auto weak_host = host->AsWeakPtr();
worker_hosts_.insert(std::move(host));
- StoragePartitionImpl* storage_partition =
- service_worker_context_->storage_partition();
- // Bounce to the IO thread to setup service worker support in case the request
- // for the worker script will need to be intercepted by service workers.
+ // Bounce to the IO thread to setup service worker and appcache support in
+ // case the request for the worker script will need to be intercepted by them.
if (blink::ServiceWorkerUtils::IsServicificationEnabled()) {
+ StoragePartitionImpl* storage_partition =
+ service_worker_context_->storage_partition();
if (!storage_partition) {
// The context is shutting down. Just drop the request.
return;
@@ -297,14 +321,25 @@ void SharedWorkerServiceImpl::CreateWorker(
// Set up the factory bundle for non-NetworkService URLs, e.g.,
// chrome-extension:// URLs. One factory bundle is consumed by the browser
- // for SharedWorkerScriptLoaderFactory, and one is sent to the renderer.
+ // for SharedWorkerScriptLoaderFactory, and one is sent to the renderer for
+ // subresource loading.
std::unique_ptr<URLLoaderFactoryBundleInfo> factory_bundle_for_browser =
CreateFactoryBundle(process_id, storage_partition,
constructor_uses_file_url);
- std::unique_ptr<URLLoaderFactoryBundleInfo> factory_bundle_for_renderer =
+ std::unique_ptr<URLLoaderFactoryBundleInfo> subresource_loader_factories =
CreateFactoryBundle(process_id, storage_partition,
constructor_uses_file_url);
+ // An appcache interceptor is available only when the network service is
+ // enabled.
+ AppCacheNavigationHandleCore* appcache_handle_core = nullptr;
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ auto appcache_handle =
+ std::make_unique<AppCacheNavigationHandle>(appcache_service_.get());
+ appcache_handle_core = appcache_handle->core();
+ weak_host->SetAppCacheHandle(std::move(appcache_handle));
+ }
+
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::BindOnce(
@@ -312,7 +347,8 @@ void SharedWorkerServiceImpl::CreateWorker(
service_worker_context_->storage_partition()
->url_loader_factory_getter(),
std::move(factory_bundle_for_browser),
- std::move(factory_bundle_for_renderer), service_worker_context_,
+ std::move(subresource_loader_factories), service_worker_context_,
+ appcache_handle_core,
blob_url_loader_factory ? blob_url_loader_factory->Clone()
: nullptr,
process_id,
@@ -337,8 +373,8 @@ void SharedWorkerServiceImpl::StartWorker(
mojom::ServiceWorkerProviderInfoForSharedWorkerPtr
service_worker_provider_info,
network::mojom::URLLoaderFactoryAssociatedPtrInfo
- script_loader_factory_info,
- std::unique_ptr<URLLoaderFactoryBundleInfo> factory_bundle) {
+ main_script_loader_factory,
+ std::unique_ptr<URLLoaderFactoryBundleInfo> subresource_loader_factories) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// The host may already be gone if something forcibly terminated the worker
@@ -365,7 +401,8 @@ void SharedWorkerServiceImpl::StartWorker(
BindInterface(process_host, &factory);
host->Start(std::move(factory), std::move(service_worker_provider_info),
- std::move(script_loader_factory_info), std::move(factory_bundle));
+ std::move(main_script_loader_factory),
+ std::move(subresource_loader_factories));
host->AddClient(std::move(client), process_id, frame_id, message_port);
}
diff --git a/chromium/content/browser/shared_worker/shared_worker_service_impl.h b/chromium/content/browser/shared_worker/shared_worker_service_impl.h
index 46810fa5d75..219003f234e 100644
--- a/chromium/content/browser/shared_worker/shared_worker_service_impl.h
+++ b/chromium/content/browser/shared_worker/shared_worker_service_impl.h
@@ -27,6 +27,8 @@ class MessagePortChannel;
}
namespace content {
+
+class ChromeAppCacheService;
class SharedWorkerInstance;
class SharedWorkerHost;
class StoragePartition;
@@ -36,7 +38,8 @@ class CONTENT_EXPORT SharedWorkerServiceImpl : public SharedWorkerService {
public:
SharedWorkerServiceImpl(
StoragePartition* storage_partition,
- scoped_refptr<ServiceWorkerContextWrapper> service_worker_context);
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
+ scoped_refptr<ChromeAppCacheService> appcache_service);
~SharedWorkerServiceImpl() override;
// SharedWorkerService implementation.
@@ -71,17 +74,18 @@ class CONTENT_EXPORT SharedWorkerServiceImpl : public SharedWorkerService {
int frame_id,
const blink::MessagePortChannel& message_port,
scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory);
- void StartWorker(std::unique_ptr<SharedWorkerInstance> instance,
- base::WeakPtr<SharedWorkerHost> host,
- mojom::SharedWorkerClientPtr client,
- int process_id,
- int frame_id,
- const blink::MessagePortChannel& message_port,
- mojom::ServiceWorkerProviderInfoForSharedWorkerPtr
- service_worker_provider_info,
- network::mojom::URLLoaderFactoryAssociatedPtrInfo
- script_loader_factory_info,
- std::unique_ptr<URLLoaderFactoryBundleInfo> factory_bundle);
+ void StartWorker(
+ std::unique_ptr<SharedWorkerInstance> instance,
+ base::WeakPtr<SharedWorkerHost> host,
+ mojom::SharedWorkerClientPtr client,
+ int process_id,
+ int frame_id,
+ const blink::MessagePortChannel& message_port,
+ mojom::ServiceWorkerProviderInfoForSharedWorkerPtr
+ service_worker_provider_info,
+ network::mojom::URLLoaderFactoryAssociatedPtrInfo
+ main_script_loader_factory,
+ std::unique_ptr<URLLoaderFactoryBundleInfo> subresource_loader_factories);
// Returns nullptr if there is no such host.
SharedWorkerHost* FindSharedWorkerHost(int process_id, int route_id);
@@ -95,6 +99,7 @@ class CONTENT_EXPORT SharedWorkerServiceImpl : public SharedWorkerService {
// |storage_partition_| owns |this|.
StoragePartition* const storage_partition_;
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
+ scoped_refptr<ChromeAppCacheService> appcache_service_;
base::WeakPtrFactory<SharedWorkerServiceImpl> weak_factory_;
diff --git a/chromium/content/browser/shared_worker/shared_worker_service_impl_unittest.cc b/chromium/content/browser/shared_worker/shared_worker_service_impl_unittest.cc
index cf56ef37546..e5d67bd381d 100644
--- a/chromium/content/browser/shared_worker/shared_worker_service_impl_unittest.cc
+++ b/chromium/content/browser/shared_worker/shared_worker_service_impl_unittest.cc
@@ -21,6 +21,7 @@
#include "content/test/test_render_view_host.h"
#include "content/test/test_web_contents.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/test_support/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/message_port/message_port_channel.h"
@@ -29,6 +30,42 @@ using blink::MessagePortChannel;
namespace content {
+namespace {
+
+// A mock URLLoaderFactory which just fails to create a loader. This is
+// sufficient because the tests don't exercise script loading. Used when
+// S13nServiceWorker is enabled.
+class NotImplementedNetworkURLLoaderFactory final
+ : public network::mojom::URLLoaderFactory {
+ public:
+ NotImplementedNetworkURLLoaderFactory() = default;
+
+ // network::mojom::URLLoaderFactory implementation.
+ void CreateLoaderAndStart(network::mojom::URLLoaderRequest request,
+ int32_t routing_id,
+ int32_t request_id,
+ uint32_t options,
+ const network::ResourceRequest& url_request,
+ network::mojom::URLLoaderClientPtr client,
+ const net::MutableNetworkTrafficAnnotationTag&
+ traffic_annotation) override {
+ network::URLLoaderCompletionStatus status;
+ status.error_code = net::ERR_NOT_IMPLEMENTED;
+ client->OnComplete(status);
+ }
+
+ void Clone(network::mojom::URLLoaderFactoryRequest request) override {
+ bindings_.AddBinding(this, std::move(request));
+ }
+
+ private:
+ mojo::BindingSet<network::mojom::URLLoaderFactory> bindings_;
+
+ DISALLOW_COPY_AND_ASSIGN(NotImplementedNetworkURLLoaderFactory);
+};
+
+} // namespace
+
class SharedWorkerServiceImplTest : public RenderViewHostImplTestHarness {
public:
mojom::SharedWorkerConnectorPtr MakeSharedWorkerConnector(
@@ -75,6 +112,8 @@ class SharedWorkerServiceImplTest : public RenderViewHostImplTestHarness {
std::make_unique<MockRenderProcessHostFactory>();
RenderProcessHostImpl::set_render_process_host_factory_for_testing(
render_process_host_factory_.get());
+ url_loader_factory_ =
+ std::make_unique<NotImplementedNetworkURLLoaderFactory>();
}
void TearDown() override {
@@ -86,6 +125,7 @@ class SharedWorkerServiceImplTest : public RenderViewHostImplTestHarness {
static std::queue<mojom::SharedWorkerFactoryRequest>
s_factory_request_received_;
std::unique_ptr<MockRenderProcessHostFactory> render_process_host_factory_;
+ std::unique_ptr<NotImplementedNetworkURLLoaderFactory> url_loader_factory_;
private:
DISALLOW_COPY_AND_ASSIGN(SharedWorkerServiceImplTest);
@@ -127,6 +167,7 @@ TEST_F(SharedWorkerServiceImplTest, BasicTest) {
renderer_host->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host->OverrideURLLoaderFactory(url_loader_factory_.get());
MockSharedWorkerClient client;
MessagePortChannel local_port;
@@ -202,6 +243,7 @@ TEST_F(SharedWorkerServiceImplTest, TwoRendererTest) {
renderer_host0->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
MockSharedWorkerClient client0;
MessagePortChannel local_port0;
@@ -270,6 +312,7 @@ TEST_F(SharedWorkerServiceImplTest, TwoRendererTest) {
renderer_host1->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
MockSharedWorkerClient client1;
MessagePortChannel local_port1;
@@ -331,6 +374,7 @@ TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_NormalCase) {
renderer_host0->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
// The second renderer host.
std::unique_ptr<TestWebContents> web_contents1 =
@@ -402,6 +446,7 @@ TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_NormalCase_URLMismatch) {
renderer_host0->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
// The second renderer host.
std::unique_ptr<TestWebContents> web_contents1 =
@@ -411,6 +456,7 @@ TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_NormalCase_URLMismatch) {
renderer_host1->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
// First client, creates worker.
@@ -485,6 +531,7 @@ TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_NormalCase_NameMismatch) {
renderer_host0->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
// The second renderer host.
std::unique_ptr<TestWebContents> web_contents1 =
@@ -494,6 +541,7 @@ TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_NormalCase_NameMismatch) {
renderer_host1->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
// First client, creates worker.
@@ -567,6 +615,7 @@ TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_PendingCase) {
renderer_host0->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
// The second renderer host.
std::unique_ptr<TestWebContents> web_contents1 =
@@ -576,6 +625,7 @@ TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_PendingCase) {
renderer_host1->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
// First client and second client are created before the worker starts.
@@ -640,6 +690,7 @@ TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_PendingCase_URLMismatch) {
renderer_host0->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
// The second renderer host.
std::unique_ptr<TestWebContents> web_contents1 =
@@ -649,6 +700,7 @@ TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_PendingCase_URLMismatch) {
renderer_host1->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
// First client and second client are created before the workers start.
@@ -727,6 +779,7 @@ TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_PendingCase_NameMismatch) {
renderer_host0->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
// The second renderer host.
std::unique_ptr<TestWebContents> web_contents1 =
@@ -736,6 +789,7 @@ TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_PendingCase_NameMismatch) {
renderer_host1->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
// First client and second client are created before the workers start.
@@ -814,6 +868,7 @@ TEST_F(SharedWorkerServiceImplTest, CreateWorkerRaceTest) {
renderer_host0->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
std::unique_ptr<TestWebContents> web_contents1 =
CreateWebContents(GURL("http://example.com/"));
@@ -822,6 +877,7 @@ TEST_F(SharedWorkerServiceImplTest, CreateWorkerRaceTest) {
renderer_host1->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
std::unique_ptr<TestWebContents> web_contents2 =
CreateWebContents(GURL("http://example.com/"));
@@ -830,6 +886,7 @@ TEST_F(SharedWorkerServiceImplTest, CreateWorkerRaceTest) {
renderer_host2->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host2->OverrideURLLoaderFactory(url_loader_factory_.get());
MockSharedWorkerClient client0;
MessagePortChannel local_port0;
@@ -922,6 +979,7 @@ TEST_F(SharedWorkerServiceImplTest, CreateWorkerRaceTest2) {
renderer_host0->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
std::unique_ptr<TestWebContents> web_contents1 =
CreateWebContents(GURL("http://example.com/"));
@@ -930,6 +988,7 @@ TEST_F(SharedWorkerServiceImplTest, CreateWorkerRaceTest2) {
renderer_host1->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
std::unique_ptr<TestWebContents> web_contents2 =
CreateWebContents(GURL("http://example.com/"));
@@ -938,6 +997,7 @@ TEST_F(SharedWorkerServiceImplTest, CreateWorkerRaceTest2) {
renderer_host2->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host2->OverrideURLLoaderFactory(url_loader_factory_.get());
MockSharedWorkerClient client0;
MessagePortChannel local_port0;
@@ -1007,6 +1067,7 @@ TEST_F(SharedWorkerServiceImplTest, CreateWorkerRaceTest3) {
mojom::SharedWorkerFactory::Name_,
base::BindRepeating(
&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
// The second renderer host.
std::unique_ptr<TestWebContents> web_contents1 =
@@ -1017,6 +1078,7 @@ TEST_F(SharedWorkerServiceImplTest, CreateWorkerRaceTest3) {
mojom::SharedWorkerFactory::Name_,
base::BindRepeating(
&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+ renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
// Both clients try to connect/create a worker.
diff --git a/chromium/content/browser/site_instance_impl.cc b/chromium/content/browser/site_instance_impl.cc
index bf59f2d42ca..073dc2d4f99 100644
--- a/chromium/content/browser/site_instance_impl.cc
+++ b/chromium/content/browser/site_instance_impl.cc
@@ -104,7 +104,8 @@ bool SiteInstanceImpl::HasProcess() const {
browsing_instance_->browser_context();
if (has_site_ &&
RenderProcessHost::ShouldUseProcessPerSite(browser_context, site_) &&
- RenderProcessHostImpl::GetProcessHostForSite(browser_context, site_)) {
+ RenderProcessHostImpl::GetSoleProcessHostForSite(browser_context, site_,
+ lock_url_)) {
return true;
}
@@ -133,8 +134,7 @@ RenderProcessHost* SiteInstanceImpl::GetProcess() {
process_reuse_policy_ = ProcessReusePolicy::DEFAULT;
}
- process_ = RenderProcessHostImpl::GetProcessHostForSiteInstance(
- browser_context, this);
+ process_ = RenderProcessHostImpl::GetProcessHostForSiteInstance(this);
CHECK(process_);
process_->AddObserver(this);
@@ -144,8 +144,8 @@ RenderProcessHost* SiteInstanceImpl::GetProcess() {
// at this time, we will register it in SetSite().)
if (process_reuse_policy_ == ProcessReusePolicy::PROCESS_PER_SITE &&
has_site_) {
- RenderProcessHostImpl::RegisterProcessHostForSite(browser_context,
- process_, site_);
+ RenderProcessHostImpl::RegisterSoleProcessHostForSite(browser_context,
+ process_, this);
}
TRACE_EVENT2("navigation", "SiteInstanceImpl::GetProcess",
@@ -182,8 +182,10 @@ void SiteInstanceImpl::SetSite(const GURL& url) {
// URL is invalid.
has_site_ = true;
BrowserContext* browser_context = browsing_instance_->browser_context();
- site_ = GetSiteForURL(browser_context, url);
+ site_ =
+ GetSiteForURL(browser_context, url, true /* should_use_effective_urls */);
original_url_ = url;
+ lock_url_ = DetermineProcessLockURL(browser_context, url);
// Now that we have a site, register it with the BrowsingInstance. This
// ensures that we won't create another SiteInstance for this site within
@@ -203,8 +205,8 @@ void SiteInstanceImpl::SetSite(const GURL& url) {
// Ensure the process is registered for this site if necessary.
if (should_use_process_per_site) {
- RenderProcessHostImpl::RegisterProcessHostForSite(
- browser_context, process_, site_);
+ RenderProcessHostImpl::RegisterSoleProcessHostForSite(browser_context,
+ process_, this);
}
}
}
@@ -249,20 +251,26 @@ bool SiteInstanceImpl::HasWrongProcessForURL(const GURL& url) {
if (IsRendererDebugURL(url))
return false;
- // Any process can host an about:blank URL. This check avoids a process
- // transfer for browser-initiated navigations to about:blank in a dedicated
- // process; without it, IsSuitableHost would consider this process unsuitable
- // for about:blank when it compares origin locks. Renderer-initiated
- // navigations will handle about:blank navigations elsewhere and leave them
- // in the source SiteInstance, along with about:srcdoc and data:.
- if (url == url::kAboutBlankURL)
+ // Any process can host an about:blank URL, except the one used for error
+ // pages, which should not commit successful navigations. This check avoids a
+ // process transfer for browser-initiated navigations to about:blank in a
+ // dedicated process; without it, IsSuitableHost would consider this process
+ // unsuitable for about:blank when it compares origin locks.
+ // Renderer-initiated navigations will handle about:blank navigations
+ // elsewhere and leave them in the source SiteInstance, along with
+ // about:srcdoc and data:.
+ if (url.IsAboutBlank() && site_ != GURL(kUnreachableWebDataURL))
return false;
// If the site URL is an extension (e.g., for hosted apps or WebUI) but the
// process is not (or vice versa), make sure we notice and fix it.
- GURL site_url = GetSiteForURL(browsing_instance_->browser_context(), url);
+ GURL site_url =
+ SiteInstance::GetSiteForURL(browsing_instance_->browser_context(), url);
+ GURL origin_lock =
+ DetermineProcessLockURL(browsing_instance_->browser_context(), url);
return !RenderProcessHostImpl::IsSuitableHost(
- GetProcess(), browsing_instance_->browser_context(), site_url);
+ GetProcess(), browsing_instance_->browser_context(), site_url,
+ origin_lock);
}
scoped_refptr<SiteInstanceImpl>
@@ -413,12 +421,32 @@ bool SiteInstanceImpl::IsSameWebSite(BrowserContext* browser_context,
// static
GURL SiteInstance::GetSiteForURL(BrowserContext* browser_context,
- const GURL& real_url) {
+ const GURL& url) {
+ // By default, GetSiteForURL will resolve |real_url| to an effective URL
+ // before computing its site.
+ return SiteInstanceImpl::GetSiteForURL(browser_context, url,
+ true /* should_use_effective_urls */);
+}
+
+// static
+GURL SiteInstanceImpl::DetermineProcessLockURL(BrowserContext* browser_context,
+ const GURL& url) {
+ // For the process lock URL, convert |url| to a site without resolving |url|
+ // to an effective URL.
+ return SiteInstanceImpl::GetSiteForURL(browser_context, url,
+ false /* should_use_effective_urls */);
+}
+
+GURL SiteInstanceImpl::GetSiteForURL(BrowserContext* browser_context,
+ const GURL& real_url,
+ bool should_use_effective_urls) {
// TODO(fsamuel, creis): For some reason appID is not recognized as a host.
if (real_url.SchemeIs(kGuestScheme))
return real_url;
- GURL url = SiteInstanceImpl::GetEffectiveURL(browser_context, real_url);
+ GURL url = should_use_effective_urls
+ ? SiteInstanceImpl::GetEffectiveURL(browser_context, real_url)
+ : real_url;
url::Origin origin = url::Origin::Create(url);
// Isolated origins should use the full origin as their site URL. A subdomain
@@ -442,6 +470,20 @@ GURL SiteInstance::GetSiteForURL(BrowserContext* browser_context,
std::string site = origin.scheme();
site += url::kStandardSchemeSeparator;
site += domain.empty() ? origin.host() : domain;
+
+ // If an effective URL was used, augment the effective site URL with the
+ // underlying web site in the hash. This is needed to keep
+ // navigations across sites covered by one hosted app in separate
+ // SiteInstances. See https://crbug.com/791796.
+ //
+ // TODO(https://crbug.com/734722): Consider replacing this hack with
+ // a proper security principal.
+ if (should_use_effective_urls && url != real_url) {
+ site += "#" + GetSiteForURL(browser_context, real_url,
+ false /* should_use_effective_urls */)
+ .spec();
+ }
+
return GURL(site);
}
@@ -520,7 +562,7 @@ bool SiteInstanceImpl::DoesSiteRequireDedicatedProcess(
return true;
// Always require a dedicated process for isolated origins.
- GURL site_url = GetSiteForURL(browser_context, url);
+ GURL site_url = SiteInstance::GetSiteForURL(browser_context, url);
auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
if (policy->IsIsolatedOrigin(url::Origin::Create(site_url)))
return true;
@@ -538,11 +580,10 @@ bool SiteInstanceImpl::DoesSiteRequireDedicatedProcess(
// static
bool SiteInstanceImpl::ShouldLockToOrigin(BrowserContext* browser_context,
- RenderProcessHost* host,
GURL site_url) {
// Don't lock to origin in --single-process mode, since this mode puts
// cross-site pages into the same process.
- if (host->run_renderer_in_process())
+ if (RenderProcessHost::run_renderer_in_process())
return false;
if (!DoesSiteRequireDedicatedProcess(browser_context, site_url))
@@ -604,8 +645,8 @@ void SiteInstanceImpl::LockToOriginIfNeeded() {
ChildProcessSecurityPolicyImpl* policy =
ChildProcessSecurityPolicyImpl::GetInstance();
- auto lock_state = policy->CheckOriginLock(process_->GetID(), site_);
- if (ShouldLockToOrigin(GetBrowserContext(), process_, site_)) {
+ auto lock_state = policy->CheckOriginLock(process_->GetID(), lock_url());
+ if (ShouldLockToOrigin(GetBrowserContext(), site_)) {
// Sanity check that this won't try to assign an origin lock to a <webview>
// process, which can't be locked.
CHECK(!process_->IsForGuestsOnly());
@@ -616,7 +657,9 @@ void SiteInstanceImpl::LockToOriginIfNeeded() {
// strong protection. If only some sites are isolated, we need
// additional logic to prevent the non-isolated sites from requesting
// resources for isolated sites. https://crbug.com/509125
- process_->LockToOrigin(site_);
+ TRACE_EVENT2("navigation", "SiteInstanceImpl::LockToOrigin", "site id",
+ id_, "lock", lock_url().possibly_invalid_spec());
+ process_->LockToOrigin(lock_url());
break;
}
case CheckOriginLockResult::HAS_WRONG_LOCK:
@@ -627,7 +670,7 @@ void SiteInstanceImpl::LockToOriginIfNeeded() {
base::debug::SetCrashKeyString(
bad_message::GetKilledProcessOriginLockKey(),
policy->GetOriginLock(process_->GetID()).spec());
- CHECK(false) << "Trying to lock a process to " << site_
+ CHECK(false) << "Trying to lock a process to " << lock_url()
<< " but the process is already locked to "
<< policy->GetOriginLock(process_->GetID());
break;
diff --git a/chromium/content/browser/site_instance_impl.h b/chromium/content/browser/site_instance_impl.h
index f2fa8e198bd..b53db35063a 100644
--- a/chromium/content/browser/site_instance_impl.h
+++ b/chromium/content/browser/site_instance_impl.h
@@ -116,11 +116,29 @@ class CONTENT_EXPORT SiteInstanceImpl final : public SiteInstance,
// May be empty if this SiteInstance does not have a |site_|.
const GURL& original_url() { return original_url_; }
+ // Returns the URL which should be used in a LockToOrigin call for this
+ // SiteInstance's process.
+ const GURL& lock_url() { return lock_url_; }
+
// True if |url| resolves to an effective URL that is different from |url|.
// See GetEffectiveURL(). This will be true for hosted apps as well as NTP
// URLs.
static bool HasEffectiveURL(BrowserContext* browser_context, const GURL& url);
+ // Returns the site for the given URL, which includes only the scheme and
+ // registered domain. Returns an empty GURL if the URL has no host.
+ // |use_effective_urls| specifies whether to resolve |url| to an effective
+ // URL (via ContentBrowserClient::GetEffectiveURL()) before determining the
+ // site.
+ static GURL GetSiteForURL(BrowserContext* context,
+ const GURL& url,
+ bool use_effective_urls);
+
+ // Returns the URL to which a process should be locked for the given URL.
+ // This is computed similarly to the site URL (see GetSiteForURL), but
+ // without resolving effective URLs.
+ static GURL DetermineProcessLockURL(BrowserContext* context, const GURL& url);
+
// Returns the SiteInstance, related to this one, that should be used
// for subframes when an oopif is required, but a dedicated process is not.
// This SiteInstance will be created if it doesn't already exist. There is
@@ -203,18 +221,17 @@ class CONTENT_EXPORT SiteInstanceImpl final : public SiteInstance,
static bool DoesSiteRequireDedicatedProcess(BrowserContext* browser_context,
const GURL& url);
- // Returns true if a process |host| can be locked to a site |site_url|.
- // Returning true here also implies that |site_url| requires a dedicated
- // process. However, the converse does not hold: this might still return
- // false for certain special cases where an origin lock can't be applied even
- // when |site_url| requires a dedicated process (e.g., with
+ // Returns true if a process can be locked to a site |site_url|. Returning
+ // true here also implies that |site_url| requires a dedicated process.
+ // However, the converse does not hold: this might still return false for
+ // certain special cases where an origin lock can't be applied even when
+ // |site_url| requires a dedicated process (e.g., with
// --site-per-process). Examples of those cases include <webview> guests,
// WebUI, single-process mode, or extensions where a process is currently
// allowed to be reused for different extensions. Most of these special
// cases should eventually be removed, and this function should become
// equivalent to DoesSiteRequireDedicatedProcess().
static bool ShouldLockToOrigin(BrowserContext* browser_context,
- RenderProcessHost* host,
GURL site_url);
private:
@@ -276,6 +293,12 @@ class CONTENT_EXPORT SiteInstanceImpl final : public SiteInstance,
// The URL which was used to set the |site_| for this SiteInstance.
GURL original_url_;
+ // The URL to use when locking a process to this SiteInstance's site via
+ // LockToOrigin(). This is the same as |site_| except for cases involving
+ // effective URLs, such as hosted apps. In those cases, this URL is a site
+ // URL that is computed without the use of effective URLs.
+ GURL lock_url_;
+
// The ProcessReusePolicy to use when creating a RenderProcessHost for this
// SiteInstance.
ProcessReusePolicy process_reuse_policy_;
@@ -283,7 +306,7 @@ class CONTENT_EXPORT SiteInstanceImpl final : public SiteInstance,
// Whether the SiteInstance was created for a service worker.
bool is_for_service_worker_;
- base::ObserverList<Observer, true> observers_;
+ base::ObserverList<Observer, true>::Unchecked observers_;
DISALLOW_COPY_AND_ASSIGN(SiteInstanceImpl);
};
diff --git a/chromium/content/browser/site_instance_impl_unittest.cc b/chromium/content/browser/site_instance_impl_unittest.cc
index 66159134d65..ec3fa59c538 100644
--- a/chromium/content/browser/site_instance_impl_unittest.cc
+++ b/chromium/content/browser/site_instance_impl_unittest.cc
@@ -258,51 +258,51 @@ TEST_F(SiteInstanceTest, SetSite) {
TEST_F(SiteInstanceTest, GetSiteForURL) {
// Pages are irrelevant.
GURL test_url = GURL("http://www.google.com/index.html");
- GURL site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+ GURL site_url = SiteInstance::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("http://google.com"), site_url);
EXPECT_EQ("http", site_url.scheme());
EXPECT_EQ("google.com", site_url.host());
// Ports are irrelevant.
test_url = GURL("https://www.google.com:8080");
- site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+ site_url = SiteInstance::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("https://google.com"), site_url);
// Punycode is canonicalized.
test_url = GURL("http://☃snowperson☃.net:333/");
- site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+ site_url = SiteInstance::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("http://xn--snowperson-di0gka.net"), site_url);
// Username and password are stripped out.
test_url = GURL("ftp://username:password@ftp.chromium.org/files/README");
- site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+ site_url = SiteInstance::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("ftp://chromium.org"), site_url);
// Literal IP addresses of any flavor are okay.
test_url = GURL("http://127.0.0.1/a.html");
- site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+ site_url = SiteInstance::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("http://127.0.0.1"), site_url);
EXPECT_EQ("127.0.0.1", site_url.host());
test_url = GURL("http://2130706433/a.html");
- site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+ site_url = SiteInstance::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("http://127.0.0.1"), site_url);
EXPECT_EQ("127.0.0.1", site_url.host());
test_url = GURL("http://[::1]:2/page.html");
- site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+ site_url = SiteInstance::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("http://[::1]"), site_url);
EXPECT_EQ("[::1]", site_url.host());
// Hostnames without TLDs are okay.
test_url = GURL("http://foo/a.html");
- site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+ site_url = SiteInstance::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("http://foo"), site_url);
EXPECT_EQ("foo", site_url.host());
// File URLs should include the scheme.
test_url = GURL("file:///C:/Downloads/");
- site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+ site_url = SiteInstance::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("file:"), site_url);
EXPECT_EQ("file", site_url.scheme());
EXPECT_FALSE(site_url.has_host());
@@ -311,7 +311,7 @@ TEST_F(SiteInstanceTest, GetSiteForURL) {
// maps *all* file://... URLs into "file://" origin) such file URLs still need
// to map into "file:" site URL. See also https://crbug.com/776160.
test_url = GURL("file://server/path");
- site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+ site_url = SiteInstance::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("file:"), site_url);
EXPECT_EQ("file", site_url.scheme());
EXPECT_FALSE(site_url.has_host());
@@ -319,7 +319,7 @@ TEST_F(SiteInstanceTest, GetSiteForURL) {
// Data URLs should include the whole URL, except for the hash, when Site
// Isolation is enabled. Otherwise they just include the scheme.
test_url = GURL("data:text/html,foo");
- site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+ site_url = SiteInstance::GetSiteForURL(nullptr, test_url);
if (AreAllSitesIsolatedForTesting())
EXPECT_EQ(test_url, site_url);
else
@@ -327,7 +327,7 @@ TEST_F(SiteInstanceTest, GetSiteForURL) {
EXPECT_EQ("data", site_url.scheme());
EXPECT_FALSE(site_url.has_host());
test_url = GURL("data:text/html,foo#bar");
- site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+ site_url = SiteInstance::GetSiteForURL(nullptr, test_url);
EXPECT_FALSE(site_url.has_ref());
if (AreAllSitesIsolatedForTesting()) {
EXPECT_NE(test_url, site_url);
@@ -338,7 +338,7 @@ TEST_F(SiteInstanceTest, GetSiteForURL) {
// Javascript URLs should include the scheme.
test_url = GURL("javascript:foo();");
- site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+ site_url = SiteInstance::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("javascript:"), site_url);
EXPECT_EQ("javascript", site_url.scheme());
EXPECT_FALSE(site_url.has_host());
@@ -347,12 +347,12 @@ TEST_F(SiteInstanceTest, GetSiteForURL) {
test_url = GURL(
"blob:gopher://www.ftp.chromium.org/"
"4d4ff040-6d61-4446-86d3-13ca07ec9ab9");
- site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+ site_url = SiteInstance::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("gopher://chromium.org"), site_url);
// Blob URLs with file origin also extract the site from the origin.
test_url = GURL("blob:file:///1029e5a4-2983-4b90-a585-ed217563acfeb");
- site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+ site_url = SiteInstance::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("file:"), site_url);
EXPECT_EQ("file", site_url.scheme());
EXPECT_FALSE(site_url.has_host());
@@ -361,13 +361,13 @@ TEST_F(SiteInstanceTest, GetSiteForURL) {
// when Site Isolation is enabled, except for the hash. Otherwise they just
// include the scheme.
test_url = GURL("blob:null/1029e5a4-2983-4b90-a585-ed217563acfeb");
- site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+ site_url = SiteInstance::GetSiteForURL(nullptr, test_url);
if (AreAllSitesIsolatedForTesting())
EXPECT_EQ(test_url, site_url);
else
EXPECT_EQ(GURL("blob:"), site_url);
test_url = GURL("blob:null/1029e5a4-2983-4b90-a585-ed217563acfeb#foo");
- site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+ site_url = SiteInstance::GetSiteForURL(nullptr, test_url);
EXPECT_FALSE(site_url.has_ref());
if (AreAllSitesIsolatedForTesting()) {
EXPECT_NE(test_url, site_url);
@@ -380,12 +380,12 @@ TEST_F(SiteInstanceTest, GetSiteForURL) {
test_url = GURL(
"blob:http://www.example.appspot.com:44/"
"4d4ff040-6d61-4446-86d3-13ca07ec9ab9");
- site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+ site_url = SiteInstance::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("http://example.appspot.com"), site_url);
// The site of filesystem URLs is determined by the inner URL.
test_url = GURL("filesystem:http://www.google.com/foo/bar.html?foo#bar");
- site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+ site_url = SiteInstance::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(GURL("http://google.com"), site_url);
// Guest URLs are special and need to have the path in the site as well,
@@ -393,12 +393,70 @@ TEST_F(SiteInstanceTest, GetSiteForURL) {
std::string guest_url(kGuestScheme);
guest_url.append("://abc123/path");
test_url = GURL(guest_url);
- site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+ site_url = SiteInstance::GetSiteForURL(nullptr, test_url);
EXPECT_EQ(test_url, site_url);
DrainMessageLoop();
}
+// Test that process lock URLs are computed without using effective URLs.
+TEST_F(SiteInstanceTest, ProcessLockDoesNotUseEffectiveURL) {
+ GURL test_url("https://some.app.foo.com/");
+ GURL nonapp_site_url("https://foo.com/");
+ GURL app_url("https://app.com/");
+ EffectiveURLContentBrowserClient modified_client(test_url, app_url);
+ ContentBrowserClient* regular_client =
+ SetBrowserClientForTesting(&modified_client);
+ std::unique_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
+
+ // Sanity check that GetSiteForURL's |use_effective_urls| option works
+ // properly. When it's true, the site URL should include both the effective
+ // URL's site (app.com) and the original URL's site (foo.com).
+ GURL expected_app_site_url(app_url.spec() + "#" + nonapp_site_url.spec());
+ {
+ GURL site_url = SiteInstanceImpl::GetSiteForURL(
+ nullptr, test_url, false /* use_effective_urls */);
+ EXPECT_EQ(nonapp_site_url, site_url);
+
+ site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url,
+ true /* use_effective_urls */);
+ EXPECT_EQ(expected_app_site_url, site_url);
+ }
+
+ // New SiteInstance in a new BrowsingInstance with a predetermined URL.
+ {
+ scoped_refptr<SiteInstanceImpl> site_instance =
+ SiteInstanceImpl::CreateForURL(browser_context.get(), test_url);
+ EXPECT_EQ(expected_app_site_url, site_instance->GetSiteURL());
+ EXPECT_EQ(nonapp_site_url, site_instance->lock_url());
+ }
+
+ // New related SiteInstance from an existing SiteInstance with a
+ // predetermined URL.
+ {
+ scoped_refptr<SiteInstanceImpl> bar_site_instance =
+ SiteInstanceImpl::CreateForURL(browser_context.get(),
+ GURL("https://bar.com/"));
+ scoped_refptr<SiteInstance> site_instance =
+ bar_site_instance->GetRelatedSiteInstance(test_url);
+ EXPECT_EQ(expected_app_site_url, site_instance->GetSiteURL());
+ EXPECT_EQ(nonapp_site_url,
+ static_cast<SiteInstanceImpl*>(site_instance.get())->lock_url());
+ }
+
+ // New SiteInstance with a lazily assigned site URL.
+ {
+ scoped_refptr<SiteInstanceImpl> site_instance =
+ SiteInstanceImpl::Create(browser_context.get());
+ EXPECT_FALSE(site_instance->HasSite());
+ site_instance->SetSite(test_url);
+ EXPECT_EQ(expected_app_site_url, site_instance->GetSiteURL());
+ EXPECT_EQ(nonapp_site_url, site_instance->lock_url());
+ }
+
+ SetBrowserClientForTesting(regular_client);
+}
+
// Test of distinguishing URLs from different sites. Most of this logic is
// tested in RegistryControlledDomainTest. This test focuses on URLs with
// different schemes or ports.
@@ -837,8 +895,10 @@ TEST_F(SiteInstanceTest, NoProcessPerSiteForEmptySite) {
EXPECT_TRUE(instance->GetSiteURL().is_empty());
host.reset(instance->GetProcess());
- EXPECT_FALSE(RenderProcessHostImpl::GetProcessHostForSite(
+ EXPECT_FALSE(RenderProcessHostImpl::GetSoleProcessHostForURL(
browser_context.get(), GURL()));
+ EXPECT_FALSE(RenderProcessHostImpl::GetSoleProcessHostForSite(
+ browser_context.get(), GURL(), GURL()));
DrainMessageLoop();
}
@@ -1203,11 +1263,15 @@ TEST_F(SiteInstanceTest, OriginalURL) {
SetBrowserClientForTesting(&modified_client);
std::unique_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
+ // The site URL of of effective URL should include both the effective URL's
+ // site and the original URL's site.
+ GURL expected_site_url(app_url.spec() + "#" + original_url.spec());
+
// New SiteInstance in a new BrowsingInstance with a predetermined URL.
{
scoped_refptr<SiteInstanceImpl> site_instance =
SiteInstanceImpl::CreateForURL(browser_context.get(), original_url);
- EXPECT_EQ(app_url, site_instance->GetSiteURL());
+ EXPECT_EQ(expected_site_url, site_instance->GetSiteURL());
EXPECT_EQ(original_url, site_instance->original_url());
}
@@ -1219,7 +1283,7 @@ TEST_F(SiteInstanceTest, OriginalURL) {
GURL("https://bar.com/"));
scoped_refptr<SiteInstance> site_instance =
bar_site_instance->GetRelatedSiteInstance(original_url);
- EXPECT_EQ(app_url, site_instance->GetSiteURL());
+ EXPECT_EQ(expected_site_url, site_instance->GetSiteURL());
EXPECT_EQ(
original_url,
static_cast<SiteInstanceImpl*>(site_instance.get())->original_url());
@@ -1232,7 +1296,7 @@ TEST_F(SiteInstanceTest, OriginalURL) {
EXPECT_FALSE(site_instance->HasSite());
EXPECT_TRUE(site_instance->original_url().is_empty());
site_instance->SetSite(original_url);
- EXPECT_EQ(app_url, site_instance->GetSiteURL());
+ EXPECT_EQ(expected_site_url, site_instance->GetSiteURL());
EXPECT_EQ(original_url, site_instance->original_url());
}
diff --git a/chromium/content/browser/site_per_process_browsertest.cc b/chromium/content/browser/site_per_process_browsertest.cc
index e2cd0167869..396d50ce3cf 100644
--- a/chromium/content/browser/site_per_process_browsertest.cc
+++ b/chromium/content/browser/site_per_process_browsertest.cc
@@ -37,6 +37,7 @@
#include "base/test/test_timeouts.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "base/timer/timer.h"
#include "build/build_config.h"
#include "cc/input/touch_action.h"
#include "components/network_session_configurator/common/network_switches.h"
@@ -136,8 +137,12 @@
#include "content/browser/android/ime_adapter_android.h"
#include "content/browser/renderer_host/input/touch_selection_controller_client_manager_android.h"
#include "content/browser/renderer_host/render_widget_host_view_android.h"
+#include "content/browser/web_contents/web_contents_view_android.h"
#include "content/public/browser/android/child_process_importance.h"
#include "content/test/mock_overscroll_refresh_handler_android.h"
+#include "ui/android/view_android.h"
+#include "ui/android/window_android.h"
+#include "ui/events/android/event_handler_android.h"
#include "ui/events/android/motion_event_android.h"
#include "ui/gfx/geometry/point_f.h"
#endif
@@ -164,12 +169,7 @@ void PostMessageAndWaitForReply(FrameTreeNode* sender_ftn,
// else it might miss the message of interest. See https://crbug.com/518729.
DOMMessageQueue msg_queue;
- bool success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- sender_ftn,
- "window.domAutomationController.send(" + post_message_script + ");",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(true, EvalJs(sender_ftn, "(" + post_message_script + ");"));
std::string status;
while (msg_queue.WaitForMessage(&status)) {
@@ -182,11 +182,7 @@ void PostMessageAndWaitForReply(FrameTreeNode* sender_ftn,
// |sender_ftn| frame. This variable is used in post_message.html to count the
// number of messages received via postMessage by the current window.
int GetReceivedMessages(FrameTreeNode* ftn) {
- int received_messages = 0;
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- ftn, "window.domAutomationController.send(window.receivedMessages);",
- &received_messages));
- return received_messages;
+ return EvalJs(ftn, "window.receivedMessages;").ExtractInt();
}
// Helper function to perform a window.open from the |caller_frame| targeting a
@@ -194,13 +190,8 @@ int GetReceivedMessages(FrameTreeNode* ftn) {
void NavigateNamedFrame(const ToRenderFrameHost& caller_frame,
const GURL& url,
const std::string& name) {
- bool success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- caller_frame,
- "window.domAutomationController.send("
- " !!window.open('" + url.spec() + "', '" + name + "'));",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(true, EvalJs(caller_frame,
+ JsReplace("!!window.open($1, $2)", url, name)));
}
// Helper function to generate a click on the given RenderWidgetHost. The
@@ -216,20 +207,12 @@ void SimulateMouseClick(RenderWidgetHost* rwh, int x, int y) {
}
// Retrieve document.origin for the frame |ftn|.
-std::string GetDocumentOrigin(FrameTreeNode* ftn) {
- std::string origin;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- ftn, "domAutomationController.send(document.origin)", &origin));
- return origin;
+EvalJsResult GetDocumentOrigin(FrameTreeNode* ftn) {
+ return EvalJs(ftn, "document.origin;");
}
double GetFrameDeviceScaleFactor(const ToRenderFrameHost& adapter) {
- double device_scale_factor;
- const char kGetFrameDeviceScaleFactor[] =
- "window.domAutomationController.send(window.devicePixelRatio);";
- EXPECT_TRUE(ExecuteScriptAndExtractDouble(adapter, kGetFrameDeviceScaleFactor,
- &device_scale_factor));
- return device_scale_factor;
+ return EvalJs(adapter, "window.devicePixelRatio;").ExtractDouble();
}
class RedirectNotificationObserver : public NotificationObserver {
@@ -269,7 +252,7 @@ class RedirectNotificationObserver : public NotificationObserver {
NotificationSource source_;
NotificationDetails details_;
- scoped_refptr<MessageLoopRunner> message_loop_runner_;
+ base::RunLoop run_loop_;
DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver);
};
@@ -290,8 +273,7 @@ void RedirectNotificationObserver::Wait() {
return;
running_ = true;
- message_loop_runner_ = new MessageLoopRunner;
- message_loop_runner_->Run();
+ run_loop_.Run();
EXPECT_TRUE(seen_);
}
@@ -306,7 +288,7 @@ void RedirectNotificationObserver::Observe(
if (!running_)
return;
- message_loop_runner_->Quit();
+ run_loop_.Quit();
running_ = false;
}
@@ -319,8 +301,7 @@ class RenderFrameHostCreatedObserver : public WebContentsObserver {
int expected_frame_count)
: WebContentsObserver(web_contents),
expected_frame_count_(expected_frame_count),
- frames_created_(0),
- message_loop_runner_(new MessageLoopRunner) {}
+ frames_created_(0) {}
~RenderFrameHostCreatedObserver() override;
@@ -338,8 +319,8 @@ class RenderFrameHostCreatedObserver : public WebContentsObserver {
// The number of RenderFrameHosts that have been created.
int frames_created_;
- // The MessageLoopRunner used to spin the message loop.
- scoped_refptr<MessageLoopRunner> message_loop_runner_;
+ // The RunLoop used to spin the message loop.
+ base::RunLoop run_loop_;
DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver);
};
@@ -348,14 +329,14 @@ RenderFrameHostCreatedObserver::~RenderFrameHostCreatedObserver() {
}
void RenderFrameHostCreatedObserver::Wait() {
- message_loop_runner_->Run();
+ run_loop_.Run();
}
void RenderFrameHostCreatedObserver::RenderFrameCreated(
RenderFrameHost* render_frame_host) {
frames_created_++;
if (frames_created_ == expected_frame_count_) {
- message_loop_runner_->Quit();
+ run_loop_.Quit();
}
}
@@ -395,23 +376,6 @@ void FocusFrame(FrameTreeNode* frame) {
focus_observer.Wait();
}
-// A BrowserMessageFilter that drops SwapOut ACK messages.
-class SwapoutACKMessageFilter : public BrowserMessageFilter {
- public:
- SwapoutACKMessageFilter() : BrowserMessageFilter(FrameMsgStart) {}
-
- protected:
- ~SwapoutACKMessageFilter() override {}
-
- private:
- // BrowserMessageFilter:
- bool OnMessageReceived(const IPC::Message& message) override {
- return message.type() == FrameHostMsg_SwapOut_ACK::ID;
- }
-
- DISALLOW_COPY_AND_ASSIGN(SwapoutACKMessageFilter);
-};
-
class RenderWidgetHostVisibilityObserver : public RenderWidgetHostObserver {
public:
explicit RenderWidgetHostVisibilityObserver(RenderWidgetHostImpl* rwhi,
@@ -530,6 +494,35 @@ void CheckFrameDepth(unsigned int expected_depth, FrameTreeNode* node) {
node->current_frame_host()->GetProcess()->GetFrameDepth());
}
+// Check |intersects_viewport| on widget and process.
+bool CheckIntersectsViewport(bool expected, FrameTreeNode* node) {
+ RenderProcessHost::Priority priority =
+ node->current_frame_host()->GetRenderWidgetHost()->GetPriority();
+ return priority.intersects_viewport == expected &&
+ node->current_frame_host()->GetProcess()->GetIntersectsViewport() ==
+ expected;
+}
+
+// Layout child frames in cross_site_iframe_factory.html so that they are the
+// same width as the viewport, and 75% of the height of the window. This is for
+// testing viewport intersection. Note this does not recurse into child frames
+// and re-layout in the same way since children might be in a different origin.
+void LayoutNonRecursiveForTestingViewportIntersection(
+ WebContents* web_contents) {
+ static const char* script =
+ "function relayoutNonRecursiveForTestingViewportIntersection() {\
+ var width = window.innerWidth;\
+ var height = window.innerHeight * 0.75;\
+ for (var i = 0; i < window.frames.length; i++) {\
+ child = document.getElementById(\"child-\" + i);\
+ child.width = width;\
+ child.height = height;\
+ }\
+ }\
+ relayoutNonRecursiveForTestingViewportIntersection();";
+ EXPECT_TRUE(ExecuteScript(web_contents, script));
+}
+
void GenerateTapDownGesture(RenderWidgetHost* rwh) {
blink::WebGestureEvent gesture_tap_down(
blink::WebGestureEvent::kGestureTapDown,
@@ -540,6 +533,86 @@ void GenerateTapDownGesture(RenderWidgetHost* rwh) {
rwh->ForwardGestureEvent(gesture_tap_down);
}
+// Class to monitor incoming FrameHostMsg_UpdateViewportIntersection messages.
+class UpdateViewportIntersectionMessageFilter
+ : public content::BrowserMessageFilter {
+ public:
+ UpdateViewportIntersectionMessageFilter()
+ : content::BrowserMessageFilter(FrameMsgStart), msg_received_(false) {}
+
+ bool OnMessageReceived(const IPC::Message& message) override {
+ IPC_BEGIN_MESSAGE_MAP(UpdateViewportIntersectionMessageFilter, message)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_UpdateViewportIntersection,
+ OnUpdateViewportIntersection)
+ IPC_END_MESSAGE_MAP()
+ return false;
+ }
+
+ gfx::Rect GetCompositingRect() const { return compositing_rect_; }
+ gfx::Rect GetViewportIntersection() const { return viewport_intersection_; }
+ bool GetOccludedOrObscured() const { return occluded_or_obscured_; }
+
+ void Wait() {
+ DCHECK(!run_loop_);
+ if (msg_received_) {
+ msg_received_ = false;
+ return;
+ }
+ std::unique_ptr<base::RunLoop> run_loop(new base::RunLoop);
+ run_loop_ = run_loop.get();
+ run_loop_->Run();
+ run_loop_ = nullptr;
+ msg_received_ = false;
+ }
+
+ void set_run_loop(base::RunLoop* run_loop) { run_loop_ = run_loop; }
+
+ private:
+ ~UpdateViewportIntersectionMessageFilter() override {}
+
+ void OnUpdateViewportIntersection(const gfx::Rect& viewport_intersection,
+ const gfx::Rect& compositing_rect,
+ bool occluded_or_obscured) {
+ // The message is going to be posted to UI thread after
+ // OnUpdateViewportIntersection returns. This additional post on the IO
+ // thread guarantees that by the time OnUpdateViewportIntersectionOnUI runs,
+ // the message has been handled on the UI thread.
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&UpdateViewportIntersectionMessageFilter::
+ OnUpdateViewportIntersectionPostOnIO,
+ this, viewport_intersection, compositing_rect,
+ occluded_or_obscured));
+ }
+ void OnUpdateViewportIntersectionPostOnIO(
+ const gfx::Rect& viewport_intersection,
+ const gfx::Rect& compositing_rect,
+ bool occluded_or_obscured) {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&UpdateViewportIntersectionMessageFilter::
+ OnUpdateViewportIntersectionOnUI,
+ this, viewport_intersection, compositing_rect,
+ occluded_or_obscured));
+ }
+ void OnUpdateViewportIntersectionOnUI(const gfx::Rect& viewport_intersection,
+ const gfx::Rect& compositing_rect,
+ bool occluded_or_obscured) {
+ viewport_intersection_ = viewport_intersection;
+ compositing_rect_ = compositing_rect;
+ occluded_or_obscured_ = occluded_or_obscured;
+ msg_received_ = true;
+ if (run_loop_)
+ run_loop_->Quit();
+ }
+ base::RunLoop* run_loop_ = nullptr;
+ bool msg_received_;
+ gfx::Rect compositing_rect_;
+ gfx::Rect viewport_intersection_;
+ bool occluded_or_obscured_ = false;
+ DISALLOW_COPY_AND_ASSIGN(UpdateViewportIntersectionMessageFilter);
+};
+
} // namespace
//
@@ -1075,9 +1148,16 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
rwhv_nested->GetCompositorViewportPixelSize());
}
+// Disable on Android: crbug/851049
+#if defined(OS_ANDROID)
+#define MAYBE_NoResizeAfterIframeLoad DISABLED_NoResizeAfterIframeLoad
+#else
+#define MAYBE_NoResizeAfterIframeLoad NoResizeAfterIframeLoad
+#endif
// Verify an OOPIF resize handler doesn't fire immediately after load without
// the frame having been resized. See https://crbug.com/826457.
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NoResizeAfterIframeLoad) {
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ MAYBE_NoResizeAfterIframeLoad) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -1089,6 +1169,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NoResizeAfterIframeLoad) {
GURL site_url =
embedded_test_server()->GetURL("b.com", "/page_with_resize_handler.html");
NavigateFrameToURL(iframe, site_url);
+ base::RunLoop().RunUntilIdle();
int resizes = -1;
EXPECT_TRUE(ExecuteScriptAndExtractInt(
@@ -2170,6 +2251,42 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessProgrammaticScrollTest,
#endif
}
+// This test verifies that smooth scrolling works correctly inside nested OOPIFs
+// which are same origin with the parent. Note that since the frame tree has
+// a A(B(A1())) structure, if and A1 and A2 shared the same
+// SmoothScrollSequencer, then this test would time out or at best be flaky with
+// random time outs. See https://crbug.com/865446 for more context.
+IN_PROC_BROWSER_TEST_F(SitePerProcessProgrammaticScrollTest,
+ SmoothScrollInNestedSameProcessOOPIF) {
+ GURL main_frame(
+ embedded_test_server()->GetURL("a.com", kIframeOutOfViewHTML));
+ GURL child_url_b(
+ embedded_test_server()->GetURL("b.com", kIframeOutOfViewHTML));
+ GURL same_origin(
+ embedded_test_server()->GetURL("a.com", kIframeOutOfViewHTML));
+
+ // This will set up the page frame tree as A(B(A1(A2()))) where A1 is later
+ // asked to scroll the <iframe> element of A2 into view. The important bit
+ // here is that the inner frame A1 is recursively scrolling (smoothly) an
+ // element inside its document into view (A2's origin is irrelevant here).
+ ASSERT_TRUE(NavigateToURL(shell(), main_frame));
+ FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+ WaitForOnLoad(root);
+ NavigateFrameToURL(root->child_at(0), child_url_b);
+ WaitForOnLoad(root->child_at(0));
+ auto* nested_ftn = root->child_at(0)->child_at(0);
+ NavigateFrameToURL(nested_ftn, same_origin);
+ WaitForOnLoad(nested_ftn);
+
+ // *Smoothly* scroll the inner most frame into view.
+ ASSERT_TRUE(ExecuteScript(
+ nested_ftn,
+ "document.querySelector('iframe').scrollIntoView({behavior: 'smooth'})"));
+ WaitForElementVisible(root, kIframeSelector);
+ WaitForElementVisible(root->child_at(0), kIframeSelector);
+ WaitForElementVisible(nested_ftn, kIframeSelector);
+}
+
// Tests OOPIF rendering by checking that the RWH of the iframe generates
// OnSwapCompositorFrame message.
IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CompositorFrameSwapped) {
@@ -3614,17 +3731,14 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// Also note that just comparing clientHeight and scrollHeight of the frame's
// document will not work.
auto has_scrollbar = [](RenderFrameHostImpl* rfh) {
- int client_width;
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- rfh, "window.domAutomationController.send(document.body.clientWidth);",
- &client_width));
+ int client_width = EvalJs(rfh, "document.body.clientWidth").ExtractInt();
const int kFrameElementWidth = 200;
return client_width < kFrameElementWidth;
};
auto set_scrolling_property = [](RenderFrameHostImpl* parent_rfh,
const std::string& value) {
- EXPECT_TRUE(ExecuteScript(
+ EXPECT_TRUE(ExecJs(
parent_rfh,
base::StringPrintf("document.getElementById('child-1').setAttribute("
" 'scrolling', '%s');",
@@ -3671,21 +3785,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
FrameTreeNode* child = root->child_at(0);
- std::string margin_width;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- child,
- "window.domAutomationController.send("
- "document.body.getAttribute('marginwidth'));",
- &margin_width));
- EXPECT_EQ("10", margin_width);
-
- std::string margin_height;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- child,
- "window.domAutomationController.send("
- "document.body.getAttribute('marginheight'));",
- &margin_height));
- EXPECT_EQ("50", margin_height);
+ EXPECT_EQ("10", EvalJs(child, "document.body.getAttribute('marginwidth');"));
+ EXPECT_EQ("50", EvalJs(child, "document.body.getAttribute('marginheight');"));
// Run the test over variety of parent/child cases.
GURL urls[] = {// Remote to remote.
@@ -3703,34 +3804,19 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// correctly after the navigation has completed.
for (size_t i = 0; i < arraysize(urls); ++i) {
// Change marginwidth and marginheight before navigating.
- EXPECT_TRUE(ExecuteScript(
- root,
- base::StringPrintf("document.getElementById('child-1').setAttribute("
- " 'marginwidth', '%d');",
- current_margin_width)));
- EXPECT_TRUE(ExecuteScript(
+ EXPECT_TRUE(ExecJs(
root,
- base::StringPrintf("document.getElementById('child-1').setAttribute("
- " 'marginheight', '%d');",
- current_margin_height)));
+ base::StringPrintf("var child = document.getElementById('child-1');"
+ "child.setAttribute('marginwidth', '%d');"
+ "child.setAttribute('marginheight', '%d');",
+ current_margin_width, current_margin_height)));
NavigateFrameToURL(child, urls[i]);
- std::string actual_margin_width;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- child,
- "window.domAutomationController.send("
- "document.body.getAttribute('marginwidth'));",
- &actual_margin_width));
- EXPECT_EQ(base::IntToString(current_margin_width), actual_margin_width);
-
- std::string actual_margin_height;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- child,
- "window.domAutomationController.send("
- "document.body.getAttribute('marginheight'));",
- &actual_margin_height));
- EXPECT_EQ(base::IntToString(current_margin_height), actual_margin_height);
+ EXPECT_EQ(base::IntToString(current_margin_width),
+ EvalJs(child, "document.body.getAttribute('marginwidth');"));
+ EXPECT_EQ(base::IntToString(current_margin_height),
+ EvalJs(child, "document.body.getAttribute('marginheight');"));
current_margin_width += 5;
current_margin_height += 10;
@@ -3758,13 +3844,9 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessEmbedderCSPEnforcementBrowserTest,
FrameTreeNode* child = root->child_at(0);
- std::string csp;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- root,
- "window.domAutomationController.send("
- "document.getElementById('child-1').getAttribute('csp'));",
- &csp));
- EXPECT_EQ("object-src \'none\'", csp);
+ EXPECT_EQ(
+ "object-src \'none\'",
+ EvalJs(root, "document.getElementById('child-1').getAttribute('csp');"));
// Run the test over variety of parent/child cases.
GURL urls[] = {// Remote to remote.
@@ -3815,9 +3897,12 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginReplication) {
" C = http://c.com/",
DepictFrameTree(root));
- std::string a_origin = embedded_test_server()->GetURL("a.com", "/").spec();
- std::string b_origin = embedded_test_server()->GetURL("b.com", "/").spec();
- std::string c_origin = embedded_test_server()->GetURL("c.com", "/").spec();
+ url::Origin a_origin =
+ url::Origin::Create(embedded_test_server()->GetURL("a.com", "/"));
+ url::Origin b_origin =
+ url::Origin::Create(embedded_test_server()->GetURL("b.com", "/"));
+ url::Origin c_origin =
+ url::Origin::Create(embedded_test_server()->GetURL("c.com", "/"));
FrameTreeNode* tiptop_child = root->child_at(0);
FrameTreeNode* middle_child = root->child_at(0)->child_at(0);
FrameTreeNode* lowest_child = root->child_at(0)->child_at(0)->child_at(0);
@@ -3826,18 +3911,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginReplication) {
// origin for the parent. The origin should have been replicated as part of
// the mojom::Renderer::CreateView message that created the parent's
// RenderFrameProxy in b.com's process.
- int ancestor_origins_length = 0;
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- tiptop_child,
- "window.domAutomationController.send(location.ancestorOrigins.length);",
- &ancestor_origins_length));
- EXPECT_EQ(1, ancestor_origins_length);
- std::string result;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- tiptop_child,
- "window.domAutomationController.send(location.ancestorOrigins[0]);",
- &result));
- EXPECT_EQ(a_origin, result + "/");
+ EXPECT_EQ(ListValueOf(a_origin),
+ EvalJs(tiptop_child, "Array.from(location.ancestorOrigins);"));
// Check that c.com frame's location.ancestorOrigins contains the correct
// origin for its two ancestors. The topmost parent origin should be
@@ -3845,44 +3920,13 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginReplication) {
// (b.com's) origin should be replicated as part of
// mojom::Renderer::CreateFrameProxy sent for b.com's frame in c.com's
// process.
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- middle_child,
- "window.domAutomationController.send(location.ancestorOrigins.length);",
- &ancestor_origins_length));
- EXPECT_EQ(2, ancestor_origins_length);
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- middle_child,
- "window.domAutomationController.send(location.ancestorOrigins[0]);",
- &result));
- EXPECT_EQ(b_origin, result + "/");
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- middle_child,
- "window.domAutomationController.send(location.ancestorOrigins[1]);",
- &result));
- EXPECT_EQ(a_origin, result + "/");
+ EXPECT_EQ(ListValueOf(b_origin, a_origin),
+ EvalJs(middle_child, "Array.from(location.ancestorOrigins);"));
// Check that the nested a.com frame's location.ancestorOrigins contains the
// correct origin for its three ancestors.
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- lowest_child,
- "window.domAutomationController.send(location.ancestorOrigins.length);",
- &ancestor_origins_length));
- EXPECT_EQ(3, ancestor_origins_length);
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- lowest_child,
- "window.domAutomationController.send(location.ancestorOrigins[0]);",
- &result));
- EXPECT_EQ(c_origin, result + "/");
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- lowest_child,
- "window.domAutomationController.send(location.ancestorOrigins[1]);",
- &result));
- EXPECT_EQ(b_origin, result + "/");
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- lowest_child,
- "window.domAutomationController.send(location.ancestorOrigins[2]);",
- &result));
- EXPECT_EQ(a_origin, result + "/");
+ EXPECT_EQ(ListValueOf(c_origin, b_origin, a_origin),
+ EvalJs(lowest_child, "Array.from(location.ancestorOrigins);"));
}
// Test that HasReceivedUserGesture and HasReceivedUserGestureBeforeNavigation
@@ -3969,6 +4013,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcesScrollAnchorTest,
// Check that iframe sandbox flags are replicated correctly.
IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SandboxFlagsReplication) {
GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
+ const url::Origin main_origin = url::Origin::Create(main_url);
EXPECT_TRUE(NavigateToURL(shell(), main_url));
// It is safe to obtain the root frame tree node here, as it doesn't change.
@@ -3995,72 +4040,34 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SandboxFlagsReplication) {
EXPECT_EQ(bar_url, observer.last_navigation_url());
// Opening a popup in the sandboxed foo.com iframe should fail.
- bool success = false;
- EXPECT_TRUE(
- ExecuteScriptAndExtractBool(root->child_at(1),
- "window.domAutomationController.send("
- "!window.open('data:text/html,dataurl'));",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(false, EvalJs(root->child_at(1),
+ "!!window.open('data:text/html,dataurl');"));
EXPECT_EQ(1u, Shell::windows().size());
// Opening a popup in a frame whose parent is sandboxed should also fail.
// Here, bar.com frame's sandboxed parent frame is a remote frame in
// bar.com's process.
- success = false;
- EXPECT_TRUE(
- ExecuteScriptAndExtractBool(root->child_at(1)->child_at(0),
- "window.domAutomationController.send("
- "!window.open('data:text/html,dataurl'));",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(false, EvalJs(root->child_at(1)->child_at(0),
+ "!!window.open('data:text/html,dataurl');"));
EXPECT_EQ(1u, Shell::windows().size());
// Same, but now try the case where bar.com frame's sandboxed parent is a
// local frame in bar.com's process.
- success = false;
- EXPECT_TRUE(
- ExecuteScriptAndExtractBool(root->child_at(2)->child_at(0),
- "window.domAutomationController.send("
- "!window.open('data:text/html,dataurl'));",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(false, EvalJs(root->child_at(2)->child_at(0),
+ "!!window.open('data:text/html,dataurl');"));
EXPECT_EQ(1u, Shell::windows().size());
// Check that foo.com frame's location.ancestorOrigins contains the correct
// origin for the parent, which should be unaffected by sandboxing.
- int ancestor_origins_length = 0;
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- root->child_at(1),
- "window.domAutomationController.send(location.ancestorOrigins.length);",
- &ancestor_origins_length));
- EXPECT_EQ(1, ancestor_origins_length);
- std::string result;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- root->child_at(1),
- "window.domAutomationController.send(location.ancestorOrigins[0]);",
- &result));
- EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
+ EXPECT_EQ(ListValueOf(main_origin),
+ EvalJs(root->child_at(1), "Array.from(location.ancestorOrigins);"));
// Now check location.ancestorOrigins for the bar.com frame. The middle frame
// (foo.com's) origin should be unique, since that frame is sandboxed, and
// the top frame should match |main_url|.
- FrameTreeNode* bottom_child = root->child_at(1)->child_at(0);
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- bottom_child,
- "window.domAutomationController.send(location.ancestorOrigins.length);",
- &ancestor_origins_length));
- EXPECT_EQ(2, ancestor_origins_length);
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- bottom_child,
- "window.domAutomationController.send(location.ancestorOrigins[0]);",
- &result));
- EXPECT_EQ("null", result);
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- bottom_child,
- "window.domAutomationController.send(location.ancestorOrigins[1]);",
- &result));
- EXPECT_EQ(main_url.GetOrigin().spec(), result + "/");
+ EXPECT_EQ(ListValueOf("null", main_origin),
+ EvalJs(root->child_at(1)->child_at(0),
+ "Array.from(location.ancestorOrigins);"));
}
// Check that dynamic updates to iframe sandbox flags are propagated correctly.
@@ -4141,13 +4148,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicSandboxFlags) {
root->child_at(0)->effective_frame_policy().sandbox_flags);
// Opening a popup in the now-sandboxed frame should fail.
- bool success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- root->child_at(0),
- "window.domAutomationController.send("
- " !window.open('data:text/html,dataurl'));",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(false, EvalJs(root->child_at(0),
+ "!!window.open('data:text/html,dataurl');"));
EXPECT_EQ(1u, Shell::windows().size());
// Navigate the child of the now-sandboxed frame to a page on baz.com. The
@@ -4171,13 +4173,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicSandboxFlags) {
DepictFrameTree(root));
// Opening a popup in the child of a sandboxed frame should fail.
- success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- root->child_at(0)->child_at(0),
- "window.domAutomationController.send("
- " !window.open('data:text/html,dataurl'));",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(false, EvalJs(root->child_at(0)->child_at(0),
+ "!!window.open('data:text/html,dataurl');"));
EXPECT_EQ(1u, Shell::windows().size());
// Child of a sandboxed frame should also be sandboxed on the browser side.
@@ -4235,24 +4232,14 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
root->child_at(1)->effective_frame_policy().sandbox_flags);
// Opening a popup in the sandboxed second frame should fail.
- bool success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- root->child_at(1),
- "window.domAutomationController.send("
- " !window.open('data:text/html,dataurl'));",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(false, EvalJs(root->child_at(1),
+ "!!window.open('data:text/html,dataurl');"));
EXPECT_EQ(1u, Shell::windows().size());
// Make sure that the child frame inherits the sandbox flags of its
// now-sandboxed parent frame.
- success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- root->child_at(1)->child_at(0),
- "window.domAutomationController.send("
- " !window.open('data:text/html,dataurl'));",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(false, EvalJs(root->child_at(1)->child_at(0),
+ "!!window.open('data:text/html,dataurl');"));
EXPECT_EQ(1u, Shell::windows().size());
}
@@ -4314,13 +4301,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
root->child_at(0)->effective_frame_policy().sandbox_flags);
// Opening a popup in the now-sandboxed frame should fail.
- bool success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- root->child_at(0),
- "window.domAutomationController.send("
- " !window.open('data:text/html,dataurl'));",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(false, EvalJs(root->child_at(0),
+ "!!window.open('data:text/html,dataurl');"));
EXPECT_EQ(1u, Shell::windows().size());
}
@@ -4382,18 +4364,8 @@ IN_PROC_BROWSER_TEST_F(
// Use location.ancestorOrigins to check that the grandchild on baz.com sees
// correct origin for its parent.
- int ancestor_origins_length = 0;
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- bottom_child,
- "window.domAutomationController.send(location.ancestorOrigins.length);",
- &ancestor_origins_length));
- EXPECT_EQ(2, ancestor_origins_length);
- std::string parent_origin;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- bottom_child,
- "window.domAutomationController.send(location.ancestorOrigins[0]);",
- &parent_origin));
- EXPECT_EQ(main_url.GetOrigin().spec(), parent_origin + "/");
+ EXPECT_EQ(ListValueOf(url::Origin::Create(main_url)),
+ EvalJs(bottom_child, "Array.from(location.ancestorOrigins);"));
// Check that the sandbox flags in the browser process are correct.
// "allow-scripts" resets both WebSandboxFlags::Scripts and
@@ -4409,13 +4381,8 @@ IN_PROC_BROWSER_TEST_F(
// should not be able to create popups.
EXPECT_EQ(expected_flags,
bottom_child->effective_frame_policy().sandbox_flags);
- bool success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- bottom_child,
- "window.domAutomationController.send("
- " !window.open('data:text/html,dataurl'));",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(false,
+ EvalJs(bottom_child, "!!window.open('data:text/html,dataurl')"));
EXPECT_EQ(1u, Shell::windows().size());
}
@@ -4442,11 +4409,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, WindowNameReplication) {
// Check that the window.name seen by the frame matches the name attribute
// specified by its parent in the iframe tag.
- std::string result;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- root->child_at(0), "window.domAutomationController.send(window.name);",
- &result));
- EXPECT_EQ("3-1-name", result);
+ EXPECT_EQ("3-1-name", EvalJs(root->child_at(0), "window.name;"));
}
// Verify that dynamic updates to a frame's window.name propagate to the
@@ -4480,26 +4443,15 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicWindowName) {
// The proxy in the parent process should also receive the updated name.
// Now iframe's name and the content window's name differ, so it shouldn't
// be possible to access to the content window with the updated name.
- bool success = false;
- EXPECT_TRUE(
- ExecuteScriptAndExtractBool(shell(),
- "window.domAutomationController.send("
- " frames['updated-name'] === undefined);",
- &success));
- // TODO(yukishiino): The following expectation should be TRUE, but we're
+ //
+ // TODO(yukishiino): The following expectation should be |true|, but we're
// intentionally disabling the name and origin check of the named access on
// window. See also crbug.com/538562 and crbug.com/701489.
- EXPECT_FALSE(success);
+ EXPECT_EQ(false, EvalJs(shell(), "frames['updated-name'] === undefined;"));
// Change iframe's name to match the content window's name so that it can
// reference the child frame by its new name in case of cross origin.
EXPECT_TRUE(ExecuteScript(root, "window['3-1-id'].name = 'updated-name';"));
- success = false;
- EXPECT_TRUE(
- ExecuteScriptAndExtractBool(shell(),
- "window.domAutomationController.send("
- " frames['updated-name'] == frames[0]);",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(true, EvalJs(shell(), "frames['updated-name'] == frames[0];"));
// Issue a renderer-initiated navigation from the root frame to the child
// frame using the frame's name. Make sure correct frame is navigated.
@@ -4925,26 +4877,9 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, IndexedFrameAccess) {
DepictFrameTree(root));
// Check that each subframe sees itself at correct index in parent.frames.
- bool success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- child0,
- "window.domAutomationController.send(window === parent.frames[0]);",
- &success));
- EXPECT_TRUE(success);
-
- success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- child1,
- "window.domAutomationController.send(window === parent.frames[1]);",
- &success));
- EXPECT_TRUE(success);
-
- success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- child2,
- "window.domAutomationController.send(window === parent.frames[2]);",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(true, EvalJs(child0, "window === parent.frames[0];"));
+ EXPECT_EQ(true, EvalJs(child1, "window === parent.frames[1];"));
+ EXPECT_EQ(true, EvalJs(child2, "window === parent.frames[2];"));
// Send a postMessage from B to parent.frames[1], which should go to C, and
// wait for reply.
@@ -5059,12 +4994,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OpenPopupWithRemoteParent) {
->root();
EXPECT_EQ(root->child_at(0), popup_root->opener());
- std::string opener_url;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- popup_root,
- "window.domAutomationController.send(window.opener.location.href);",
- &opener_url));
- EXPECT_EQ(frame_url.spec(), opener_url);
+ EXPECT_EQ(frame_url.spec(),
+ EvalJs(popup_root, "window.opener.location.href;"));
// Now try the same with a cross-site popup and make sure it ends up in a new
// process and with a correct opener.
@@ -5087,13 +5018,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OpenPopupWithRemoteParent) {
// Ensure the popup's window.opener points to the right subframe. Note that
// we can't check the opener's location as above since it's cross-origin.
- bool success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- cross_site_popup_root,
- "window.domAutomationController.send("
- " window.opener === window.opener.top.frames[0]);",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(true, EvalJs(cross_site_popup_root,
+ "window.opener === window.opener.top.frames[0];"));
}
// Test that cross-process popups can't be navigated to disallowed URLs by
@@ -5271,45 +5197,27 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, UpdateSubframeOpener) {
// Update the popup's opener to the second subframe on the main page (which
// is same-origin with the top frame, i.e., foo.com).
- bool success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- root->child_at(1),
- "window.domAutomationController.send(!!window.open('','popup'));",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(true, EvalJs(root->child_at(1), "!!window.open('','popup');"));
// Check that updated opener propagated to the browser process and the
// popup's bar.com process.
EXPECT_EQ(root->child_at(1), popup_root->opener());
- success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- popup_shell,
- "window.domAutomationController.send("
- " window.opener === window.opener.parent.frames['frame2']);",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(true,
+ EvalJs(popup_shell,
+ "window.opener === window.opener.parent.frames['frame2'];"));
// Now update opener on the popup's second subframe (foo.com) to the main
// page's first subframe (bar.com).
- success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- root->child_at(0),
- "window.domAutomationController.send(!!window.open('','subframe2'));",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(true, EvalJs(root->child_at(0), "!!window.open('','subframe2');"));
// Check that updated opener propagated to the browser process and the
// foo.com process.
EXPECT_EQ(root->child_at(0), popup_root->child_at(1)->opener());
- success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- popup_root->child_at(1),
- "window.domAutomationController.send("
- " window.opener === window.opener.parent.frames['frame1']);",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(true,
+ EvalJs(popup_root->child_at(1),
+ "window.opener === window.opener.parent.frames['frame1'];"));
}
// Check that when a subframe navigates to a new SiteInstance, the new
@@ -5343,19 +5251,12 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// Check that the new subframe process still sees correct opener for its
// parent by sending a postMessage to subframe's parent.opener.
- bool success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- popup_root->child_at(0),
- "window.domAutomationController.send(!!parent.opener);", &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(true, EvalJs(popup_root->child_at(0), "!!parent.opener;"));
base::string16 expected_title = base::ASCIIToUTF16("msg");
TitleWatcher title_watcher(shell()->web_contents(), expected_title);
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- popup_root->child_at(0),
- "window.domAutomationController.send(postToOpenerOfParent('msg','*'));",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(true, EvalJs(popup_root->child_at(0),
+ "postToOpenerOfParent('msg','*');"));
EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
}
@@ -5376,47 +5277,30 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigateSubframeWithOpener) {
DepictFrameTree(root));
// Update the first (cross-site) subframe's opener to root frame.
- bool success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- root, "window.domAutomationController.send(!!window.open('','frame1'));",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(true, EvalJs(root, "!!window.open('','frame1');"));
// Check that updated opener propagated to the browser process and subframe's
// process.
EXPECT_EQ(root, root->child_at(0)->opener());
- success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- root->child_at(0),
- "window.domAutomationController.send(window.opener === window.parent);",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(true,
+ EvalJs(root->child_at(0), "window.opener === window.parent;"));
// Navigate the subframe with opener to another site.
GURL frame_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
NavigateFrameToURL(root->child_at(0), frame_url);
// Check that the subframe still sees correct opener in its new process.
- success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- root->child_at(0),
- "window.domAutomationController.send(window.opener === window.parent);",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(true,
+ EvalJs(root->child_at(0), "window.opener === window.parent;"));
// Navigate second subframe to a new site. Check that the proxy that's
// created for the first subframe in the new SiteInstance has correct opener.
GURL frame2_url(embedded_test_server()->GetURL("qux.com", "/title1.html"));
NavigateFrameToURL(root->child_at(1), frame2_url);
- success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- root->child_at(1),
- "window.domAutomationController.send("
- " parent.frames['frame1'].opener === parent);",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(true, EvalJs(root->child_at(1),
+ "parent.frames['frame1'].opener === parent;"));
}
// Check that if a subframe has an opener, that opener is preserved when a new
@@ -5452,24 +5336,15 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// Update the popup's second subframe's opener to root frame. This is
// allowed because that subframe is in the same foo.com SiteInstance as the
// root frame.
- bool success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- root,
- "window.domAutomationController.send(!!window.open('','subframe2'));",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(true, EvalJs(root, "!!window.open('','subframe2');"));
// Check that the opener update propagated to the browser process and bar.com
// process.
EXPECT_EQ(root, popup_root->child_at(1)->opener());
- success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- popup_root->child_at(0),
- "window.domAutomationController.send("
- " parent.frames['subframe2'].opener && "
- " parent.frames['subframe2'].opener === parent.opener);",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(true,
+ EvalJs(popup_root->child_at(0),
+ "parent.frames['subframe2'].opener && "
+ " parent.frames['subframe2'].opener === parent.opener;"));
// Navigate the popup's first subframe to another site.
GURL frame_url(
@@ -5478,23 +5353,15 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// Check that the second subframe's opener is still correct in the first
// subframe's new process. Verify it both in JS and with a postMessage.
- success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- popup_root->child_at(0),
- "window.domAutomationController.send("
- " parent.frames['subframe2'].opener && "
- " parent.frames['subframe2'].opener === parent.opener);",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(true,
+ EvalJs(popup_root->child_at(0),
+ "parent.frames['subframe2'].opener && "
+ " parent.frames['subframe2'].opener === parent.opener;"));
base::string16 expected_title = base::ASCIIToUTF16("msg");
TitleWatcher title_watcher(shell()->web_contents(), expected_title);
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- popup_root->child_at(0),
- "window.domAutomationController.send("
- " postToOpenerOfSibling('subframe2', 'msg', '*'));",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(true, EvalJs(popup_root->child_at(0),
+ "postToOpenerOfSibling('subframe2', 'msg', '*');"));
EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
}
@@ -5542,19 +5409,13 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// RenderFrameHost should be pending deletion after the last navigation.
EXPECT_FALSE(rfh->is_active());
- // Wait for process A to exit so we can reinitialize it cleanly for the next
- // navigation. Since process A doesn't have any active views, it will
- // initiate shutdown via ChildProcessHostMsg_ShutdownRequest. After process
- // A shuts down, the |rfh| and |rvh| should get destroyed via
- // OnRenderProcessGone.
- //
- // Not waiting for process shutdown here could lead to the |rvh| being
- // reused, now that there is no notion of pending deletion RenderViewHosts.
- // This would also be fine; however, the race in https://crbug.com/535246
- // still needs to be addressed and tested in that case.
- RenderProcessHostWatcher process_exit_observer(
- rvh->GetProcess(), RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
- process_exit_observer.Wait();
+ // Without the SwapOut ACK and timer, the process A will never shutdown.
+ // Simulate the process being killed now.
+ content::RenderProcessHostWatcher crash_observer(
+ rvh->GetProcess(),
+ content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+ EXPECT_TRUE(rvh->GetProcess()->Shutdown(0));
+ crash_observer.Wait();
// Verify that the RVH and RFH for A were cleaned up.
EXPECT_FALSE(root->frame_tree()->GetRenderViewHost(site_instance));
@@ -5702,11 +5563,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DocumentActiveElement) {
const std::string& property,
const std::string& expected_value) {
std::string script = base::StringPrintf(
- "window.domAutomationController.send(document.activeElement.%s);",
- property.c_str());
- std::string result;
- EXPECT_TRUE(ExecuteScriptAndExtractString(rfh, script, &result));
- EXPECT_EQ(expected_value, base::ToLowerASCII(result));
+ "document.activeElement.%s.toLowerCase();", property.c_str());
+ EXPECT_EQ(expected_value, EvalJs(rfh, script));
};
// Verify that document.activeElement on main frame points to the <iframe>
@@ -5764,17 +5622,33 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SubframeWindowFocus) {
// The main frame should be focused to start with.
EXPECT_EQ(root, root->frame_tree()->GetFocusedFrame());
- DOMMessageQueue msg_queue;
-
// Register focus and blur events that will send messages when each frame's
- // window gets or loses focus.
- const char kSetupFocusEvents[] =
- "window.addEventListener('focus', function() {"
- " domAutomationController.send('%s-got-focus');"
- "});"
- "window.addEventListener('blur', function() {"
- " domAutomationController.send('%s-lost-focus');"
- "});";
+ // window gets or loses focus, and configure some utility functions useful for
+ // waiting for these messages.
+ const char kSetupFocusEvents[] = R"(
+ window.addEventListener('focus', function() {
+ window.top.postMessage('%s-got-focus', '*');
+ });
+ window.addEventListener('blur', function() {
+ window.top.postMessage('%s-lost-focus', '*');
+ });
+ function onEvent(target, eventName, property, value) {
+ return new Promise((resolve, reject) => {
+ function listener(event) {
+ if (event[property] == value) {
+ resolve();
+ target.removeEventListener(eventName, listener);
+ }
+ };
+ target.addEventListener(eventName, listener);
+ });
+ }
+ function expectMessages(messageList) {
+ var promiseList = messageList.map(
+ (dataValue) => onEvent(window, 'message', 'data', dataValue));
+ return Promise.all(promiseList);
+ }
+ )";
std::string script = base::StringPrintf(kSetupFocusEvents, "main", "main");
ExecuteScriptAsync(shell(), script);
script = base::StringPrintf(kSetupFocusEvents, "child1", "child1");
@@ -5783,51 +5657,52 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SubframeWindowFocus) {
ExecuteScriptAsync(child2, script);
// Execute window.focus on the B subframe from the A main frame.
- ExecuteScriptAsync(root, "frames[0].focus()");
-
- // Helper to wait for two specified messages to arrive on the specified
- // DOMMessageQueue, assuming that the two messages can arrive in any order.
- auto wait_for_two_messages = [](DOMMessageQueue* msg_queue,
- const std::string& msg1,
- const std::string& msg2) {
- bool msg1_received = false;
- bool msg2_received = false;
- std::string status;
- while (msg_queue->WaitForMessage(&status)) {
- if (status == msg1)
- msg1_received = true;
- if (status == msg2)
- msg2_received = true;
- if (msg1_received && msg2_received)
- break;
- }
- };
-
// Process A should fire a blur event, and process B should fire a focus
// event. Wait for both events.
- wait_for_two_messages(&msg_queue, "\"main-lost-focus\"",
- "\"child1-got-focus\"");
+ EXPECT_EQ(true, EvalJs(root, R"((async function() {
+ allMessages = [];
+ window.addEventListener('message', (event) => {
+ allMessages.push(event.data);
+ });
+
+ var messages = expectMessages(['main-lost-focus', 'child1-got-focus']);
+ frames[0].focus();
+ await messages;
+
+ return allMessages.length == 2 || allMessages;
+ })())"));
- // The B subframe should now be focused in the browser process.
EXPECT_EQ(child1, root->frame_tree()->GetFocusedFrame());
// Now, execute window.focus on the C subframe from A main frame. This
// checks that we can shift focus from one remote frame to another.
- ExecuteScriptAsync(root, "frames[1].focus()");
-
+ //
// Wait for the two subframes (B and C) to fire blur and focus events.
- wait_for_two_messages(&msg_queue, "\"child1-lost-focus\"",
- "\"child2-got-focus\"");
+ EXPECT_EQ(true, EvalJs(root, R"((async function() {
+ var messages = expectMessages(['child1-lost-focus', 'child2-got-focus']);
+ frames[1].focus();
+ await messages;
+ return allMessages.length == 4 || allMessages;
+ })())"));
// The C subframe should now be focused.
EXPECT_EQ(child2, root->frame_tree()->GetFocusedFrame());
+ // Install event listeners in the A main frame, expecting the main frame to
+ // obtain focus.
+ EXPECT_TRUE(
+ ExecJs(root,
+ "var messages = "
+ " expectMessages(['child2-lost-focus', 'main-got-focus']);"));
+
// window.focus the main frame from the C subframe.
ExecuteScriptAsync(child2, "parent.focus()");
- // Wait for the C subframe to blur and main frame to focus.
- wait_for_two_messages(&msg_queue, "\"child2-lost-focus\"",
- "\"main-got-focus\"");
+ // Wait for the messages to arrive in the A main frame.
+ EXPECT_EQ(true, EvalJs(root, R"((async function() {
+ await messages;
+ return allMessages.length == 6 || allMessages;
+ })())"));
// The main frame should now be focused.
EXPECT_EQ(root, root->frame_tree()->GetFocusedFrame());
@@ -5928,10 +5803,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// Make sure the main frame renderer does not crash and ignores the
// navigation to the frame that's already been deleted.
- int child_count = 0;
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- root, "domAutomationController.send(frames.length)", &child_count));
- EXPECT_EQ(1, child_count);
+ EXPECT_EQ(1, EvalJs(root, "frames.length"));
}
// Test for a variation of https://crbug.com/526304, where a child frame does a
@@ -5967,10 +5839,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
EXPECT_EQ(1U, root->child_count());
// Make sure the a.com renderer does not crash.
- int child_count = 0;
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- root, "domAutomationController.send(frames.length)", &child_count));
- EXPECT_EQ(1, child_count);
+ EXPECT_EQ(1, EvalJs(root, "frames.length;"));
}
// Similar to NavigateProxyAndDetachBeforeCommit, but uses a synchronous
@@ -5997,10 +5866,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigateAboutBlankAndDetach) {
observer.Wait();
// Make sure the a.com renderer does not crash and the frame is removed.
- int child_count = 0;
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- root, "domAutomationController.send(frames.length)", &child_count));
- EXPECT_EQ(0, child_count);
+ EXPECT_EQ(0, EvalJs(root, "frames.length;"));
}
// Test for https://crbug.com/568670. In A-embed-B, simultaneously have B
@@ -6051,10 +5917,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
EXPECT_EQ(0U, root->child_count());
// Make sure process A did not crash.
- int child_count = 0;
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- root, "domAutomationController.send(frames.length)", &child_count));
- EXPECT_EQ(0, child_count);
+ EXPECT_EQ(0, EvalJs(root, "frames.length;"));
}
// This test ensures that the RenderFrame isn't leaked in the renderer process
@@ -6609,7 +6472,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// Check that the grandchild frame isn't sandboxed on the renderer side. If
// sandboxed, its origin would be unique ("null").
- EXPECT_EQ(frame_url.GetOrigin().spec(), GetDocumentOrigin(grandchild) + "/");
+ std::string expected_origin = url::Origin::Create(frame_url).Serialize();
+ EXPECT_EQ(expected_origin, GetDocumentOrigin(grandchild));
}
// Verify that popups opened from sandboxed frames inherit sandbox flags from
@@ -6755,11 +6619,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
foo_root->effective_frame_policy().sandbox_flags);
// The popup's origin should match |b_url|, since it's not sandboxed.
- std::string popup_origin;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- foo_root, "domAutomationController.send(document.origin)",
- &popup_origin));
- EXPECT_EQ(b_url.GetOrigin().spec(), popup_origin + "/");
+ EXPECT_EQ(url::Origin::Create(b_url).Serialize(),
+ EvalJs(foo_root, "document.origin;"));
}
// Tests that the WebContents is notified when passive mixed content is
@@ -6993,29 +6854,53 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
"document.querySelector('iframe').onload = "
" function() { document.title = 'loaded'; };"));
- GURL blocked_urls[] = {
- embedded_test_server()->GetURL("b.com", "/frame-ancestors-none.html"),
- embedded_test_server()->GetURL("b.com", "/x-frame-options-deny.html")
+ const struct {
+ const char* url;
+ bool use_error_page;
+ } kTestCases[] = {
+ {"/frame-ancestors-none.html", false},
+ {"/x-frame-options-deny.html", true},
};
- for (size_t i = 0; i < arraysize(blocked_urls); ++i) {
+ for (const auto& test : kTestCases) {
+ GURL blocked_url = embedded_test_server()->GetURL("b.com", test.url);
EXPECT_TRUE(ExecuteScript(shell(), "document.title = 'not loaded';"));
base::string16 expected_title(base::UTF8ToUTF16("loaded"));
TitleWatcher title_watcher(shell()->web_contents(), expected_title);
// Navigate the subframe to a blocked URL.
TestNavigationObserver load_observer(shell()->web_contents());
- EXPECT_TRUE(ExecuteScript(shell(), "frames[0].location.href = '" +
- blocked_urls[i].spec() + "';"));
+ EXPECT_TRUE(ExecuteScript(
+ shell(), "frames[0].location.href = '" + blocked_url.spec() + "';"));
load_observer.Wait();
// The blocked frame's origin should become unique.
EXPECT_EQ("null", root->child_at(0)->current_origin().Serialize());
- // Ensure that we don't use the blocked URL as the blocked frame's last
- // committed URL (see https://crbug.com/622385).
- EXPECT_NE(root->child_at(0)->current_frame_host()->GetLastCommittedURL(),
- blocked_urls[i]);
+ // X-Frame-Options and CSP frame-ancestors behave differently. XFO commits
+ // an error page, while CSP commits a "data:," URL.
+ // TODO(https://crbug.com/870815): Use an error page for both.
+ if (test.use_error_page) {
+ EXPECT_FALSE(load_observer.last_navigation_succeeded());
+ EXPECT_EQ(net::ERR_BLOCKED_BY_RESPONSE,
+ load_observer.last_net_error_code());
+ EXPECT_EQ(root->child_at(0)->current_frame_host()->GetLastCommittedURL(),
+ blocked_url);
+ EXPECT_EQ("Error", EvalJs(root->child_at(0), "document.title"));
+ } else {
+ EXPECT_TRUE(load_observer.last_navigation_succeeded());
+ EXPECT_EQ(net::OK, load_observer.last_net_error_code());
+ // Ensure that we don't use the blocked URL as the blocked frame's last
+ // committed URL (see https://crbug.com/622385).
+ EXPECT_EQ(root->child_at(0)->current_frame_host()->GetLastCommittedURL(),
+ GURL("data:,"));
+
+ // The blocked navigation should behave like an empty 200 response. Make
+ // sure that the frame's document.title is empty: this double-checks both
+ // that the blocked URL's contents wasn't loaded, and that the old page
+ // isn't active anymore (both of these pages have non-empty titles).
+ EXPECT_EQ("", EvalJs(root->child_at(0), "document.title"));
+ }
// The blocked frame should still fire a load event in its parent's process.
EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
@@ -7023,16 +6908,6 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// Check that the current RenderFrameHost has stopped loading.
EXPECT_FALSE(root->child_at(0)->current_frame_host()->is_loading());
- // The blocked navigation should behave like an empty 200 response. Make
- // sure that the frame's document.title is empty: this double-checks both
- // that the blocked URL's contents wasn't loaded, and that the old page
- // isn't active anymore (both of these pages have non-empty titles).
- std::string frame_title;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- root->child_at(0), "domAutomationController.send(document.title)",
- &frame_title));
- EXPECT_EQ("", frame_title);
-
// Navigate the subframe to another cross-origin page and ensure that this
// navigation succeeds. Use a renderer-initiated navigation to test the
// transfer logic, which used to have some issues with this.
@@ -7103,19 +6978,11 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// The page should get the title of an error page (i.e "Error") and not the
// title of the blocked page.
- std::string frame_title;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- root->child_at(0), "domAutomationController.send(document.title)",
- &frame_title));
- EXPECT_EQ("Error", frame_title);
+ EXPECT_EQ("Error", EvalJs(root->child_at(0), "document.title"));
// Navigate to a URL without CSP.
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
-
- // Verify that the frame's CSP got correctly reset to an empty set.
- EXPECT_EQ(0u,
- root->current_replication_state().accumulated_csp_headers.size());
}
// Test that a cross-origin frame's navigation can be blocked by CSP frame-src.
@@ -7135,12 +7002,12 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
NavigateFrameToURL(root->child_at(0), old_subframe_url);
// Add frame-src CSP via a new <meta> element.
- EXPECT_TRUE(ExecuteScript(
- shell(),
- "var meta = document.createElement('meta');"
- "meta.httpEquiv = 'Content-Security-Policy';"
- "meta.content = 'frame-src https://a.com:*';"
- "document.getElementsByTagName('head')[0].appendChild(meta);"));
+ EXPECT_TRUE(
+ ExecJs(shell(),
+ "var meta = document.createElement('meta');"
+ "meta.httpEquiv = 'Content-Security-Policy';"
+ "meta.content = 'frame-src https://a.com:*';"
+ "document.getElementsByTagName('head')[0].appendChild(meta);"));
// Sanity-check that the test page has the expected shape for testing.
// (the CSP should not have an effect on the already loaded frames).
@@ -7152,18 +7019,18 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
EXPECT_EQ("frame-src https://a.com:*", root_csp[0].header_value);
// Monitor subframe's load events via main frame's title.
- EXPECT_TRUE(ExecuteScript(shell(),
- "document.querySelector('iframe').onload = "
- " function() { document.title = 'loaded'; };"));
- EXPECT_TRUE(ExecuteScript(shell(), "document.title = 'not loaded';"));
+ EXPECT_TRUE(ExecJs(shell(),
+ "document.querySelector('iframe').onload = "
+ " function() { document.title = 'loaded'; };"));
+ EXPECT_TRUE(ExecJs(shell(), "document.title = 'not loaded';"));
base::string16 expected_title(base::UTF8ToUTF16("loaded"));
TitleWatcher title_watcher(shell()->web_contents(), expected_title);
// Try to navigate the subframe to a blocked URL.
TestNavigationObserver load_observer2(shell()->web_contents());
GURL blocked_url = embedded_test_server()->GetURL("c.com", "/title3.html");
- EXPECT_TRUE(ExecuteScript(root->child_at(0), "window.location.href = '" +
- blocked_url.spec() + "';"));
+ EXPECT_TRUE(ExecJs(root->child_at(0),
+ JsReplace("window.location.href = $1;", blocked_url)));
// The blocked frame should still fire a load event in its parent's process.
EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
@@ -7182,11 +7049,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// The page should get the title of an error page (i.e "Error") and not the
// title of the blocked page.
- std::string frame_title;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- root->child_at(0), "domAutomationController.send(document.title)",
- &frame_title));
- EXPECT_EQ("Error", frame_title);
+ EXPECT_EQ("Error", EvalJs(root->child_at(0), "document.title"));
}
// Test that a cross-origin frame's navigation can be blocked by CSP frame-src.
@@ -7219,24 +7082,23 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// Monitor navigating_frame's load events via srcdoc_frame posting
// a message to the parent frame.
+ EXPECT_TRUE(ExecJs(root,
+ "window.addEventListener('message', function(event) {"
+ " document.title = event.data;"
+ "});"));
EXPECT_TRUE(
- ExecuteScript(root,
- "window.addEventListener('message', function(event) {"
- " document.title = event.data;"
- "});"));
- EXPECT_TRUE(ExecuteScript(
- srcdoc_frame,
- "document.querySelector('iframe').onload = "
- " function() { window.top.postMessage('loaded', '*'); };"));
- EXPECT_TRUE(ExecuteScript(shell(), "document.title = 'not loaded';"));
+ ExecJs(srcdoc_frame,
+ "document.querySelector('iframe').onload = "
+ " function() { window.top.postMessage('loaded', '*'); };"));
+ EXPECT_TRUE(ExecJs(shell(), "document.title = 'not loaded';"));
base::string16 expected_title(base::UTF8ToUTF16("loaded"));
TitleWatcher title_watcher(shell()->web_contents(), expected_title);
// Try to navigate the subframe to a blocked URL.
TestNavigationObserver load_observer2(shell()->web_contents());
GURL blocked_url = embedded_test_server()->GetURL("c.com", "/title3.html");
- EXPECT_TRUE(ExecuteScript(navigating_frame, "window.location.href = '" +
- blocked_url.spec() + "';"));
+ EXPECT_TRUE(ExecJs(navigating_frame,
+ JsReplace("window.location.href = $1;", blocked_url)));
// The blocked frame should still fire a load event in its parent's process.
EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
@@ -7255,11 +7117,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// The page should get the title of an error page (i.e "Error") and not the
// title of the blocked page.
- std::string frame_title;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- navigating_frame, "domAutomationController.send(document.title)",
- &frame_title));
- EXPECT_EQ("Error", frame_title);
+ EXPECT_EQ("Error", EvalJs(navigating_frame, "document.title"));
// Navigate the subframe to a URL without CSP.
NavigateFrameToURL(srcdoc_frame,
@@ -7283,16 +7141,9 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, ScreenCoordinates) {
"outerHeight"};
for (const char* property : properties) {
- std::string script = "window.domAutomationController.send(window.";
- script += property;
- script += ");";
- int root_value = 1;
- int child_value = 2;
- EXPECT_TRUE(ExecuteScriptAndExtractInt(root, script.c_str(), &root_value));
-
- EXPECT_TRUE(
- ExecuteScriptAndExtractInt(child, script.c_str(), &child_value));
-
+ std::string script = base::StringPrintf("window.%s;", property);
+ int root_value = EvalJs(root, script).ExtractInt();
+ int child_value = EvalJs(child, script).ExtractInt();
EXPECT_EQ(root_value, child_value);
}
}
@@ -7337,28 +7188,6 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
EXPECT_FALSE(rvh->is_swapped_out_);
}
-// Helper class to wait for a ShutdownRequest message to arrive.
-class ShutdownObserver : public RenderProcessHostObserver {
- public:
- ShutdownObserver() : message_loop_runner_(new MessageLoopRunner) {}
-
- void RenderProcessShutdownRequested(RenderProcessHost* host) override {
- has_received_shutdown_request_ = true;
- message_loop_runner_->Quit();
- }
-
- void Wait() { message_loop_runner_->Run(); }
-
- bool has_received_shutdown_request() {
- return has_received_shutdown_request_;
- }
-
- private:
- scoped_refptr<MessageLoopRunner> message_loop_runner_;
- bool has_received_shutdown_request_ = false;
- DISALLOW_COPY_AND_ASSIGN(ShutdownObserver);
-};
-
// Test for https://crbug.com/568836. From an A-embed-B page, navigate the
// subframe from B to A. This cleans up the process for B, but the test delays
// the browser side from killing the B process right away. This allows the
@@ -7395,26 +7224,16 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// Navigate the subframe away from b.com. Since this is the last active
// frame in the b.com process, this causes the RenderWidget and RenderView to
- // be closed. If this succeeds without crashing, the renderer will release
- // the process and send a ShutdownRequest to the browser
- // process to ask whether it's ok to terminate. Thus, wait for this message
- // to ensure that the RenderView and widget were closed without crashing.
- ShutdownObserver shutdown_observer;
- subframe_process->AddObserver(&shutdown_observer);
+ // be closed.
NavigateFrameToURL(root->child_at(0),
embedded_test_server()->GetURL("a.com", "/title1.html"));
- shutdown_observer.Wait();
- subframe_process->RemoveObserver(&shutdown_observer);
-
- // TODO(alexmos): Navigating the subframe back to b.com at this point would
- // trigger the race in https://crbug.com/535246, where the browser process
- // tries to reuse the b.com process thinking it's still initialized, whereas
- // the process has actually been destroyed by the renderer (but the browser
- // process hasn't heard the OnChannelError yet). This race will need to be
- // fixed.
+ // Release the process.
+ RenderProcessHostWatcher process_shutdown_observer(
+ subframe_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
subframe_process->DecrementKeepAliveRefCount(
RenderProcessHostImpl::KeepAliveClientType::kFetch);
+ process_shutdown_observer.Wait();
}
// Tests that an input event targeted to a out-of-process iframe correctly
@@ -7839,11 +7658,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DetachInUnloadHandler) {
" B = http://b.com/",
DepictFrameTree(root));
- int child_count = 0;
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- root->child_at(0), "window.domAutomationController.send(frames.length);",
- &child_count));
- EXPECT_EQ(1, child_count);
+ EXPECT_EQ(1, EvalJs(root->child_at(0), "frames.length;"));
RenderFrameDeletedObserver deleted_observer(
root->child_at(0)->child_at(0)->current_frame_host());
@@ -7865,10 +7680,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DetachInUnloadHandler) {
deleted_observer.WaitUntilDeleted();
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- root->child_at(0), "window.domAutomationController.send(frames.length);",
- &child_count));
- EXPECT_EQ(0, child_count);
+ EXPECT_EQ(0, EvalJs(root->child_at(0), "frames.length;"));
EXPECT_EQ(
" Site A ------------ proxies for B\n"
@@ -7885,8 +7697,7 @@ class PendingWidgetMessageFilter : public BrowserMessageFilter {
public:
PendingWidgetMessageFilter()
: BrowserMessageFilter(kMessageClasses, arraysize(kMessageClasses)),
- routing_id_(MSG_ROUTING_NONE),
- message_loop_runner_(new MessageLoopRunner) {}
+ routing_id_(MSG_ROUTING_NONE) {}
bool OnMessageReceived(const IPC::Message& message) override {
bool handled = true;
@@ -7898,9 +7709,7 @@ class PendingWidgetMessageFilter : public BrowserMessageFilter {
return handled;
}
- void Wait() {
- message_loop_runner_->Run();
- }
+ void Wait() { run_loop_.Run(); }
int routing_id() { return routing_id_; }
@@ -7926,11 +7735,11 @@ class PendingWidgetMessageFilter : public BrowserMessageFilter {
void OnReceivedRoutingIDOnUI(int widget_routing_id) {
routing_id_ = widget_routing_id;
- message_loop_runner_->Quit();
+ run_loop_.Quit();
}
int routing_id_;
- scoped_refptr<MessageLoopRunner> message_loop_runner_;
+ base::RunLoop run_loop_;
DISALLOW_COPY_AND_ASSIGN(PendingWidgetMessageFilter);
};
@@ -7975,10 +7784,10 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// At this point, we should have two pending WebContents.
EXPECT_TRUE(base::ContainsKey(
web_contents()->pending_contents_,
- std::make_pair(process1->GetID(), filter1->routing_id())));
+ GlobalRoutingID(process1->GetID(), filter1->routing_id())));
EXPECT_TRUE(base::ContainsKey(
web_contents()->pending_contents_,
- std::make_pair(process2->GetID(), filter2->routing_id())));
+ GlobalRoutingID(process2->GetID(), filter2->routing_id())));
// Both subframes were set up in the same way, so the next routing ID for the
// new popup windows should match up (this led to the collision in the
@@ -8053,10 +7862,10 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// At this point, we should have two pending widgets.
EXPECT_TRUE(base::ContainsKey(
web_contents()->pending_widget_views_,
- std::make_pair(process1->GetID(), filter1->routing_id())));
+ GlobalRoutingID(process1->GetID(), filter1->routing_id())));
EXPECT_TRUE(base::ContainsKey(
web_contents()->pending_widget_views_,
- std::make_pair(process2->GetID(), filter2->routing_id())));
+ GlobalRoutingID(process2->GetID(), filter2->routing_id())));
// Both subframes were set up in the same way, so the next routing ID for the
// new popup widgets should match up (this led to the collision in the
@@ -8070,10 +7879,10 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
false, gfx::Rect());
EXPECT_FALSE(base::ContainsKey(
web_contents()->pending_widget_views_,
- std::make_pair(process1->GetID(), filter1->routing_id())));
+ GlobalRoutingID(process1->GetID(), filter1->routing_id())));
EXPECT_FALSE(base::ContainsKey(
web_contents()->pending_widget_views_,
- std::make_pair(process2->GetID(), filter2->routing_id())));
+ GlobalRoutingID(process2->GetID(), filter2->routing_id())));
}
#endif
@@ -8100,13 +7909,9 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, FileChooserInSubframe) {
// Also, extract the file from the renderer process to ensure that the
// response made it over successfully and the proper filename is set.
- std::string file_name;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- root->child_at(0),
- "window.domAutomationController.send("
- "document.getElementById('fileinput').files[0].name);",
- &file_name));
- EXPECT_EQ("bar", file_name);
+ EXPECT_EQ("bar",
+ EvalJs(root->child_at(0),
+ "document.getElementById('fileinput').files[0].name;"));
}
// Tests that an out-of-process iframe receives the visibilitychange event.
@@ -8126,26 +7931,19 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, VisibilityChange) {
" B = http://b.com/",
DepictFrameTree(root));
- EXPECT_TRUE(ExecuteScript(
- root->child_at(0)->current_frame_host(),
- "var event_fired = 0;\n"
- "document.addEventListener('visibilitychange',\n"
- " function() { event_fired++; });\n"));
+ EXPECT_TRUE(
+ ExecJs(root->child_at(0),
+ "var event_fired = 0;\n"
+ "document.addEventListener('visibilitychange',\n"
+ " function() { event_fired++; });\n"));
shell()->web_contents()->WasHidden();
- int event_fired = 0;
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- root->child_at(0)->current_frame_host(),
- "window.domAutomationController.send(event_fired);", &event_fired));
- EXPECT_EQ(1, event_fired);
+ EXPECT_EQ(1, EvalJs(root->child_at(0), "event_fired"));
shell()->web_contents()->WasShown();
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- root->child_at(0)->current_frame_host(),
- "window.domAutomationController.send(event_fired);", &event_fired));
- EXPECT_EQ(2, event_fired);
+ EXPECT_EQ(2, EvalJs(root->child_at(0), "event_fired"));
}
// Test that the pending RenderFrameHost is canceled and destroyed when its
@@ -8336,12 +8134,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SessionHistoryReplication) {
// Helper to retrieve the history length from a given frame.
auto history_length = [](FrameTreeNode* ftn) {
- int history_length = -1;
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- ftn->current_frame_host(),
- "window.domAutomationController.send(history.length);",
- &history_length));
- return history_length;
+ return EvalJs(ftn->current_frame_host(), "history.length;");
};
// All frames should see a history length of 1 to start with.
@@ -8484,11 +8277,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigateInUnloadHandler) {
" B = http://b.com/",
DepictFrameTree(root));
- int child_count = 0;
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- root->child_at(0)->current_frame_host(),
- "window.domAutomationController.send(frames.length);", &child_count));
- EXPECT_EQ(1, child_count);
+ EXPECT_EQ(1,
+ EvalJs(root->child_at(0)->current_frame_host(), "frames.length;"));
// Add an unload handler to B's subframe.
EXPECT_TRUE(
@@ -8514,10 +8304,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigateInUnloadHandler) {
// Check that C's subframe is alive and the navigation in the unload handler
// was ignored.
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- root->child_at(0)->child_at(0)->current_frame_host(),
- "window.domAutomationController.send(frames.length);", &child_count));
- EXPECT_EQ(0, child_count);
+ EXPECT_EQ(0, EvalJs(root->child_at(0)->child_at(0)->current_frame_host(),
+ "frames.length;"));
EXPECT_EQ(
" Site A ------------ proxies for B C\n"
@@ -8874,13 +8662,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessFeaturePolicyJavaScriptBrowserTest,
// feature. If its parent frame's policy was replicated correctly to the
// proxy, then this will be enabled. Otherwise, it will be disabled, as
// geolocation is disabled by default in cross-origin frames.
- bool success = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- root->child_at(1)->child_at(0),
- "window.domAutomationController.send("
- "document.policy.allowsFeature('geolocation'));",
- &success));
- EXPECT_TRUE(success);
+ EXPECT_EQ(true, EvalJs(root->child_at(1)->child_at(0),
+ "document.policy.allowsFeature('geolocation')"));
// Now navigate the iframe to a page with no policy, and the same nested
// cross-site iframe. The policy should be cleared in the proxy.
@@ -8893,13 +8676,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessFeaturePolicyJavaScriptBrowserTest,
// Ask the deepest iframe to report the enabled state of the geolocation
// feature. If its parent frame's policy was replicated correctly to the
// proxy, then this will now be disabled.
- success = true;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- root->child_at(1)->child_at(0),
- "window.domAutomationController.send("
- "document.policy.allowsFeature('geolocation'));",
- &success));
- EXPECT_FALSE(success);
+ EXPECT_EQ(false, EvalJs(root->child_at(1)->child_at(0),
+ "document.policy.allowsFeature('geolocation')"));
}
// Test that the constructed feature policy is correct in sandboxed
@@ -9096,18 +8874,10 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// Ensure the subframe is correctly attached in the frame tree, and that it
// has correct content.
- int child_count = 0;
- EXPECT_TRUE(ExecuteScriptAndExtractInt(
- root, "window.domAutomationController.send(frames.length);",
- &child_count));
- EXPECT_EQ(1, child_count);
+ EXPECT_EQ(1, EvalJs(root, "frames.length;"));
- std::string result;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- root,
- "window.domAutomationController.send(frames[0].document.body.innerText);",
- &result));
- EXPECT_EQ("This page has no title.", result);
+ EXPECT_EQ("This page has no title.",
+ EvalJs(root, "frames[0].document.body.innerText;"));
}
// Tests that trying to open a context menu in the old RFH after commiting a
@@ -9204,12 +8974,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// Helper to check if a frame is allowed to go fullscreen on the renderer
// side.
auto is_fullscreen_allowed = [](FrameTreeNode* ftn) {
- bool fullscreen_allowed = false;
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- ftn,
- "window.domAutomationController.send(document.webkitFullscreenEnabled)",
- &fullscreen_allowed));
- return fullscreen_allowed;
+ return EvalJs(ftn, "document.webkitFullscreenEnabled;");
};
// Load a page with an <iframe> without allowFullscreen.
@@ -9224,13 +8989,13 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// No change is expected to the container policy for dynamic modification of
// a loaded frame.
- EXPECT_FALSE(is_fullscreen_allowed(root->child_at(0)));
+ EXPECT_EQ(false, is_fullscreen_allowed(root->child_at(0)));
// Cross-site navigation should update the container policy in the new render
// frame.
NavigateFrameToURL(root->child_at(0),
embedded_test_server()->GetURL("c.com", "/title1.html"));
- EXPECT_TRUE(is_fullscreen_allowed(root->child_at(0)));
+ EXPECT_EQ(true, is_fullscreen_allowed(root->child_at(0)));
}
// Test that dynamic updates to iframe sandbox attribute correctly set the
@@ -9528,13 +9293,6 @@ class SitePerProcessAndroidImeTest : public SitePerProcessBrowserTest {
->ime_adapter_for_testing();
}
- std::string GetInputValue(RenderFrameHostImpl* frame) {
- std::string result;
- EXPECT_TRUE(ExecuteScriptAndExtractString(
- frame, "window.domAutomationController.send(input.value);", &result));
- return result;
- }
-
void FocusInputInFrame(RenderFrameHostImpl* frame) {
ASSERT_TRUE(ExecuteScript(frame, "window.focus(); input.focus();"));
}
@@ -9737,12 +9495,9 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, PostTargetSubFrame) {
// Verify that POST body was correctly passed to the server and ended up in
// the body of the page.
- std::string body;
- EXPECT_TRUE(ExecuteScriptAndExtractString(root->child_at(0), R"(
- var body = document.getElementsByTagName('pre')[0].innerText;
- window.domAutomationController.send(body);)",
- &body));
- EXPECT_EQ("my_token=my_value\n", body);
+ EXPECT_EQ("my_token=my_value\n",
+ EvalJs(root->child_at(0),
+ "document.getElementsByTagName('pre')[0].innerText;"));
}
// Tests that POST method and body is not lost when an OOPIF submits a form
@@ -9853,7 +9608,6 @@ class SetIsInertMessageFilter : public content::BrowserMessageFilter {
public:
SetIsInertMessageFilter()
: content::BrowserMessageFilter(FrameMsgStart),
- message_loop_runner_(new content::MessageLoopRunner),
msg_received_(false) {}
bool OnMessageReceived(const IPC::Message& message) override {
@@ -9865,7 +9619,7 @@ class SetIsInertMessageFilter : public content::BrowserMessageFilter {
bool is_inert() const { return is_inert_; }
- void Wait() { message_loop_runner_->Run(); }
+ void Wait() { run_loop_.Run(); }
private:
~SetIsInertMessageFilter() override {}
@@ -9880,10 +9634,10 @@ class SetIsInertMessageFilter : public content::BrowserMessageFilter {
is_inert_ = is_inert;
if (!msg_received_) {
msg_received_ = true;
- message_loop_runner_->Quit();
+ run_loop_.Quit();
}
}
- scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
+ base::RunLoop run_loop_;
bool msg_received_;
bool is_inert_;
DISALLOW_COPY_AND_ASSIGN(SetIsInertMessageFilter);
@@ -10348,6 +10102,76 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
}
#if defined(OS_ANDROID)
+
+namespace {
+
+class MockEventHandlerAndroid : public ui::EventHandlerAndroid {
+ public:
+ bool OnTouchEvent(const ui::MotionEventAndroid& event) override {
+ did_receive_event_ = true;
+ return true;
+ }
+
+ bool did_receive_event() { return did_receive_event_; }
+
+ private:
+ bool did_receive_event_ = false;
+};
+
+} // namespace
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ SpeculativeRenderFrameHostDoesNotReceiveInput) {
+ GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), url1));
+
+ RenderWidgetHostViewAndroid* rwhva =
+ static_cast<RenderWidgetHostViewAndroid*>(
+ shell()->web_contents()->GetRenderWidgetHostView());
+ ui::ViewAndroid* rwhva_native_view = rwhva->GetNativeView();
+ FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+
+ // Start a cross-site navigation.
+ GURL url2(embedded_test_server()->GetURL("b.com", "/title2.html"));
+ TestNavigationManager nav_manager(web_contents(), url2);
+ shell()->LoadURL(url2);
+
+ // Wait for the request, but don't commit it yet. This should create a
+ // speculative RenderFrameHost.
+ ASSERT_TRUE(nav_manager.WaitForRequestStart());
+ RenderFrameHostImpl* root_speculative_rfh =
+ root->render_manager()->speculative_frame_host();
+ EXPECT_TRUE(root_speculative_rfh);
+ RenderWidgetHostViewAndroid* rwhv_speculative =
+ static_cast<RenderWidgetHostViewAndroid*>(
+ root_speculative_rfh->GetView());
+ ui::ViewAndroid* rwhv_speculative_native_view =
+ rwhv_speculative->GetNativeView();
+
+ ui::ViewAndroid* root_view = web_contents()->GetView()->GetNativeView();
+ EXPECT_TRUE(root_view);
+
+ MockEventHandlerAndroid mock_handler;
+ rwhva_native_view->set_event_handler(&mock_handler);
+ MockEventHandlerAndroid mock_handler_speculative;
+ rwhv_speculative_native_view->set_event_handler(&mock_handler_speculative);
+ // Avoid having the root try to handle the following event.
+ root_view->set_event_handler(nullptr);
+
+ auto size = root_view->GetSize();
+ float x = size.width() / 2;
+ float y = size.height() / 2;
+ ui::MotionEventAndroid::Pointer pointer0(0, x, y, 0, 0, 0, 0, 0);
+ ui::MotionEventAndroid::Pointer pointer1(0, 0, 0, 0, 0, 0, 0, 0);
+ ui::MotionEventAndroid event(nullptr, nullptr, 1.f / root_view->GetDipScale(),
+ 0.f, 0.f, 0.f, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ false, &pointer0, &pointer1);
+ root_view->OnTouchEventForTesting(event);
+
+ EXPECT_TRUE(mock_handler.did_receive_event());
+ EXPECT_FALSE(mock_handler_speculative.did_receive_event());
+}
+
IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, TestChildProcessImportance) {
web_contents()->SetMainFrameImportance(ChildProcessImportance::MODERATE);
@@ -11789,6 +11613,100 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, VisibilityFrameDepthTest) {
EXPECT_EQ(0u, popup_process->GetFrameDepth());
}
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ FrameViewportIntersectionTestSimple) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(b(c),d,e(f))"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+ scoped_refptr<UpdateViewportIntersectionMessageFilter> root_filter =
+ new UpdateViewportIntersectionMessageFilter();
+ root->current_frame_host()->GetProcess()->AddFilter(root_filter.get());
+
+ scoped_refptr<UpdateViewportIntersectionMessageFilter> child0_filter =
+ new UpdateViewportIntersectionMessageFilter();
+ root->child_at(0)->current_frame_host()->GetProcess()->AddFilter(
+ child0_filter.get());
+
+ scoped_refptr<UpdateViewportIntersectionMessageFilter> child2_filter =
+ new UpdateViewportIntersectionMessageFilter();
+ root->child_at(2)->current_frame_host()->GetProcess()->AddFilter(
+ child2_filter.get());
+
+ // Each immediate child is sized to 100% width and 75% height.
+ LayoutNonRecursiveForTestingViewportIntersection(shell()->web_contents());
+
+ while (true) {
+ base::RunLoop run_loop;
+ root_filter->set_run_loop(&run_loop);
+ child0_filter->set_run_loop(&run_loop);
+ child2_filter->set_run_loop(&run_loop);
+ run_loop.Run();
+ root_filter->set_run_loop(nullptr);
+ child0_filter->set_run_loop(nullptr);
+ child2_filter->set_run_loop(nullptr);
+
+ if ( // Root should always intersect.
+ CheckIntersectsViewport(true, root) &&
+ // Child 0 should be entirely in viewport.
+ CheckIntersectsViewport(true, root->child_at(0)) &&
+ // Grand child should match parent.
+ CheckIntersectsViewport(true, root->child_at(0)->child_at(0)) &&
+ // Child 1 should be partially in viewport.
+ CheckIntersectsViewport(true, root->child_at(1)) &&
+ // Child 2 should be not be in viewport.
+ CheckIntersectsViewport(false, root->child_at(2)) &&
+ // Grand child should match parent.
+ CheckIntersectsViewport(false, root->child_at(2)->child_at(0))) {
+ break;
+ }
+ }
+}
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ FrameViewportIntersectionTestAggregate) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(b,c,a,b)"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+ scoped_refptr<UpdateViewportIntersectionMessageFilter> filter =
+ new UpdateViewportIntersectionMessageFilter();
+ root->current_frame_host()->GetProcess()->AddFilter(filter.get());
+
+ // Each immediate child is sized to 100% width and 75% height.
+ LayoutNonRecursiveForTestingViewportIntersection(shell()->web_contents());
+
+ while (true) {
+ filter->Wait();
+
+ bool pass = true;
+ {
+ // Child 2 does not intersect, but shares widget with the main frame.
+ FrameTreeNode* node = root->child_at(2);
+ RenderProcessHost::Priority priority =
+ node->current_frame_host()->GetRenderWidgetHost()->GetPriority();
+ pass = pass && priority.intersects_viewport;
+ pass = pass &&
+ node->current_frame_host()->GetProcess()->GetIntersectsViewport();
+ }
+
+ {
+ // Child 3 does not intersect, but shares a process with child 0.
+ FrameTreeNode* node = root->child_at(3);
+ RenderProcessHost::Priority priority =
+ node->current_frame_host()->GetRenderWidgetHost()->GetPriority();
+ pass = pass && !priority.intersects_viewport;
+ pass = pass &&
+ node->current_frame_host()->GetProcess()->GetIntersectsViewport();
+ }
+
+ if (pass)
+ break;
+ }
+}
+
// Ensure that after a main frame with an OOPIF is navigated cross-site, the
// unload handler in the OOPIF sees correct main frame origin, namely the old
// and not the new origin. See https://crbug.com/825283.
@@ -11935,14 +11853,11 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
namespace {
// A helper class that watches for SwapOut ACK messages, allowing them
-// to go through but remembering that the message was received. It also
-// watches for any ShutdownRequests coming from the renderer and ensures that
-// the SwapOut ACK is received prior to those.
+// to go through but remembering that the message was received.
class SwapoutACKReceivedFilter : public BrowserMessageFilter {
public:
explicit SwapoutACKReceivedFilter(RenderProcessHost* process)
: BrowserMessageFilter(FrameMsgStart) {
- process->AddObserver(&shutdown_observer_);
process->AddFilter(this);
}
@@ -11955,17 +11870,12 @@ class SwapoutACKReceivedFilter : public BrowserMessageFilter {
// BrowserMessageFilter:
bool OnMessageReceived(const IPC::Message& message) override {
if (message.type() == FrameHostMsg_SwapOut_ACK::ID) {
- // This ensures that the SwapOut ACK arrived before any
- // renderer-initiated process shutdown requests.
- EXPECT_FALSE(shutdown_observer_.has_received_shutdown_request())
- << " Shutdown request should be received after the swapout ACK";
received_ = true;
}
return false;
}
bool received_ = false;
- ShutdownObserver shutdown_observer_;
DISALLOW_COPY_AND_ASSIGN(SwapoutACKReceivedFilter);
};
@@ -11998,62 +11908,6 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
EXPECT_TRUE(watcher.did_exit_normally());
}
-// Class to monitor incoming FrameHostMsg_UpdateViewportIntersection messages.
-class UpdateViewportIntersectionMessageFilter
- : public content::BrowserMessageFilter {
- public:
- UpdateViewportIntersectionMessageFilter()
- : content::BrowserMessageFilter(FrameMsgStart), msg_received_(false) {}
-
- bool OnMessageReceived(const IPC::Message& message) override {
- IPC_BEGIN_MESSAGE_MAP(UpdateViewportIntersectionMessageFilter, message)
- IPC_MESSAGE_HANDLER(FrameHostMsg_UpdateViewportIntersection,
- OnUpdateViewportIntersection)
- IPC_END_MESSAGE_MAP()
- return false;
- }
-
- gfx::Rect GetCompositingRect() const { return compositing_rect_; }
- gfx::Rect GetViewportIntersection() const { return viewport_intersection_; }
-
- void Wait() {
- DCHECK(!run_loop_);
- if (msg_received_) {
- msg_received_ = false;
- return;
- }
- run_loop_.reset(new base::RunLoop());
- run_loop_->Run();
- run_loop_.reset();
- msg_received_ = false;
- }
-
- private:
- ~UpdateViewportIntersectionMessageFilter() override {}
-
- void OnUpdateViewportIntersection(const gfx::Rect& viewport_intersection,
- const gfx::Rect& compositing_rect) {
- content::BrowserThread::PostTask(
- content::BrowserThread::UI, FROM_HERE,
- base::BindOnce(&UpdateViewportIntersectionMessageFilter::
- OnUpdateViewportIntersectionOnUI,
- this, viewport_intersection, compositing_rect));
- }
- void OnUpdateViewportIntersectionOnUI(const gfx::Rect& viewport_intersection,
- const gfx::Rect& compositing_rect) {
- compositing_rect_ = compositing_rect;
- viewport_intersection_ = viewport_intersection;
- msg_received_ = true;
- if (run_loop_)
- run_loop_->Quit();
- }
- std::unique_ptr<base::RunLoop> run_loop_;
- bool msg_received_;
- gfx::Rect compositing_rect_;
- gfx::Rect viewport_intersection_;
- DISALLOW_COPY_AND_ASSIGN(UpdateViewportIntersectionMessageFilter);
-};
-
// Tests that when a large OOPIF has been scaled, the compositor raster area
// sent from the embedder is correct.
#if defined(OS_ANDROID) || defined(OS_MACOSX)
@@ -12259,8 +12113,16 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
// Test to verify that viewport intersection is propagated to nested OOPIFs
// even when a parent OOPIF has been throttled.
+// TODO(crbug.com/869758) The test is flaky on android
+#if defined(OS_ANDROID)
+#define MAYBE_NestedFrameViewportIntersectionUpdated \
+ DISABLED_NestedFrameViewportIntersectionUpdated
+#else
+#define MAYBE_NestedFrameViewportIntersectionUpdated \
+ NestedFrameViewportIntersectionUpdated
+#endif
IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
- NestedFrameViewportIntersectionUpdated) {
+ MAYBE_NestedFrameViewportIntersectionUpdated) {
GURL main_url(embedded_test_server()->GetURL(
"foo.com", "/frame_tree/scrollable_page_with_positioned_frame.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -12939,13 +12801,12 @@ namespace {
// |web_contents|.
class SameDocumentCommitObserver : public WebContentsObserver {
public:
- SameDocumentCommitObserver(WebContents* web_contents)
- : WebContentsObserver(web_contents),
- message_loop_runner_(new MessageLoopRunner) {
+ explicit SameDocumentCommitObserver(WebContents* web_contents)
+ : WebContentsObserver(web_contents) {
EXPECT_TRUE(web_contents);
}
- void Wait() { message_loop_runner_->Run(); }
+ void Wait() { run_loop_.Run(); }
const GURL& last_committed_url() { return last_committed_url_; }
@@ -12953,12 +12814,12 @@ class SameDocumentCommitObserver : public WebContentsObserver {
void DidFinishNavigation(NavigationHandle* navigation_handle) override {
if (navigation_handle->IsSameDocument()) {
last_committed_url_ = navigation_handle->GetURL();
- message_loop_runner_->Quit();
+ run_loop_.Quit();
}
}
GURL last_committed_url_;
- scoped_refptr<MessageLoopRunner> message_loop_runner_;
+ base::RunLoop run_loop_;
DISALLOW_COPY_AND_ASSIGN(SameDocumentCommitObserver);
};
@@ -13196,4 +13057,172 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
EXPECT_TRUE(b_process_observer.did_exit_normally());
}
+// This observer waits until WebContentsObserver::OnRendererUnresponsive
+// notification.
+class UnresponsiveRendererObserver : public WebContentsObserver {
+ public:
+ explicit UnresponsiveRendererObserver(WebContents* web_contents)
+ : WebContentsObserver(web_contents) {}
+
+ ~UnresponsiveRendererObserver() override {}
+
+ RenderProcessHost* Wait(base::TimeDelta timeout = base::TimeDelta::Max()) {
+ if (!captured_render_process_host_) {
+ base::OneShotTimer timer;
+ timer.Start(FROM_HERE, timeout, run_loop_.QuitClosure());
+ run_loop_.Run();
+ timer.Stop();
+ }
+ return captured_render_process_host_;
+ }
+
+ private:
+ void OnRendererUnresponsive(RenderProcessHost* render_process_host) override {
+ captured_render_process_host_ = render_process_host;
+ run_loop_.Quit();
+ }
+
+ RenderProcessHost* captured_render_process_host_ = nullptr;
+ base::RunLoop run_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(UnresponsiveRendererObserver);
+};
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ CommitTimeoutForHungRenderer) {
+ // Navigate first tab to a.com.
+ GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), a_url));
+ RenderProcessHost* a_process =
+ shell()->web_contents()->GetMainFrame()->GetProcess();
+
+ // Open b.com in a second tab. Using a renderer-initiated navigation is
+ // important to leave a.com and b.com SiteInstances in the same
+ // BrowsingInstance (so the b.com -> a.com navigation in the next test step
+ // will reuse the process associated with the first a.com tab).
+ GURL b_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
+ Shell* new_shell = OpenPopup(shell()->web_contents(), b_url, "newtab");
+ WebContents* new_contents = new_shell->web_contents();
+ EXPECT_TRUE(WaitForLoadStop(new_contents));
+ RenderProcessHost* b_process = new_contents->GetMainFrame()->GetProcess();
+ EXPECT_NE(a_process, b_process);
+
+ // Hang the first tab's renderer.
+ const char* kHungScript = "setTimeout(function() { for (;;) {}; }, 0);";
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(), kHungScript));
+
+ // Attempt to navigate the second tab to a.com. This will attempt to reuse
+ // the hung process.
+ NavigationHandleImpl::SetCommitTimeoutForTesting(
+ base::TimeDelta::FromMilliseconds(100));
+ GURL hung_url(embedded_test_server()->GetURL("a.com", "/title3.html"));
+ UnresponsiveRendererObserver unresponsive_renderer_observer(new_contents);
+ EXPECT_TRUE(
+ ExecJs(new_contents, JsReplace("window.location = $1", hung_url)));
+
+ // Verify that we will be notified about the unresponsive renderer. Before
+ // changes in https://crrev.com/c/1089797, the test would hang here forever.
+ RenderProcessHost* hung_process = unresponsive_renderer_observer.Wait();
+ EXPECT_EQ(hung_process, a_process);
+
+ // Reset the timeout.
+ NavigationHandleImpl::SetCommitTimeoutForTesting(base::TimeDelta());
+}
+
+// This is a regression test for https://crbug.com/881812 which complained that
+// the hung renderer dialog used to undesirably show up for background tabs
+// (typically during session restore when many navigations would be happening in
+// backgrounded processes).
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ CommitTimeoutForInvisibleWebContents) {
+ // Navigate first tab to a.com.
+ GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), a_url));
+ RenderProcessHost* a_process =
+ shell()->web_contents()->GetMainFrame()->GetProcess();
+
+ // Open b.com in a second tab. Using a renderer-initiated navigation is
+ // important to leave a.com and b.com SiteInstances in the same
+ // BrowsingInstance (so the b.com -> a.com navigation in the next test step
+ // will reuse the process associated with the first a.com tab).
+ GURL b_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
+ Shell* new_shell = OpenPopup(shell()->web_contents(), b_url, "newtab");
+ WebContents* new_contents = new_shell->web_contents();
+ EXPECT_TRUE(WaitForLoadStop(new_contents));
+ RenderProcessHost* b_process = new_contents->GetMainFrame()->GetProcess();
+ EXPECT_NE(a_process, b_process);
+
+ // Hang the first tab's renderer.
+ const char* kHungScript = "setTimeout(function() { for (;;) {}; }, 0);";
+ EXPECT_TRUE(ExecuteScript(shell()->web_contents(), kHungScript));
+
+ // Hide the second tab. This should prevent reporting of hangs in this tab
+ // (see https://crbug.com/881812).
+ new_contents->WasHidden();
+ EXPECT_EQ(Visibility::HIDDEN, new_contents->GetVisibility());
+
+ // Attempt to navigate the second tab to a.com. This will attempt to reuse
+ // the hung process.
+ base::TimeDelta kTimeout = base::TimeDelta::FromMilliseconds(100);
+ NavigationHandleImpl::SetCommitTimeoutForTesting(kTimeout);
+ GURL hung_url(embedded_test_server()->GetURL("a.com", "/title3.html"));
+ UnresponsiveRendererObserver unresponsive_renderer_observer(new_contents);
+ EXPECT_TRUE(
+ ExecJs(new_contents, JsReplace("window.location = $1", hung_url)));
+
+ // Verify that we will not be notified about the unresponsive renderer.
+ // Before changes in https://crrev.com/c/1089797, the test would get notified
+ // and therefore |hung_process| would be non-null.
+ RenderProcessHost* hung_process =
+ unresponsive_renderer_observer.Wait(kTimeout * 10);
+ EXPECT_FALSE(hung_process);
+
+ // Reset the timeout.
+ NavigationHandleImpl::SetCommitTimeoutForTesting(base::TimeDelta());
+}
+
+// Tests that an inner WebContents will reattach to its outer WebContents after
+// a navigation that causes a process swap.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, ProcessSwapOnInnerContents) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(a)"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ FrameTreeNode* child_frame =
+ web_contents()->GetFrameTree()->root()->child_at(0);
+ WebContentsImpl* inner_contents =
+ static_cast<WebContentsImpl*>(CreateAndAttachInnerContents(
+ ToRenderFrameHost(child_frame).render_frame_host()));
+ FrameTreeNode* inner_contents_root = inner_contents->GetFrameTree()->root();
+ RenderFrameProxyHost* outer_proxy =
+ inner_contents_root->render_manager()->GetProxyToOuterDelegate();
+ CrossProcessFrameConnector* outer_connector =
+ outer_proxy->cross_process_frame_connector();
+ EXPECT_NE(nullptr, outer_connector->get_view_for_testing());
+
+ GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
+ NavigateFrameToURL(inner_contents_root, a_url);
+ SiteInstance* a_site_instance =
+ inner_contents->GetMainFrame()->GetSiteInstance();
+ RenderProcessHost* a_process = a_site_instance->GetProcess();
+ RenderWidgetHostViewChildFrame* a_view =
+ outer_connector->get_view_for_testing();
+
+ GURL b_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
+ NavigateFrameToURL(inner_contents_root, b_url);
+ SiteInstance* b_site_instance =
+ inner_contents->GetMainFrame()->GetSiteInstance();
+ RenderProcessHost* b_process = b_site_instance->GetProcess();
+ RenderWidgetHostViewChildFrame* b_view =
+ outer_connector->get_view_for_testing();
+
+ // Ensure that the SiteInstances have changed, we've completed a process swap
+ // and reattached the inner WebContents creating a new RenderWidgetHostView.
+ EXPECT_NE(a_site_instance, b_site_instance);
+ EXPECT_NE(a_process, b_process);
+ EXPECT_NE(nullptr, a_view);
+ EXPECT_NE(nullptr, b_view);
+ EXPECT_NE(a_view, b_view);
+}
+
} // namespace content
diff --git a/chromium/content/browser/site_per_process_hit_test_browsertest.cc b/chromium/content/browser/site_per_process_hit_test_browsertest.cc
index c8ab9dd5684..dc73deb2e4c 100644
--- a/chromium/content/browser/site_per_process_hit_test_browsertest.cc
+++ b/chromium/content/browser/site_per_process_hit_test_browsertest.cc
@@ -14,7 +14,9 @@
#include "base/test/test_timeouts.h"
#include "build/build_config.h"
#include "components/viz/common/features.h"
+#include "content/browser/compositor/surface_utils.h"
#include "content/browser/renderer_host/cursor_manager.h"
+#include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h"
#include "content/browser/renderer_host/input/synthetic_tap_gesture.h"
#include "content/browser/renderer_host/input/touch_emulator.h"
#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
@@ -37,12 +39,14 @@
#include "ui/events/base_event_utils.h"
#include "ui/events/gesture_detection/gesture_configuration.h"
#include "ui/events/gesture_detection/gesture_provider_config_helper.h"
+#include "ui/gfx/geometry/quad_f.h"
#if defined(USE_AURA)
#include "content/browser/renderer_host/render_widget_host_view_aura.h"
#include "content/public/browser/overscroll_configuration.h"
#include "content/test/mock_overscroll_controller_delegate_aura.h"
#include "ui/aura/window_tree_host.h"
+#include "ui/events/event_rewriter.h"
#endif
#if defined(OS_MACOSX)
@@ -54,6 +58,10 @@
#include "content/test/mock_overscroll_refresh_handler_android.h"
#endif
+#if defined(OS_WIN)
+#include "base/debug/stack_trace.h"
+#endif
+
namespace content {
namespace {
@@ -190,8 +198,10 @@ void RouteMouseEventAndWaitUntilDispatch(
waiter.Wait();
}
+// Dispatch |event| to the specified view using browser process hit testing.
void DispatchMouseEventAndWaitUntilDispatch(
WebContentsImpl* web_contents,
+ blink::WebMouseEvent& event,
RenderWidgetHostViewBase* location_view,
const gfx::PointF& location,
RenderWidgetHostViewBase* expected_target,
@@ -202,22 +212,37 @@ void DispatchMouseEventAndWaitUntilDispatch(
expected_target->GetRenderWidgetHost());
gfx::PointF root_location =
location_view->TransformPointToRootCoordSpaceF(location);
- blink::WebMouseEvent down_event(
- blink::WebInputEvent::kMouseDown, blink::WebInputEvent::kNoModifiers,
- blink::WebInputEvent::GetStaticTimeStampForTests());
- down_event.button = blink::WebPointerProperties::Button::kLeft;
- down_event.click_count = 1;
FrameTreeNode* root = web_contents->GetFrameTree()->root();
auto* root_view = static_cast<RenderWidgetHostViewBase*>(
root->current_frame_host()->GetRenderWidgetHost()->GetView());
- SetWebEventPositions(&down_event, root_location, root_view);
+ SetWebEventPositions(&event, root_location, root_view);
RouteMouseEventAndWaitUntilDispatch(router, root_view, expected_target,
- &down_event);
+ &event);
EXPECT_TRUE(monitor.EventWasReceived());
- EXPECT_NEAR(expected_location.x(), monitor.event().PositionInWidget().x, 2);
+ EXPECT_NEAR(expected_location.x(), monitor.event().PositionInWidget().x, 2)
+ << " & original location was " << location.x() << ", " << location.y()
+ << " & root_location was " << root_location.x() << ", "
+ << root_location.y();
EXPECT_NEAR(expected_location.y(), monitor.event().PositionInWidget().y, 2);
}
+// Wrapper for the above method that creates a MouseDown to send.
+void DispatchMouseEventAndWaitUntilDispatch(
+ WebContentsImpl* web_contents,
+ RenderWidgetHostViewBase* location_view,
+ const gfx::PointF& location,
+ RenderWidgetHostViewBase* expected_target,
+ const gfx::PointF& expected_location) {
+ blink::WebMouseEvent down_event(
+ blink::WebInputEvent::kMouseDown, blink::WebInputEvent::kNoModifiers,
+ blink::WebInputEvent::GetStaticTimeStampForTests());
+ down_event.button = blink::WebPointerProperties::Button::kLeft;
+ down_event.click_count = 1;
+ DispatchMouseEventAndWaitUntilDispatch(web_contents, down_event,
+ location_view, location,
+ expected_target, expected_location);
+}
+
// Helper function that performs a surface hittest.
void SurfaceHitTestTestHelper(
Shell* shell,
@@ -288,6 +313,71 @@ void OverlapSurfaceHitTestHelper(
gfx::PointF(95, 95));
}
+void NonFlatTransformedSurfaceHitTestHelper(
+ Shell* shell,
+ net::test_server::EmbeddedTestServer* embedded_test_server) {
+ GURL main_url(embedded_test_server->GetURL(
+ "/frame_tree/page_with_non_flat_transformed_frame.html"));
+ EXPECT_TRUE(NavigateToURL(shell, main_url));
+ auto* web_contents = static_cast<WebContentsImpl*>(shell->web_contents());
+
+ FrameTreeNode* root = web_contents->GetFrameTree()->root();
+ ASSERT_EQ(1U, root->child_count());
+
+ FrameTreeNode* child_node = root->child_at(0);
+ GURL site_url(embedded_test_server->GetURL("baz.com", "/title1.html"));
+ EXPECT_EQ(site_url, child_node->current_url());
+ EXPECT_NE(shell->web_contents()->GetSiteInstance(),
+ child_node->current_frame_host()->GetSiteInstance());
+
+ RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
+ child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+ WaitForHitTestDataOrChildSurfaceReady(child_node->current_frame_host());
+
+ DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_child,
+ gfx::PointF(5, 5), rwhv_child,
+ gfx::PointF(5, 5));
+}
+
+void PerspectiveTransformedSurfaceHitTestHelper(
+ Shell* shell,
+ net::test_server::EmbeddedTestServer* embedded_test_server) {
+ GURL main_url(embedded_test_server->GetURL(
+ "/frame_tree/page_with_perspective_transformed_frame.html"));
+ EXPECT_TRUE(NavigateToURL(shell, main_url));
+ auto* web_contents = static_cast<WebContentsImpl*>(shell->web_contents());
+
+ RenderFrameSubmissionObserver render_frame_submission_observer(web_contents);
+
+ FrameTreeNode* root = web_contents->GetFrameTree()->root();
+ ASSERT_EQ(1U, root->child_count());
+
+ FrameTreeNode* child_node = root->child_at(0);
+ GURL site_url(embedded_test_server->GetURL("baz.com", "/title1.html"));
+ EXPECT_EQ(site_url, child_node->current_url());
+ EXPECT_NE(shell->web_contents()->GetSiteInstance(),
+ child_node->current_frame_host()->GetSiteInstance());
+
+ RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
+ root->current_frame_host()->GetRenderWidgetHost()->GetView());
+ RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
+ child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+ WaitForHitTestDataOrChildSurfaceReady(child_node->current_frame_host());
+
+ // (90, 75) hit tests into the child frame that is positioned at (50, 50).
+ // Without other transformations this should result in a translated point
+ // of (40, 25), but the 45 degree 3-dimensional rotation of the frame about
+ // a vertical axis skews it.
+ // We can't allow DispatchMouseEventAndWaitUntilDispatch to compute the
+ // coordinates in the root space unless browser conversions with
+ // perspective transforms are first fixed. See https://crbug.com/854257.
+ DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_root,
+ gfx::PointF(90, 75), rwhv_child,
+ gfx::PointF(33, 23));
+}
+
// Helper function that performs a surface hittest in nested frame.
void NestedSurfaceHitTestTestHelper(
Shell* shell,
@@ -416,10 +506,14 @@ void HitTestWatermark(
// Set 'pointer-events: none' on the div.
EXPECT_TRUE(ExecuteScript(web_contents, "W.style.pointerEvents = 'none';"));
+ // TODO(sunxd): Re-enable this test when surface layer hit test is able to
+ // handle pointer-events none. See https://crbug.com/841358.
// Dispatch another event at the same location. It should reach the oopif this
// time.
- DispatchMouseEventAndWaitUntilDispatch(
- web_contents, rwhv_child, child_location, rwhv_child, child_location);
+ if (!features::IsVizHitTestingSurfaceLayerEnabled()) {
+ DispatchMouseEventAndWaitUntilDispatch(
+ web_contents, rwhv_child, child_location, rwhv_child, child_location);
+ }
}
#if defined(USE_AURA)
@@ -569,6 +663,34 @@ class SetMouseCaptureInterceptor
DISALLOW_COPY_AND_ASSIGN(SetMouseCaptureInterceptor);
};
+#if defined(USE_AURA)
+// A class to allow intercepting and discarding of system-level mouse events
+// that might otherwise cause unpredictable behaviour in tests.
+class MouseEventRewriter : public ui::EventRewriter {
+ public:
+ MouseEventRewriter() = default;
+ ~MouseEventRewriter() override {}
+
+ private:
+ ui::EventRewriteStatus RewriteEvent(
+ const ui::Event& event,
+ std::unique_ptr<ui::Event>* new_event) override {
+ if (event.IsMouseEvent())
+ return ui::EVENT_REWRITE_DISCARD;
+ return ui::EVENT_REWRITE_CONTINUE;
+ }
+
+ ui::EventRewriteStatus NextDispatchEvent(
+ const ui::Event& event,
+ std::unique_ptr<ui::Event>* new_event) override {
+ NOTREACHED();
+ return ui::EVENT_REWRITE_CONTINUE;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(MouseEventRewriter);
+};
+#endif
+
} // namespace
class SitePerProcessHitTestBrowserTest
@@ -577,6 +699,19 @@ class SitePerProcessHitTestBrowserTest
public:
SitePerProcessHitTestBrowserTest() {}
+#if defined(USE_AURA)
+ void PreRunTestOnMainThread() override {
+ SitePerProcessBrowserTest::PreRunTestOnMainThread();
+ // Disable system mouse events, which can interfere with tests.
+ shell()->window()->GetHost()->AddEventRewriter(&event_rewriter);
+ }
+
+ void PostRunTestOnMainThread() override {
+ shell()->window()->GetHost()->RemoveEventRewriter(&event_rewriter);
+ SitePerProcessBrowserTest::PostRunTestOnMainThread();
+ }
+#endif
+
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
SitePerProcessBrowserTest::SetUpCommandLine(command_line);
@@ -592,6 +727,9 @@ class SitePerProcessHitTestBrowserTest
}
base::test::ScopedFeatureList feature_list_;
+#if defined(USE_AURA)
+ MouseEventRewriter event_rewriter;
+#endif
};
//
@@ -1042,14 +1180,6 @@ IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
scroll_end_observer.Wait();
}
-#if defined(OS_LINUX)
-// The test is flaky on Linux: https://crbug.com/833380.
-#define MAYBE_BubbledScrollEventsTransformedCorrectly \
- DISABLED_BubbledScrollEventsTransformedCorrectly
-#else
-#define MAYBE_BubbledScrollEventsTransformedCorrectly \
- BubbledScrollEventsTransformedCorrectly
-#endif
// When a scroll event is bubbled, ensure that the bubbled event's coordinates
// are correctly updated to the ancestor's coordinate space. In particular,
// ensure that the transformation considers CSS scaling of the child where
@@ -1057,7 +1187,7 @@ IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
// coordinates in the ancestor's coordinate space.
// See https://crbug.com/817392
IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
- MAYBE_BubbledScrollEventsTransformedCorrectly) {
+ BubbledScrollEventsTransformedCorrectly) {
GURL main_url(embedded_test_server()->GetURL(
"/frame_tree/page_with_positioned_scaled_frame.html"));
ASSERT_TRUE(NavigateToURL(shell(), main_url));
@@ -1125,10 +1255,57 @@ IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
root_scroll_begin_observer.Wait();
}
+#if defined(OS_WIN)
+// Add temporary TouchMove event observer to detect spurious TouchMove events
+// leading to test flake.
+// https://crbug.com/833380.
+class EmulatedTouchTouchMoveInputObserver
+ : public RenderWidgetHost::InputEventObserver {
+ public:
+ explicit EmulatedTouchTouchMoveInputObserver(RenderWidgetHost* host)
+ : host_(host), first_touch_move_seen_(false) {
+ host_->AddInputEventObserver(this);
+ }
+ ~EmulatedTouchTouchMoveInputObserver() override {
+ host_->RemoveInputEventObserver(this);
+ }
+
+ void OnInputEvent(const blink::WebInputEvent& event) override {
+ if (event.GetType() != blink::WebInputEvent::kTouchMove)
+ return;
+
+ const blink::WebTouchEvent& touch_event =
+ static_cast<const blink::WebTouchEvent&>(event);
+ blink::WebFloatPoint pos_in_widget =
+ touch_event.touches[0].PositionInWidget();
+ blink::WebFloatPoint pos_in_screen =
+ touch_event.touches[0].PositionInScreen();
+ LOG(ERROR) << "TouchMove seen: widget @ (" << pos_in_widget.x << ","
+ << pos_in_widget.y << "), screen @ (" << pos_in_screen.x << ","
+ << pos_in_screen.y << ")";
+
+ if (first_touch_move_seen_)
+ return;
+
+ first_touch_move_seen_ = true;
+ base::debug::StackTrace().Print();
+ }
+
+ private:
+ RenderWidgetHost* host_;
+ bool first_touch_move_seen_;
+};
+#endif
+
class SitePerProcessEmulatedTouchBrowserTest
: public SitePerProcessHitTestBrowserTest {
public:
- enum TestType { ScrollBubbling, PinchGoesToMainFrame, TouchActionBubbling };
+ enum TestType {
+ ScrollBubbling,
+ PinchGoesToMainFrame,
+ TouchActionBubbling,
+ ShowPressHasTouchID
+ };
~SitePerProcessEmulatedTouchBrowserTest() override {}
@@ -1167,6 +1344,17 @@ class SitePerProcessEmulatedTouchBrowserTest
[](blink::WebInputEvent::Type expected_type,
const gfx::Point& expected_position, content::InputEventAckSource,
content::InputEventAckState, const blink::WebInputEvent& event) {
+#if defined(OS_WIN)
+ // Add some logging to diagnose a potential source of flake:
+ // the hypothesis is that something is causing the gesture
+ // stream to cancel before kGestureShowPress is generated, so
+ // we'll dump the event stream that we actually see in this case.
+ // https://crbug.com/833380.
+ if (expected_type == blink::WebInputEvent::kGestureShowPress) {
+ LOG(ERROR) << "Waiting for: kGestureShowPress: ack seen for "
+ << blink::WebInputEvent::GetName(event.GetType());
+ }
+#endif
if (event.GetType() != expected_type)
return false;
@@ -1178,6 +1366,10 @@ class SitePerProcessEmulatedTouchBrowserTest
1);
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen,
gesture_event.SourceDevice());
+ // We expect all gesture events to have non-zero ids otherwise they
+ // can force hit-testing in RenderWidgetHostInputEventRouter even
+ // when it's unnecessary.
+ EXPECT_NE(0U, gesture_event.unique_touch_event_id);
return true;
});
@@ -1190,10 +1382,22 @@ class SitePerProcessEmulatedTouchBrowserTest
case PinchGoesToMainFrame:
expected_gesture_type = blink::WebInputEvent::kGesturePinchBegin;
break;
+ case ShowPressHasTouchID:
+ expected_gesture_type = blink::WebInputEvent::kGestureShowPress;
+ break;
default:
ASSERT_TRUE(false);
}
+#if defined(OS_WIN)
+ {
+ gfx::Rect view_bounds = root_rwhv->GetViewBounds();
+ LOG(ERROR) << "Root view bounds = (" << view_bounds.x() << ","
+ << view_bounds.y() << ") " << view_bounds.width() << " x "
+ << view_bounds.height();
+ }
+#endif
+
gfx::Point position_in_child(5, 5);
InputEventAckWaiter child_gesture_event_observer(
child_rwhv->GetRenderWidgetHost(),
@@ -1251,9 +1455,29 @@ class SitePerProcessEmulatedTouchBrowserTest
simulated_event_time += simulated_event_time_delta;
mouse_up_event.SetTimeStamp(simulated_event_time);
+#if defined(OS_WIN)
+ // Add temporary TouchMove event observer to detect spurious TouchMove
+ // events leading to test flake.
+ // https://crbug.com/833380.
+ std::unique_ptr<EmulatedTouchTouchMoveInputObserver> touch_move_observer;
+ if (test_type == ShowPressHasTouchID) {
+ touch_move_observer.reset(new EmulatedTouchTouchMoveInputObserver(
+ child_rwhv->GetRenderWidgetHost()));
+ }
+#endif
+
// Send mouse events and wait for GesturePinchBegin.
router->RouteMouseEvent(root_rwhv, &mouse_move_event, ui::LatencyInfo());
router->RouteMouseEvent(root_rwhv, &mouse_down_event, ui::LatencyInfo());
+ if (test_type == ShowPressHasTouchID) {
+ // Wait for child to receive GestureShowPress. If this test fails, it
+ // will either DCHECK or time out.
+ child_gesture_event_observer.Wait();
+#if defined(OS_WIN)
+ touch_move_observer.reset();
+#endif
+ return;
+ }
router->RouteMouseEvent(root_rwhv, &mouse_drag_event, ui::LatencyInfo());
router->RouteMouseEvent(root_rwhv, &mouse_up_event, ui::LatencyInfo());
@@ -1271,43 +1495,126 @@ class SitePerProcessEmulatedTouchBrowserTest
}
};
-#if defined(OS_CHROMEOS)
-// Flaky: https://crbug.com/833380
-#define MAYBE_EmulatedTouchScrollBubbles DISABLED_EmulatedTouchScrollBubbles
-#else
-#define MAYBE_EmulatedTouchScrollBubbles EmulatedTouchScrollBubbles
-#endif
+IN_PROC_BROWSER_TEST_P(SitePerProcessEmulatedTouchBrowserTest,
+ EmulatedTouchShowPressHasTouchID) {
+ RunTest(ShowPressHasTouchID);
+}
IN_PROC_BROWSER_TEST_P(SitePerProcessEmulatedTouchBrowserTest,
- MAYBE_EmulatedTouchScrollBubbles) {
+ EmulatedTouchScrollBubbles) {
RunTest(ScrollBubbling);
}
-#if defined(OS_LINUX)
-// Flaky: https://crbug.com/833380
-#define MAYBE_EmulatedTouchPinchGoesToMainFrame \
- DISABLED_EmulatedTouchPinchGoesToMainFrame
-#else
-#define MAYBE_EmulatedTouchPinchGoesToMainFrame \
- EmulatedTouchPinchGoesToMainFrame
-#endif
IN_PROC_BROWSER_TEST_P(SitePerProcessEmulatedTouchBrowserTest,
- MAYBE_EmulatedTouchPinchGoesToMainFrame) {
+ EmulatedTouchPinchGoesToMainFrame) {
RunTest(PinchGoesToMainFrame);
}
-#if defined(OS_CHROMEOS)
-// Flaky timeouts: https://crbug.com/833380
-#define MAYBE_EmulatedGestureScrollBubbles DISABLED_EmulatedGestureScrollBubbles
-#else
-#define MAYBE_EmulatedGestureScrollBubbles EmulatedGestureScrollBubbles
-#endif
-
IN_PROC_BROWSER_TEST_P(SitePerProcessEmulatedTouchBrowserTest,
- MAYBE_EmulatedGestureScrollBubbles) {
+ EmulatedGestureScrollBubbles) {
RunTest(TouchActionBubbling);
}
+#if defined(OS_ANDROID) || defined(USE_AURA)
+namespace {
+// This function is used in TouchActionAckTimeout and
+// SubframeGestureEventRouting, which is defined either under Android or Aura.
+void OnSyntheticGestureCompleted(scoped_refptr<MessageLoopRunner> runner,
+ SyntheticGesture::Result result) {
+ EXPECT_EQ(SyntheticGesture::GESTURE_FINISHED, result);
+ runner->Quit();
+}
+
+#if defined(OS_ANDROID)
+void GiveItSomeTime(int t) {
+ base::RunLoop run_loop;
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitClosure(), base::TimeDelta::FromMilliseconds(t));
+ run_loop.Run();
+}
+#endif // defined(OS_ANDROID)
+
+} // namespace
+#endif // defined(OS_ANDROID) || defined(USE_AURA)
+
+// Regression test for https://crbug.com/851644. The test passes as long as it
+// doesn't crash.
+// Touch action ack timeout is enabled on Android only.
+// Flaky, see https://crbug.com/871062.
+#if defined(OS_ANDROID)
+IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
+ DISABLED_TouchActionAckTimeout) {
+ GURL main_url(
+ embedded_test_server()->GetURL("/frame_tree/page_with_janky_frame.html"));
+ ASSERT_TRUE(NavigateToURL(shell(), main_url));
+ FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+ ASSERT_EQ(1U, root->child_count());
+ GURL frame_url(embedded_test_server()->GetURL(
+ "baz.com", "/page_with_touch_start_janking_main_thread.html"));
+ auto* child_frame_host = root->child_at(0)->current_frame_host();
+
+ RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
+ root->current_frame_host()->GetRenderWidgetHost()->GetView());
+ RenderWidgetHostViewChildFrame* rwhv_child =
+ static_cast<RenderWidgetHostViewChildFrame*>(
+ child_frame_host->GetRenderWidgetHost()->GetView());
+
+ WaitForHitTestDataOrChildSurfaceReady(child_frame_host);
+
+ // Compute the point so that the gesture event can target the child frame.
+ const gfx::Rect root_bounds = rwhv_root->GetViewBounds();
+ const gfx::Rect child_bounds = rwhv_child->GetViewBounds();
+ RenderFrameSubmissionObserver render_frame_submission_observer(
+ shell()->web_contents());
+ const float page_scale_factor =
+ render_frame_submission_observer.LastRenderFrameMetadata()
+ .page_scale_factor;
+ const gfx::PointF point_in_child(
+ (child_bounds.x() - root_bounds.x() + 25) * page_scale_factor,
+ (child_bounds.y() - root_bounds.y() + 25) * page_scale_factor);
+
+ SyntheticSmoothScrollGestureParams params;
+ params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
+ params.anchor = gfx::PointF(point_in_child.x(), point_in_child.y());
+ params.distances.push_back(gfx::Vector2dF(0, -10));
+ // Make this scroll slow so that the second scroll will be queued even before
+ // this one ends.
+ params.speed_in_pixels_s = 1000;
+ std::unique_ptr<SyntheticSmoothScrollGesture> gesture(
+ new SyntheticSmoothScrollGesture(params));
+
+ scoped_refptr<MessageLoopRunner> runner = new MessageLoopRunner();
+ RenderWidgetHostImpl* render_widget_host =
+ root->current_frame_host()->GetRenderWidgetHost();
+ render_widget_host->QueueSyntheticGesture(
+ std::move(gesture), base::BindOnce(OnSyntheticGestureCompleted, runner));
+ // The first gesture takes 100ms, so wait for 120ms to ensure that it has
+ // finished.
+ runner->Run();
+ GiveItSomeTime(120);
+
+ SyntheticSmoothScrollGestureParams params2;
+ params2.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
+ params2.anchor = gfx::PointF(point_in_child.x(), point_in_child.y());
+ params2.distances.push_back(gfx::Vector2dF(0, -10));
+ params2.speed_in_pixels_s = 100000;
+ std::unique_ptr<SyntheticSmoothScrollGesture> gesture2(
+ new SyntheticSmoothScrollGesture(params2));
+ render_widget_host->QueueSyntheticGesture(
+ std::move(gesture2), base::BindOnce(OnSyntheticGestureCompleted, runner));
+
+ runner->Run();
+ runner = nullptr;
+
+ // Give enough time to make sure all gesture are flushed and handled.
+ base::RunLoop run_loop;
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitClosure(),
+ base::TimeDelta::FromMilliseconds(2500));
+ run_loop.Run();
+}
+#endif // defined(OS_ANDROID)
+
#if defined(USE_AURA) || defined(OS_ANDROID)
// When unconsumed scrolls in a child bubble to the root and start an
@@ -1316,14 +1623,6 @@ IN_PROC_BROWSER_TEST_P(SitePerProcessEmulatedTouchBrowserTest,
// overscroll gesture.
IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
RootConsumesScrollDuringOverscrollGesture) {
-#if defined(OS_ANDROID)
- // TODO(835058): Fix flakiness on android with viz hit testing.
- if (features::IsVizHitTestingEnabled()) {
- LOG(INFO) << "Skipping test due to https://crbug.com/835058";
- return;
- }
-#endif
-
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -1668,7 +1967,11 @@ IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
// Since we are targeting child, event dispatch should not happen
// synchronously. Validate that the expected target does not receive the
// event immediately.
- EXPECT_FALSE(child_frame_monitor.EventWasReceived());
+ // When V2 surface layer hit testing is enabled, we expect to do synchronous
+ // event targeting on a child under some circumstances, so we expect the event
+ // immediately dispatched to the child.
+ if (!features::IsVizHitTestingSurfaceLayerEnabled())
+ EXPECT_FALSE(child_frame_monitor.EventWasReceived());
waiter.Wait();
EXPECT_TRUE(child_frame_monitor.EventWasReceived());
@@ -1731,19 +2034,44 @@ IN_PROC_BROWSER_TEST_P(SitePerProcessHighDPIHitTestBrowserTest,
NestedSurfaceHitTestTestHelper(shell(), embedded_test_server());
}
-#if defined(OS_LINUX)
-// Flaky timeouts and failures: https://crbug.com/833380
-#define MAYBE_OverlapSurfaceHitTestTest DISABLED_OverlapSurfaceHitTestTest
+IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
+ NonFlatTransformedSurfaceHitTestTest) {
+ NonFlatTransformedSurfaceHitTestHelper(shell(), embedded_test_server());
+}
+
+IN_PROC_BROWSER_TEST_P(SitePerProcessHighDPIHitTestBrowserTest,
+ NonFlatTransformedSurfaceHitTestTest) {
+ NonFlatTransformedSurfaceHitTestHelper(shell(), embedded_test_server());
+}
+
+// TODO(kenrb): Running this test on Android bots has slight discrepancies in
+// transformed event coordinates when we do manual calculation of expected
+// values. We can't rely on browser side transformation because it is broken
+// for perspective transforms. See https://crbug.com/854247.
+#if defined(OS_ANDROID)
+#define MAYBE_PerspectiveTransformedSurfaceHitTestTest \
+ DISABLED_PerspectiveTransformedSurfaceHitTestTest
#else
-#define MAYBE_OverlapSurfaceHitTestTest OverlapSurfaceHitTestTest
+#define MAYBE_PerspectiveTransformedSurfaceHitTestTest \
+ PerspectiveTransformedSurfaceHitTestTest
#endif
+IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
+ MAYBE_PerspectiveTransformedSurfaceHitTestTest) {
+ PerspectiveTransformedSurfaceHitTestHelper(shell(), embedded_test_server());
+}
+
+IN_PROC_BROWSER_TEST_P(SitePerProcessHighDPIHitTestBrowserTest,
+ MAYBE_PerspectiveTransformedSurfaceHitTestTest) {
+ PerspectiveTransformedSurfaceHitTestHelper(shell(), embedded_test_server());
+}
+
IN_PROC_BROWSER_TEST_P(SitePerProcessHighDPIHitTestBrowserTest,
- MAYBE_OverlapSurfaceHitTestTest) {
+ OverlapSurfaceHitTestTest) {
OverlapSurfaceHitTestHelper(shell(), embedded_test_server());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
- MAYBE_OverlapSurfaceHitTestTest) {
+ OverlapSurfaceHitTestTest) {
OverlapSurfaceHitTestHelper(shell(), embedded_test_server());
}
@@ -1780,12 +2108,13 @@ IN_PROC_BROWSER_TEST_P(SitePerProcessHighDPIHitTestBrowserTest,
}
#if defined(USE_AURA)
-IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest, RootWindowTransform) {
+IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
+ DISABLED_RootWindowTransform) {
HitTestRootWindowTransform(shell(), embedded_test_server());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessHighDPIHitTestBrowserTest,
- RootWindowTransform) {
+ DISABLED_RootWindowTransform) {
HitTestRootWindowTransform(shell(), embedded_test_server());
}
#endif // defined(USE_AURA)
@@ -1882,6 +2211,12 @@ IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
// pointer-events: none.
IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
MAYBE_SurfaceHitTestPointerEventsNone) {
+ // TODO(sunxd): Fix pointer-events none for surface layer viz hit testing. See
+ // https://crbug.com/841358.
+ if (features::IsVizHitTestingSurfaceLayerEnabled()) {
+ LOG(INFO) << "Skipping test due to https://crbug.com/841358";
+ return;
+ }
GURL main_url(embedded_test_server()->GetURL(
"/frame_tree/page_with_positioned_frame_pointer-events_none.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -2355,8 +2690,14 @@ IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
// TODO(kenrb): This currently only works for scrollbar dragging.
// Other reasons for a node to capture mouse input need to be addressed. See
// https://crbug.com/647378.
+#if defined(OS_CHROMEOS)
+// TODO: Flaky on Chrome OS. crbug.com/868409
+#define MAYBE_CrossProcessMouseCapture DISABLED_CrossProcessMouseCapture
+#else
+#define MAYBE_CrossProcessMouseCapture CrossProcessMouseCapture
+#endif
IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
- CrossProcessMouseCapture) {
+ MAYBE_CrossProcessMouseCapture) {
GURL main_url(embedded_test_server()->GetURL(
"/frame_tree/page_with_large_scrollable_frame.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -2496,6 +2837,113 @@ IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
#endif // !defined(OS_MACOSX) && !defined(OS_ANDROID)
}
+IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
+ MouseCaptureOnDragSelection) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "/frame_tree/page_with_positioned_frame.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ RenderFrameSubmissionObserver render_frame_submission_observer(
+ shell()->web_contents());
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+ ASSERT_EQ(1U, root->child_count());
+
+ FrameTreeNode* child_node = root->child_at(0);
+ ASSERT_EQ(
+ " Site A ------------ proxies for B\n"
+ " +--Site B ------- proxies for A\n"
+ "Where A = http://127.0.0.1/\n"
+ " B = http://baz.com/",
+ DepictFrameTree(root));
+
+ // Create listeners for mouse events.
+ RenderWidgetHostMouseEventMonitor main_frame_monitor(
+ root->current_frame_host()->GetRenderWidgetHost());
+ RenderWidgetHostMouseEventMonitor child_frame_monitor(
+ child_node->current_frame_host()->GetRenderWidgetHost());
+
+ RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
+ child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+ WaitForHitTestDataOrChildSurfaceReady(child_node->current_frame_host());
+
+ // Target MouseDown to child frame.
+ blink::WebMouseEvent mouse_event(
+ blink::WebInputEvent::kMouseDown, blink::WebInputEvent::kNoModifiers,
+ blink::WebInputEvent::GetStaticTimeStampForTests());
+ mouse_event.button = blink::WebPointerProperties::Button::kLeft;
+ mouse_event.click_count = 1;
+ main_frame_monitor.ResetEventReceived();
+ child_frame_monitor.ResetEventReceived();
+ DispatchMouseEventAndWaitUntilDispatch(web_contents(), mouse_event,
+ rwhv_child, gfx::PointF(15.0, 5.0),
+ rwhv_child, gfx::PointF(15.0, 5.0));
+
+ EXPECT_FALSE(main_frame_monitor.EventWasReceived());
+ EXPECT_TRUE(child_frame_monitor.EventWasReceived());
+ main_frame_monitor.ResetEventReceived();
+ child_frame_monitor.ResetEventReceived();
+
+ scoped_refptr<SetMouseCaptureInterceptor> interceptor =
+ new SetMouseCaptureInterceptor(static_cast<RenderWidgetHostImpl*>(
+ child_node->current_frame_host()->GetRenderWidgetHost()));
+
+ // Target MouseMove to child frame to start drag. This should cause the
+ // child to start capturing mouse input.
+ mouse_event.SetType(blink::WebInputEvent::kMouseMove);
+ mouse_event.SetModifiers(blink::WebInputEvent::kLeftButtonDown);
+ DispatchMouseEventAndWaitUntilDispatch(web_contents(), mouse_event,
+ rwhv_child, gfx::PointF(5.0, 5.0),
+ rwhv_child, gfx::PointF(5.0, 5.0));
+
+ // Dispatch twice because the router generates an extra MouseLeave for the
+ // main frame.
+ main_frame_monitor.ResetEventReceived();
+ child_frame_monitor.ResetEventReceived();
+ DispatchMouseEventAndWaitUntilDispatch(web_contents(), mouse_event,
+ rwhv_child, gfx::PointF(5.0, 5.0),
+ rwhv_child, gfx::PointF(5.0, 5.0));
+
+ EXPECT_FALSE(main_frame_monitor.EventWasReceived());
+ EXPECT_TRUE(child_frame_monitor.EventWasReceived());
+ main_frame_monitor.ResetEventReceived();
+ child_frame_monitor.ResetEventReceived();
+
+ // Wait for the mouse capture message.
+ interceptor->Wait();
+ EXPECT_TRUE(interceptor->Capturing());
+ // Yield the thread, in order to let the capture message be processed by its
+ // actual handler.
+ {
+ base::RunLoop loop;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ loop.QuitClosure());
+ loop.Run();
+ }
+
+ // Now that the child frame is capturing, a MouseMove targeted to the main
+ // frame should be received by the child frame.
+ DispatchMouseEventAndWaitUntilDispatch(web_contents(), mouse_event,
+ rwhv_child, gfx::PointF(-25.0, -25.0),
+ rwhv_child, gfx::PointF(-25.0, -25.0));
+ EXPECT_FALSE(main_frame_monitor.EventWasReceived());
+ EXPECT_TRUE(child_frame_monitor.EventWasReceived());
+ main_frame_monitor.ResetEventReceived();
+ child_frame_monitor.ResetEventReceived();
+
+ // A MouseUp sent anywhere should cancel the mouse capture.
+ mouse_event.SetType(blink::WebInputEvent::kMouseUp);
+ mouse_event.SetModifiers(0);
+ DispatchMouseEventAndWaitUntilDispatch(web_contents(), mouse_event,
+ rwhv_child, gfx::PointF(-25.0, -25.0),
+ rwhv_child, gfx::PointF(-25.0, -25.0));
+
+ interceptor->Wait();
+ EXPECT_FALSE(interceptor->Capturing());
+}
+
// There are no cursors on Android.
#if !defined(OS_ANDROID)
class CursorMessageFilter : public content::BrowserMessageFilter {
@@ -2916,9 +3364,9 @@ IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
// will trigger kTouchActionNone being sent back to the browser.
RenderWidgetHostImpl* child_render_widget_host =
root->child_at(0)->current_frame_host()->GetRenderWidgetHost();
- EXPECT_EQ(true, child_render_widget_host->input_router()
- ->AllowedTouchAction()
- .has_value());
+ EXPECT_FALSE(child_render_widget_host->input_router()
+ ->AllowedTouchAction()
+ .has_value());
InputEventAckWaiter waiter(child_render_widget_host,
blink::WebInputEvent::kTouchStart);
@@ -2992,8 +3440,7 @@ IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
// browser.
RenderWidgetHostImpl* render_widget_host =
root->current_frame_host()->GetRenderWidgetHost();
- EXPECT_EQ(
- true,
+ EXPECT_FALSE(
render_widget_host->input_router()->AllowedTouchAction().has_value());
// Simulate touch event to sub-frame.
@@ -3034,17 +3481,6 @@ IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
render_widget_host->input_router()->AllowedTouchAction());
}
-namespace {
-
-// Declared here to be close to the SubframeGestureEventRouting test.
-void OnSyntheticGestureCompleted(scoped_refptr<MessageLoopRunner> runner,
- SyntheticGesture::Result result) {
- EXPECT_EQ(SyntheticGesture::GESTURE_FINISHED, result);
- runner->Quit();
-}
-
-} // anonymous namespace
-
// https://crbug.com/592320
IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
DISABLED_SubframeGestureEventRouting) {
@@ -3242,8 +3678,12 @@ void SendTouchpadPinchSequenceWithExpectedTarget(
// targeting first. So event dispatch should not happen synchronously.
// Validate that the expected target does not receive the event immediately in
// such cases.
- if (root_view != expected_target)
+ // V2 surface layer hit testing cannot handle pointer-events: none elements
+ // yet, see https://crbug.com/841358.
+ if (root_view != expected_target &&
+ !features::IsVizHitTestingSurfaceLayerEnabled()) {
EXPECT_FALSE(target_monitor.EventWasReceived());
+ }
waiter.Wait();
EXPECT_TRUE(target_monitor.EventWasReceived());
EXPECT_EQ(expected_target, router_touchpad_gesture_target);
@@ -3294,13 +3734,20 @@ void SendTouchpadFlingSequenceWithExpectedTarget(
InputEventAckWaiter fling_start_waiter(
expected_target->GetRenderWidgetHost(),
blink::WebInputEvent::kGestureFlingStart);
+ InputMsgWatcher gestrue_scroll_end_waiter(
+ expected_target->GetRenderWidgetHost(),
+ blink::WebInputEvent::kGestureScrollEnd);
root_view_aura->OnScrollEvent(&fling_start);
// If the expected target is not the root, then we should be doing async
// targeting first. So event dispatch should not happen synchronously.
// Validate that the expected target does not receive the event immediately in
// such cases.
- if (root_view != expected_target)
+ // When V2 surface layer hit testing is enabled, we should synchronously
+ // target the event to the child.
+ if (root_view != expected_target &&
+ !features::IsVizHitTestingSurfaceLayerEnabled()) {
EXPECT_FALSE(target_monitor.EventWasReceived());
+ }
fling_start_waiter.Wait();
EXPECT_TRUE(target_monitor.EventWasReceived());
EXPECT_EQ(expected_target, router_wheel_target);
@@ -3309,9 +3756,6 @@ void SendTouchpadFlingSequenceWithExpectedTarget(
// Send a GFC event, the fling_controller will process the GFC and stop the
// fling by generating a wheel event with phaseEnded. The
// mouse_wheel_event_queue will process the wheel event and generate a GSE.
- InputEventAckWaiter gestrue_scroll_end_waiter(
- expected_target->GetRenderWidgetHost(),
- blink::WebInputEvent::kGestureScrollEnd);
InputEventAckWaiter fling_cancel_waiter(
expected_target->GetRenderWidgetHost(),
blink::WebInputEvent::kGestureFlingCancel);
@@ -3319,7 +3763,9 @@ void SendTouchpadFlingSequenceWithExpectedTarget(
ui::EventTimeForNow(), 0, 1, 0, 1, 0, 1);
UpdateEventRootLocation(&fling_cancel, root_view_aura);
root_view_aura->OnScrollEvent(&fling_cancel);
- gestrue_scroll_end_waiter.Wait();
+ // Since the fling velocity is small, sometimes the fling is over before
+ // sending the GFC event.
+ gestrue_scroll_end_waiter.GetAckStateWaitIfNecessary();
fling_cancel_waiter.Wait();
}
#endif // !defined(OS_WIN)
@@ -3508,14 +3954,6 @@ IN_PROC_BROWSER_TEST_P(
IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
InputEventRouterTouchpadGestureTargetTest) {
-#if defined(OS_WIN)
- // TODO(838835): Flaky with viz hit testing
- if (features::IsVizHitTestingEnabled()) {
- LOG(INFO) << "Skipping test due to https://crbug.com/838835";
- return;
- }
-#endif
-
GURL main_url(embedded_test_server()->GetURL(
"/frame_tree/page_with_positioned_nested_frames.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -3609,13 +4047,7 @@ IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
// wheel events to the child and causes the page scale factor to change for
// the main frame (given that the child did not consume the wheel).
IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
- TouchpadPinchOverOOPIF) {
- // TODO(crbug.com/853761): Flaky with viz hit testing
- if (features::IsVizHitTestingEnabled()) {
- LOG(INFO) << "Skipping test due to https://crbug.com/853761";
- return;
- }
-
+ MAYBE_TouchpadPinchOverOOPIF) {
GURL main_url(embedded_test_server()->GetURL(
"/frame_tree/page_with_positioned_frame.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -4262,6 +4694,89 @@ class SitePerProcessGestureHitTestBrowserTest
rwhi_root_ = root_node->current_frame_host()->GetRenderWidgetHost();
}
+ void SubframeGesturePinchTestHelper(const std::string& url,
+ bool reset_root_touch_action) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(b)"));
+
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ // It is safe to obtain the root frame tree node here, as it doesn't change.
+ FrameTreeNode* root_node =
+ static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+ ASSERT_EQ(1U, root_node->child_count());
+
+ FrameTreeNode* child_node = root_node->child_at(0);
+ GURL b_url(embedded_test_server()->GetURL("b.com", url));
+ NavigateFrameToURL(child_node, b_url);
+
+ ASSERT_EQ(
+ " Site A ------------ proxies for B\n"
+ " +--Site B ------- proxies for A\n"
+ "Where A = http://a.com/\n"
+ " B = http://b.com/",
+ DepictFrameTree(root_node));
+
+ rwhv_child_ = static_cast<RenderWidgetHostViewBase*>(
+ child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+ rwhva_root_ = static_cast<RenderWidgetHostViewAura*>(
+ shell()->web_contents()->GetRenderWidgetHostView());
+
+ WaitForHitTestDataOrChildSurfaceReady(child_node->current_frame_host());
+
+ MainThreadFrameObserver observer(rwhv_child_->GetRenderWidgetHost());
+ observer.Wait();
+
+ rwhi_child_ = child_node->current_frame_host()->GetRenderWidgetHost();
+ rwhi_root_ = root_node->current_frame_host()->GetRenderWidgetHost();
+
+ TestInputEventObserver root_frame_monitor(rwhi_root_);
+ TestInputEventObserver child_frame_monitor(rwhi_child_);
+
+ gfx::Rect bounds = rwhv_child_->GetViewBounds();
+ bounds.Offset(gfx::Point() - rwhva_root_->GetViewBounds().origin());
+
+ // The pinch gesture will always sent to the root frame even if the fingers
+ // are targeting the iframe. In this case, the test should not crash.
+ if (reset_root_touch_action) {
+ static_cast<InputRouterImpl*>(
+ static_cast<RenderWidgetHostImpl*>(rwhva_root_->GetRenderWidgetHost())
+ ->input_router())
+ ->OnHasTouchEventHandlersForTest(true);
+ }
+ SendPinchBeginEndSequence(rwhva_root_, bounds.CenterPoint(), rwhi_child_);
+
+ if (reset_root_touch_action)
+ return;
+
+ // Verify that root-RWHI gets nothing.
+ EXPECT_FALSE(root_frame_monitor.EventWasReceived());
+ // Verify that child-RWHI gets TS/GTD/GSB/GPB/GPE/GSE/TE.
+ EXPECT_EQ(blink::WebInputEvent::kTouchStart,
+ child_frame_monitor.events_received()[0]);
+ EXPECT_EQ(blink::WebInputEvent::kGestureTapDown,
+ child_frame_monitor.events_received()[1]);
+ EXPECT_EQ(blink::WebInputEvent::kGestureScrollBegin,
+ child_frame_monitor.events_received()[2]);
+ EXPECT_EQ(blink::WebInputEvent::kGesturePinchBegin,
+ child_frame_monitor.events_received()[3]);
+ EXPECT_EQ(blink::WebInputEvent::kGesturePinchEnd,
+ child_frame_monitor.events_received()[4]);
+ EXPECT_EQ(blink::WebInputEvent::kGestureScrollEnd,
+ child_frame_monitor.events_received()[5]);
+ EXPECT_EQ(blink::WebInputEvent::kTouchEnd,
+ child_frame_monitor.events_received()[6]);
+
+ // Verify that the pinch gestures are consumed by browser.
+ EXPECT_EQ(InputEventAckSource::BROWSER,
+ child_frame_monitor.events_acked()[3]);
+ EXPECT_EQ(InputEventAckSource::BROWSER,
+ child_frame_monitor.events_acked()[4]);
+ }
+
protected:
RenderWidgetHostViewBase* rwhv_child_;
RenderWidgetHostViewAura* rwhva_root_;
@@ -4347,75 +4862,12 @@ IN_PROC_BROWSER_TEST_P(SitePerProcessGestureHitTestBrowserTest,
IN_PROC_BROWSER_TEST_P(SitePerProcessGestureHitTestBrowserTest,
SubframeGesturePinchDeniedBySubframeTouchAction) {
- GURL main_url(embedded_test_server()->GetURL(
- "a.com", "/cross_site_iframe_factory.html?a(b)"));
-
- EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
- // It is safe to obtain the root frame tree node here, as it doesn't change.
- FrameTreeNode* root_node =
- static_cast<WebContentsImpl*>(shell()->web_contents())
- ->GetFrameTree()
- ->root();
- ASSERT_EQ(1U, root_node->child_count());
-
- FrameTreeNode* child_node = root_node->child_at(0);
- GURL b_url(embedded_test_server()->GetURL(
- "b.com", "/div_with_touch_action_none.html"));
- NavigateFrameToURL(child_node, b_url);
-
- ASSERT_EQ(
- " Site A ------------ proxies for B\n"
- " +--Site B ------- proxies for A\n"
- "Where A = http://a.com/\n"
- " B = http://b.com/",
- DepictFrameTree(root_node));
-
- rwhv_child_ = static_cast<RenderWidgetHostViewBase*>(
- child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
-
- rwhva_root_ = static_cast<RenderWidgetHostViewAura*>(
- shell()->web_contents()->GetRenderWidgetHostView());
-
- WaitForHitTestDataOrChildSurfaceReady(child_node->current_frame_host());
-
- MainThreadFrameObserver observer(rwhv_child_->GetRenderWidgetHost());
- observer.Wait();
-
- rwhi_child_ = child_node->current_frame_host()->GetRenderWidgetHost();
- rwhi_root_ = root_node->current_frame_host()->GetRenderWidgetHost();
-
- TestInputEventObserver root_frame_monitor(rwhi_root_);
- TestInputEventObserver child_frame_monitor(rwhi_child_);
-
- gfx::Rect bounds = rwhv_child_->GetViewBounds();
- bounds.Offset(gfx::Point() - rwhva_root_->GetViewBounds().origin());
-
- SendPinchBeginEndSequence(rwhva_root_, bounds.CenterPoint(), rwhi_child_);
-
- // Verify that root-RWHI gets nothing.
- EXPECT_FALSE(root_frame_monitor.EventWasReceived());
- // Verify that child-RWHI gets TS/GTD/GSB/GPB/GPE/GSE/TE.
- EXPECT_EQ(blink::WebInputEvent::kTouchStart,
- child_frame_monitor.events_received()[0]);
- EXPECT_EQ(blink::WebInputEvent::kGestureTapDown,
- child_frame_monitor.events_received()[1]);
- EXPECT_EQ(blink::WebInputEvent::kGestureScrollBegin,
- child_frame_monitor.events_received()[2]);
- EXPECT_EQ(blink::WebInputEvent::kGesturePinchBegin,
- child_frame_monitor.events_received()[3]);
- EXPECT_EQ(blink::WebInputEvent::kGesturePinchEnd,
- child_frame_monitor.events_received()[4]);
- EXPECT_EQ(blink::WebInputEvent::kGestureScrollEnd,
- child_frame_monitor.events_received()[5]);
- EXPECT_EQ(blink::WebInputEvent::kTouchEnd,
- child_frame_monitor.events_received()[6]);
+ SubframeGesturePinchTestHelper("/div_with_touch_action_none.html", false);
+}
- // Verify that the pinch gestures are consumed by browser.
- EXPECT_EQ(InputEventAckSource::BROWSER,
- child_frame_monitor.events_acked()[3]);
- EXPECT_EQ(InputEventAckSource::BROWSER,
- child_frame_monitor.events_acked()[4]);
+IN_PROC_BROWSER_TEST_P(SitePerProcessGestureHitTestBrowserTest,
+ SubframeGesturePinchNoCrash) {
+ SubframeGesturePinchTestHelper("/div_with_touch_action_auto.html", true);
}
#endif // defined(USE_AURA)
@@ -4526,40 +4978,379 @@ IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest, HitTestNestedFrames) {
{
base::RunLoop run_loop;
viz::FrameSinkId received_frame_sink_id;
+ gfx::PointF returned_point;
base::Closure quit_closure =
content::GetDeferredQuitTaskForRunLoop(&run_loop);
DCHECK_NE(child_node->current_frame_host()->GetInputTargetClient(),
nullptr);
child_node->current_frame_host()->GetInputTargetClient()->FrameSinkIdAt(
point_in_child,
- base::BindLambdaForTesting([&](const viz::FrameSinkId& id) {
- received_frame_sink_id = id;
- quit_closure.Run();
- }));
+ base::BindLambdaForTesting(
+ [&](const viz::FrameSinkId& id, const gfx::PointF& point) {
+ received_frame_sink_id = id;
+ returned_point = point;
+ quit_closure.Run();
+ }));
content::RunThisRunLoop(&run_loop);
// |point_in_child| should hit test to the view for |child_node|.
ASSERT_EQ(rwhv_child->GetFrameSinkId(), received_frame_sink_id);
+ ASSERT_EQ(gfx::PointF(1, 1), returned_point);
}
{
base::RunLoop run_loop;
viz::FrameSinkId received_frame_sink_id;
+ gfx::PointF returned_point;
base::Closure quit_closure =
content::GetDeferredQuitTaskForRunLoop(&run_loop);
DCHECK_NE(child_node->current_frame_host()->GetInputTargetClient(),
nullptr);
child_node->current_frame_host()->GetInputTargetClient()->FrameSinkIdAt(
gfx::ToCeiledPoint(point_in_nested_child),
- base::BindLambdaForTesting([&](const viz::FrameSinkId& id) {
- received_frame_sink_id = id;
- quit_closure.Run();
- }));
+ base::BindLambdaForTesting(
+ [&](const viz::FrameSinkId& id, const gfx::PointF& point) {
+ received_frame_sink_id = id;
+ returned_point = point;
+ quit_closure.Run();
+ }));
content::RunThisRunLoop(&run_loop);
// |point_in_nested_child| should hit test to |rwhv_grandchild|.
ASSERT_EQ(rwhv_grandchild->GetFrameSinkId(), received_frame_sink_id);
+ EXPECT_NEAR(returned_point.x(), 5, 2);
+ EXPECT_NEAR(returned_point.y(), 5, 2);
}
}
+class SitePerProcessHitTestDataGenerationBrowserTest
+ : public SitePerProcessHitTestBrowserTest {
+ public:
+ SitePerProcessHitTestDataGenerationBrowserTest() {}
+
+ protected:
+ // Load the page |host_name| and retrieve the hit test data from HitTestQuery.
+ std::vector<viz::AggregatedHitTestRegion> SetupAndGetHitTestData(
+ const std::string& host_name) {
+ GURL main_url(embedded_test_server()->GetURL(host_name));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+ ->GetFrameTree()
+ ->root();
+
+ RenderWidgetHostViewBase* rwhv_root =
+ static_cast<RenderWidgetHostViewBase*>(
+ root->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+ for (unsigned i = 0; i < root->child_count(); i++) {
+ WaitForHitTestDataOrChildSurfaceReady(
+ root->child_at(i)->current_frame_host());
+ }
+
+ HitTestRegionObserver observer(rwhv_root->GetRootFrameSinkId());
+ observer.WaitForHitTestData();
+
+ device_scale_factor_ = rwhv_root->GetDeviceScaleFactor();
+ DCHECK_GT(device_scale_factor_, 0);
+
+ return observer.GetHitTestData();
+ }
+
+ float current_device_scale_factor() const { return device_scale_factor_; }
+
+ gfx::QuadF TransformRectToQuadF(const gfx::Rect& rect,
+ const gfx::Transform& transform,
+ bool use_scale_factor = true) {
+ gfx::Rect scaled_rect =
+ use_scale_factor ? gfx::ScaleToEnclosingRect(rect, device_scale_factor_,
+ device_scale_factor_)
+ : rect;
+ gfx::PointF p1(scaled_rect.origin());
+ gfx::PointF p2(scaled_rect.top_right());
+ gfx::PointF p3(scaled_rect.bottom_right());
+ gfx::PointF p4(scaled_rect.bottom_left());
+ transform.TransformPoint(&p1);
+ transform.TransformPoint(&p2);
+ transform.TransformPoint(&p3);
+ transform.TransformPoint(&p4);
+ return gfx::QuadF(p1, p2, p3, p4);
+ }
+
+ gfx::QuadF TransformRectToQuadF(
+ const viz::AggregatedHitTestRegion& hit_test_region) {
+ return TransformRectToQuadF(hit_test_region.rect,
+ hit_test_region.transform(), false);
+ }
+
+ bool ApproximatelyEqual(const gfx::PointF& p1, const gfx::PointF& p2) const {
+ return std::abs(p1.x() - p2.x()) <= 1 && std::abs(p1.y() - p2.y()) <= 1;
+ }
+
+ bool ApproximatelyEqual(const gfx::QuadF& quad,
+ const gfx::QuadF& other) const {
+ return ApproximatelyEqual(quad.p1(), other.p1()) &&
+ ApproximatelyEqual(quad.p2(), other.p2()) &&
+ ApproximatelyEqual(quad.p3(), other.p3()) &&
+ ApproximatelyEqual(quad.p4(), other.p4());
+ }
+
+ gfx::Rect AxisAlignedLayoutRectFromHitTest(
+ const viz::AggregatedHitTestRegion& hit_test_region) {
+ DCHECK(hit_test_region.transform().Preserves2dAxisAlignment());
+ gfx::RectF rect(hit_test_region.rect);
+ hit_test_region.transform().TransformRect(&rect);
+ return gfx::ToEnclosingRect(rect);
+ }
+
+ public:
+ static const uint32_t kFastHitTestFlags;
+ static const uint32_t kSlowHitTestFlags;
+ float device_scale_factor_;
+};
+
+const uint32_t
+ SitePerProcessHitTestDataGenerationBrowserTest::kFastHitTestFlags =
+ viz::HitTestRegionFlags::kHitTestMine |
+ viz::HitTestRegionFlags::kHitTestChildSurface |
+ viz::HitTestRegionFlags::kHitTestMouse |
+ viz::HitTestRegionFlags::kHitTestTouch;
+
+const uint32_t
+ SitePerProcessHitTestDataGenerationBrowserTest::kSlowHitTestFlags =
+ SitePerProcessHitTestDataGenerationBrowserTest::kFastHitTestFlags |
+ viz::HitTestRegionFlags::kHitTestAsk;
+
+IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestDataGenerationBrowserTest,
+ TransformedOOPIF) {
+ if (!features::IsVizHitTestingEnabled())
+ return;
+ auto hit_test_data =
+ SetupAndGetHitTestData("/frame_tree/page_with_transformed_iframe.html");
+ float device_scale_factor = current_device_scale_factor();
+
+ // Compute screen space transform for iframe element.
+ gfx::Transform expected_transform;
+ gfx::Transform translate;
+ expected_transform.RotateAboutZAxis(-45);
+ translate.Translate(-100 * device_scale_factor, -100 * device_scale_factor);
+ expected_transform.PreconcatTransform(translate);
+
+ DCHECK(hit_test_data.size() >= 3);
+ // The iframe element in main page is transformed and also clips the content
+ // of the subframe, so we expect to do slow path hit testing in this case.
+ // TODO(sunxd): We should do fast path hit testing in this case. See
+ // https://crbug.com/851507.
+ EXPECT_TRUE(ApproximatelyEqual(
+ TransformRectToQuadF(gfx::Rect(100, 100), expected_transform),
+ TransformRectToQuadF(hit_test_data[2])));
+ EXPECT_EQ(kSlowHitTestFlags, hit_test_data[2].flags);
+}
+
+IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestDataGenerationBrowserTest,
+ ClippedOOPIFFastPath) {
+ if (!features::IsVizHitTestingEnabled())
+ return;
+ auto hit_test_data =
+ SetupAndGetHitTestData("/frame_tree/page_with_clipped_iframe.html");
+ float device_scale_factor = current_device_scale_factor();
+ gfx::Transform expected_transform;
+ // In V1 hit testing or V2 hit testing slow path, we expected unclipped iframe
+ // bounds in its own space.
+ gfx::Rect original_region(200, 200);
+ gfx::Rect expected_transformed_region = gfx::ScaleToEnclosingRect(
+ original_region, device_scale_factor, device_scale_factor);
+
+ uint32_t expected_flags = kFastHitTestFlags;
+ // Clip2 has overflow: visible property, so it does not apply clip to iframe.
+ // Clip1 and clip3 all preserve 2d axis alignment, so we should allow fast
+ // path hit testing for the iframe in V2 hit testing.
+ // When VizDisplayCompositor is enabled, HitTestDataProviderDrawQuad will
+ // override LTHI's hit test data.
+ if (features::IsVizHitTestingDrawQuadEnabled()) {
+ // In V1 hit testing, we expect slow path and the submitted region should be
+ // equivalent to the unclipped iframe bounds.
+ expected_flags = kSlowHitTestFlags;
+ } else if (features::IsVizHitTestingSurfaceLayerEnabled()) {
+ // In V2 hit testing fast path, we expect precise clipped iframe bounds in
+ // its own space.
+ expected_transformed_region = gfx::ScaleToEnclosingRect(
+ gfx::Rect(100, 100), device_scale_factor, device_scale_factor);
+ }
+
+ // Apart from the iframe, it also contains data for root and main frame.
+ DCHECK(hit_test_data.size() >= 3);
+ EXPECT_TRUE(expected_transformed_region.ApproximatelyEqual(
+ AxisAlignedLayoutRectFromHitTest(hit_test_data[2]),
+ gfx::ToRoundedInt(device_scale_factor) + 2));
+ EXPECT_TRUE(
+ expected_transform.ApproximatelyEqual(hit_test_data[2].transform()));
+ EXPECT_EQ(expected_flags, hit_test_data[2].flags);
+}
+
+IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestDataGenerationBrowserTest,
+ RotatedClippedOOPIF) {
+ if (!features::IsVizHitTestingEnabled())
+ return;
+ auto hit_test_data = SetupAndGetHitTestData(
+ "/frame_tree/page_with_rotated_clipped_iframe.html");
+ float device_scale_factor = current_device_scale_factor();
+ // +-Root
+ // +---clip1
+ // +-----clip2 rotateZ(45)
+ // +-------clip3 rotateZ(-45)
+ // +---------iframe
+ //
+ // +----------------300px--------------+
+ // |\ |
+ // | \ |
+ // | \ 100px
+ // |- x --\ |
+ // | / |
+ // +-----------------------------------+
+ //
+ // Clipped region: x=100/sqrt(2), y=100.
+ gfx::Transform expected_transform;
+ gfx::Rect expected_region = gfx::ScaleToEnclosingRect(
+ gfx::Rect(200, 200), device_scale_factor, device_scale_factor);
+ if (!features::IsVizHitTestingDrawQuadEnabled()) {
+ expected_region = gfx::ScaleToEnclosingRect(
+ gfx::Rect(100 / 1.414, 100), device_scale_factor, device_scale_factor);
+ }
+
+ // Compute screen space transform for iframe element, since clip2 is rotated
+ // and also clips the iframe, we expect to do slow path hit test on the
+ // iframe.
+ DCHECK(hit_test_data.size() >= 3);
+ EXPECT_TRUE(expected_region.ApproximatelyEqual(hit_test_data[2].rect,
+ 1 + device_scale_factor));
+ EXPECT_TRUE(
+ expected_transform.ApproximatelyEqual(hit_test_data[2].transform()));
+ EXPECT_EQ(kSlowHitTestFlags, hit_test_data[2].flags);
+}
+
+IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestDataGenerationBrowserTest,
+ ClippedRotatedOOPIF) {
+ if (!features::IsVizHitTestingEnabled())
+ return;
+ auto hit_test_data = SetupAndGetHitTestData(
+ "/frame_tree/page_with_clipped_rotated_iframe.html");
+ float device_scale_factor = current_device_scale_factor();
+ // +-Root
+ // +---clip1
+ // +---------iframe rotateZ(45deg)
+ //
+ // There are actually 2 clips applied to surface layer, in root space they
+ // are:
+ // bounding box of clip1: rect 0, 0 300x100, transform = identity;
+ // bounding box of iframe itself: rect -100*sqrt(2), 0 200*sqrt(2)x200*sqrt(2)
+ // transform: rotateZ(45).
+ // In root space the two clips accumulates to:
+ // rect 0, 0 100*sqrt(2)x100, transform=identity
+ // Transform this to layer's local space, the clip rect is:
+ // rect 0, -100/sqrt(2) (100+100/sqrt(2))x(100/sqrt(2))
+ // So the intersected visible layer rect is:
+ // rect 0, 0, (100+100/sqrt(2)), 100/sqrt(2).
+ // +----------------300px--------------+
+ // |\ |
+ // | \ |
+ // | \x 100px
+ // | / \ |
+ // | /y \ |
+ // +-----------------------------------+
+ gfx::Transform expected_transform;
+ expected_transform.RotateAboutZAxis(-45);
+ gfx::Rect expected_region = gfx::ScaleToEnclosingRect(
+ gfx::Rect(200, 200), device_scale_factor, device_scale_factor);
+ if (!features::IsVizHitTestingDrawQuadEnabled()) {
+ expected_region =
+ gfx::ScaleToEnclosingRect(gfx::Rect(100 + 100 / 1.414f, 100 / 1.414f),
+ device_scale_factor, device_scale_factor);
+ }
+
+ // Since iframe is clipped into an octagon, we expect to do slow path hit
+ // test on the iframe.
+ DCHECK(hit_test_data.size() >= 3);
+ EXPECT_TRUE(expected_region.ApproximatelyEqual(hit_test_data[2].rect,
+ 1 + device_scale_factor));
+ EXPECT_TRUE(
+ expected_transform.ApproximatelyEqual(hit_test_data[2].transform()));
+ EXPECT_EQ(kSlowHitTestFlags, hit_test_data[2].flags);
+}
+
+IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestDataGenerationBrowserTest,
+ ClipPathOOPIF) {
+ if (!features::IsVizHitTestingEnabled())
+ return;
+ auto hit_test_data =
+ SetupAndGetHitTestData("/frame_tree/page_with_clip_path_iframe.html");
+ float device_scale_factor = current_device_scale_factor();
+ gfx::Transform expected_transform;
+ gfx::Rect expected_region = gfx::ScaleToEnclosingRect(
+ gfx::Rect(100, 100), device_scale_factor, device_scale_factor);
+ if (!features::IsVizHitTestingDrawQuadEnabled()) {
+ expected_region = gfx::ScaleToEnclosingRect(
+ gfx::Rect(80, 80), device_scale_factor, device_scale_factor);
+ }
+
+ // Since iframe is clipped into an octagon, we expect to do slow path hit
+ // test on the iframe.
+ DCHECK(hit_test_data.size() >= 3);
+ EXPECT_TRUE(expected_region.ApproximatelyEqual(hit_test_data[2].rect,
+ 1 + device_scale_factor));
+ EXPECT_TRUE(
+ expected_transform.ApproximatelyEqual(hit_test_data[2].transform()));
+ EXPECT_EQ(kSlowHitTestFlags, hit_test_data[2].flags);
+}
+
+IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestDataGenerationBrowserTest,
+ OverlappedOOPIF) {
+ if (!features::IsVizHitTestingEnabled())
+ return;
+ auto hit_test_data =
+ SetupAndGetHitTestData("/frame_tree/page_with_overlapped_iframes.html");
+ float device_scale_factor = current_device_scale_factor();
+ gfx::Transform expected_transform1;
+ gfx::Transform expected_transform2;
+ expected_transform2.matrix().postTranslate(-100 * device_scale_factor, 0, 0);
+
+ gfx::Rect expected_region = gfx::ScaleToEnclosingRect(
+ gfx::Rect(100, 100), device_scale_factor, device_scale_factor);
+
+ // Since iframe is occluded by a div in parent frame, we expect to do slow hit
+ // test.
+ DCHECK(hit_test_data.size() >= 4);
+ EXPECT_EQ(expected_region.ToString(), hit_test_data[3].rect.ToString());
+ EXPECT_TRUE(
+ expected_transform1.ApproximatelyEqual(hit_test_data[3].transform()));
+ EXPECT_EQ(kSlowHitTestFlags, hit_test_data[3].flags);
+ EXPECT_EQ(expected_region.ToString(), hit_test_data[2].rect.ToString());
+ EXPECT_TRUE(
+ expected_transform2.ApproximatelyEqual(hit_test_data[2].transform()));
+ if (features::IsVizHitTestingDrawQuadEnabled())
+ EXPECT_EQ(kSlowHitTestFlags, hit_test_data[2].flags);
+ else if (features::IsVizHitTestingSurfaceLayerEnabled())
+ EXPECT_EQ(kFastHitTestFlags, hit_test_data[2].flags);
+}
+
+IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestDataGenerationBrowserTest,
+ MaskedOOPIF) {
+ if (!features::IsVizHitTestingEnabled())
+ return;
+ auto hit_test_data =
+ SetupAndGetHitTestData("/frame_tree/page_with_masked_iframe.html");
+ float device_scale_factor = current_device_scale_factor();
+ gfx::Transform expected_transform;
+ gfx::Rect expected_region = gfx::ScaleToEnclosingRect(
+ gfx::Rect(200, 200), device_scale_factor, device_scale_factor);
+
+ // Since iframe clipped by clip-path and has a mask layer, we expect to do
+ // slow path hit testing.
+ DCHECK(hit_test_data.size() >= 3);
+ EXPECT_EQ(expected_region.ToString(), hit_test_data[2].rect.ToString());
+ EXPECT_TRUE(
+ expected_transform.ApproximatelyEqual(hit_test_data[2].transform()));
+ EXPECT_EQ(kSlowHitTestFlags, hit_test_data[2].flags);
+}
+
static const int kHitTestOption[] = {0, 1, 2};
static const float kOneScale[] = {1.f};
@@ -4583,6 +5374,11 @@ INSTANTIATE_TEST_CASE_P(/* no prefix */,
SitePerProcessEmulatedTouchBrowserTest,
testing::Combine(testing::ValuesIn(kHitTestOption),
testing::ValuesIn(kOneScale)));
+
+INSTANTIATE_TEST_CASE_P(/* no prefix */,
+ SitePerProcessHitTestDataGenerationBrowserTest,
+ testing::Combine(testing::ValuesIn(kHitTestOption),
+ testing::ValuesIn(kOneScale)));
#if defined(USE_AURA)
static const float kMultiScale[] = {1.f, 1.5f, 2.f};
diff --git a/chromium/content/browser/speech/speech_recognition_dispatcher_host.cc b/chromium/content/browser/speech/speech_recognition_dispatcher_host.cc
index 4e8664ea9da..1658119876a 100644
--- a/chromium/content/browser/speech/speech_recognition_dispatcher_host.cc
+++ b/chromium/content/browser/speech/speech_recognition_dispatcher_host.cc
@@ -16,11 +16,13 @@
#include "content/browser/speech/speech_recognition_manager_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_context.h"
+#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/speech_recognition_manager_delegate.h"
#include "content/public/browser/speech_recognition_session_config.h"
#include "content/public/browser/speech_recognition_session_context.h"
#include "content/public/browser/storage_partition.h"
+#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -131,8 +133,9 @@ void SpeechRecognitionDispatcherHost::StartRequestOnUI(
->delegate()
->FilterProfanities(embedder_render_process_id);
+ content::BrowserContext* browser_context = web_contents->GetBrowserContext();
StoragePartition* storage_partition = BrowserContext::GetStoragePartition(
- web_contents->GetBrowserContext(), web_contents->GetSiteInstance());
+ browser_context, web_contents->GetSiteInstance());
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
@@ -142,7 +145,7 @@ void SpeechRecognitionDispatcherHost::StartRequestOnUI(
embedder_render_process_id, embedder_render_frame_id,
filter_profanities,
storage_partition->GetURLLoaderFactoryForBrowserProcessIOThread(),
- base::WrapRefCounted(storage_partition->GetURLRequestContext())));
+ GetContentClient()->browser()->GetAcceptLangs(browser_context)));
}
void SpeechRecognitionDispatcherHost::StartSessionOnIO(
@@ -152,7 +155,7 @@ void SpeechRecognitionDispatcherHost::StartSessionOnIO(
bool filter_profanities,
std::unique_ptr<network::SharedURLLoaderFactoryInfo>
shared_url_loader_factory_info,
- scoped_refptr<net::URLRequestContextGetter> deprecated_context_getter) {
+ const std::string& accept_language) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
SpeechRecognitionSessionContext context;
@@ -167,13 +170,12 @@ void SpeechRecognitionDispatcherHost::StartSessionOnIO(
SpeechRecognitionSessionConfig config;
config.language = params->language;
+ config.accept_language = accept_language;
config.max_hypotheses = params->max_hypotheses;
config.origin = params->origin;
config.initial_context = context;
config.shared_url_loader_factory = network::SharedURLLoaderFactory::Create(
std::move(shared_url_loader_factory_info));
- config.deprecated_url_request_context_getter =
- std::move(deprecated_context_getter);
config.filter_profanities = filter_profanities;
config.continuous = params->continuous;
config.interim_results = params->interim_results;
@@ -201,7 +203,11 @@ SpeechRecognitionSession::SpeechRecognitionSession(
: session_id_(SpeechRecognitionManager::kSessionIDInvalid),
client_(std::move(client_ptr_info)),
stopped_(false),
- weak_factory_(this) {}
+ weak_factory_(this) {
+ client_.set_connection_error_handler(
+ base::BindOnce(&SpeechRecognitionSession::ConnectionErrorHandler,
+ base::Unretained(this)));
+}
SpeechRecognitionSession::~SpeechRecognitionSession() {
// If a connection error happens and the session hasn't been stopped yet,
@@ -273,4 +279,9 @@ void SpeechRecognitionSession::OnAudioLevelsChange(int session_id,
void SpeechRecognitionSession::OnEnvironmentEstimationComplete(int session_id) {
}
+void SpeechRecognitionSession::ConnectionErrorHandler() {
+ if (!stopped_)
+ Abort();
+}
+
} // namespace content
diff --git a/chromium/content/browser/speech/speech_recognition_dispatcher_host.h b/chromium/content/browser/speech/speech_recognition_dispatcher_host.h
index ffa9bd51448..2ae15969b20 100644
--- a/chromium/content/browser/speech/speech_recognition_dispatcher_host.h
+++ b/chromium/content/browser/speech/speech_recognition_dispatcher_host.h
@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_SPEECH_SPEECH_RECOGNITION_DISPATCHER_HOST_H_
#include <memory>
+#include <string>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
@@ -14,7 +15,6 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/speech_recognition_event_listener.h"
#include "mojo/public/cpp/bindings/binding.h"
-#include "net/url_request/url_request_context_getter.h"
#include "third_party/blink/public/mojom/speech/speech_recognizer.mojom.h"
namespace network {
@@ -57,7 +57,7 @@ class CONTENT_EXPORT SpeechRecognitionDispatcherHost
bool filter_profanities,
std::unique_ptr<network::SharedURLLoaderFactoryInfo>
shared_url_loader_factory_info,
- scoped_refptr<net::URLRequestContextGetter> deprecated_context_getter);
+ const std::string& accept_language);
const int render_process_id_;
const int render_frame_id_;
@@ -109,6 +109,8 @@ class SpeechRecognitionSession : public blink::mojom::SpeechRecognitionSession,
float noise_volume) override;
private:
+ void ConnectionErrorHandler();
+
int session_id_;
blink::mojom::SpeechRecognitionSessionClientPtr client_;
bool stopped_;
diff --git a/chromium/content/browser/speech/speech_recognition_engine.cc b/chromium/content/browser/speech/speech_recognition_engine.cc
index 275129d367e..3bb628ae218 100644
--- a/chromium/content/browser/speech/speech_recognition_engine.cc
+++ b/chromium/content/browser/speech/speech_recognition_engine.cc
@@ -22,11 +22,6 @@
#include "net/base/escape.h"
#include "net/base/load_flags.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/http_user_agent_settings.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "net/url_request/url_request_status.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "services/network/public/mojom/chunked_data_pipe_getter.mojom.h"
@@ -293,11 +288,9 @@ const int SpeechRecognitionEngine::kWebserviceStatusErrorNoMatch = 5;
SpeechRecognitionEngine::SpeechRecognitionEngine(
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
- scoped_refptr<net::URLRequestContextGetter>
- deprecated_url_request_context_getter)
+ const std::string& accept_language)
: shared_url_loader_factory_(std::move(shared_url_loader_factory)),
- deprecated_url_request_context_getter_(
- std::move(deprecated_url_request_context_getter)),
+ accept_language_(accept_language),
got_last_definitive_result_(false),
is_dispatching_event_(false),
use_framed_post_data_(false),
@@ -872,23 +865,13 @@ SpeechRecognitionEngine::NotFeasible(const FSMEventArgs& event_args) {
std::string SpeechRecognitionEngine::GetAcceptedLanguages() const {
std::string langs = config_.language;
- if (langs.empty() && deprecated_url_request_context_getter_.get()) {
+ if (langs.empty() && !accept_language_.empty()) {
// If no language is provided then we use the first from the accepted
// language list. If this list is empty then it defaults to "en-US".
// Example of the contents of this list: "es,en-GB;q=0.8", ""
- net::URLRequestContext* request_context =
- deprecated_url_request_context_getter_->GetURLRequestContext();
- DCHECK(request_context);
- // TODO(pauljensen): SpeechRecognitionEngine should be constructed with
- // a reference to the HttpUserAgentSettings rather than accessing the
- // accept language through the URLRequestContext.
- if (request_context->http_user_agent_settings()) {
- std::string accepted_language_list =
- request_context->http_user_agent_settings()->GetAcceptLanguage();
- size_t separator = accepted_language_list.find_first_of(",;");
- if (separator != std::string::npos)
- langs = accepted_language_list.substr(0, separator);
- }
+ size_t separator = accept_language_.find_first_of(",;");
+ if (separator != std::string::npos)
+ langs = accept_language_.substr(0, separator);
}
if (langs.empty())
langs = "en-US";
diff --git a/chromium/content/browser/speech/speech_recognition_engine.h b/chromium/content/browser/speech/speech_recognition_engine.h
index 5119585cdd2..1f3501200e5 100644
--- a/chromium/content/browser/speech/speech_recognition_engine.h
+++ b/chromium/content/browser/speech/speech_recognition_engine.h
@@ -24,10 +24,6 @@
#include "third_party/blink/public/mojom/speech/speech_recognition_grammar.mojom.h"
#include "third_party/blink/public/mojom/speech/speech_recognition_result.mojom.h"
-namespace net {
-class URLRequestContextGetter;
-}
-
namespace network {
class SharedURLLoaderFactory;
}
@@ -104,14 +100,10 @@ class CONTENT_EXPORT SpeechRecognitionEngine {
// Duration of each audio packet.
static const int kAudioPacketIntervalMs;
- // |deprecated_url_request_context_getter| is only for poking at the
- // Accept-Language header.
- // TODO(mmenke): Remove |deprecated_url_request_context_getter| as an
- // argument.
+ // |accept_language| is the default Accept-Language header.
SpeechRecognitionEngine(
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
- scoped_refptr<net::URLRequestContextGetter>
- deprecated_url_request_context_getter);
+ const std::string& accept_language);
~SpeechRecognitionEngine();
// Sets the URL requests are sent to for tests.
@@ -215,8 +207,7 @@ class CONTENT_EXPORT SpeechRecognitionEngine {
std::unique_ptr<UpstreamLoader> upstream_loader_;
std::unique_ptr<DownstreamLoader> downstream_loader_;
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
- scoped_refptr<net::URLRequestContextGetter>
- deprecated_url_request_context_getter_;
+ const std::string accept_language_;
std::unique_ptr<AudioEncoder> encoder_;
std::unique_ptr<AudioEncoder> preamble_encoder_;
ChunkedByteBuffer chunked_byte_buffer_;
diff --git a/chromium/content/browser/speech/speech_recognition_engine_unittest.cc b/chromium/content/browser/speech/speech_recognition_engine_unittest.cc
index e5cc0943b11..e67d2517559 100644
--- a/chromium/content/browser/speech/speech_recognition_engine_unittest.cc
+++ b/chromium/content/browser/speech/speech_recognition_engine_unittest.cc
@@ -489,7 +489,7 @@ void SpeechRecognitionEngineTest::SetUp() {
engine_under_test_.reset(new SpeechRecognitionEngine(
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&url_loader_factory_),
- nullptr /*URLRequestContextGetter*/));
+ "" /* accept_language */));
engine_under_test_->set_delegate(this);
}
diff --git a/chromium/content/browser/speech/speech_recognition_manager_impl.cc b/chromium/content/browser/speech/speech_recognition_manager_impl.cc
index 0fe2c51770a..08bcec68559 100644
--- a/chromium/content/browser/speech/speech_recognition_manager_impl.cc
+++ b/chromium/content/browser/speech/speech_recognition_manager_impl.cc
@@ -282,9 +282,8 @@ int SpeechRecognitionManagerImpl::CreateSession(
remote_engine_config.auth_scope = config.auth_scope;
remote_engine_config.preamble = config.preamble;
- SpeechRecognitionEngine* google_remote_engine =
- new SpeechRecognitionEngine(config.shared_url_loader_factory,
- config.deprecated_url_request_context_getter);
+ SpeechRecognitionEngine* google_remote_engine = new SpeechRecognitionEngine(
+ config.shared_url_loader_factory, config.accept_language);
google_remote_engine->SetConfig(remote_engine_config);
session->recognizer = new SpeechRecognizerImpl(
diff --git a/chromium/content/browser/speech/speech_recognizer_impl.h b/chromium/content/browser/speech/speech_recognizer_impl.h
index fd6d57b8b8f..5636b18cbf5 100644
--- a/chromium/content/browser/speech/speech_recognizer_impl.h
+++ b/chromium/content/browser/speech/speech_recognizer_impl.h
@@ -15,7 +15,6 @@
#include "content/browser/speech/speech_recognition_engine.h"
#include "content/browser/speech/speech_recognizer.h"
#include "media/base/audio_capturer_source.h"
-#include "net/url_request/url_request_context_getter.h"
#include "third_party/blink/public/mojom/speech/speech_recognition_error.mojom.h"
#include "third_party/blink/public/mojom/speech/speech_recognition_result.mojom.h"
diff --git a/chromium/content/browser/speech/speech_recognizer_impl_unittest.cc b/chromium/content/browser/speech/speech_recognizer_impl_unittest.cc
index 0ef14a5d5ea..8c4fa526886 100644
--- a/chromium/content/browser/speech/speech_recognizer_impl_unittest.cc
+++ b/chromium/content/browser/speech/speech_recognizer_impl_unittest.cc
@@ -85,7 +85,7 @@ class SpeechRecognizerImplTest : public SpeechRecognitionEventListener,
SpeechRecognitionEngine* sr_engine = new SpeechRecognitionEngine(
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&url_loader_factory_),
- nullptr /* URLRequestContextGetter */);
+ "" /* accept_language */);
SpeechRecognitionEngine::Config config;
config.audio_num_bits_per_sample =
SpeechRecognizerImpl::kNumBitsPerAudioSample;
diff --git a/chromium/content/browser/storage_partition_impl.cc b/chromium/content/browser/storage_partition_impl.cc
index ab6a04d6ec9..ee48d130400 100644
--- a/chromium/content/browser/storage_partition_impl.cc
+++ b/chromium/content/browser/storage_partition_impl.cc
@@ -25,6 +25,7 @@
#include "content/browser/browser_main_loop.h"
#include "content/browser/browsing_data/storage_partition_http_cache_data_remover.h"
#include "content/browser/child_process_security_policy_impl.h"
+#include "content/browser/code_cache/generated_code_cache_context.h"
#include "content/browser/cookie_store/cookie_store_context.h"
#include "content/browser/fileapi/browser_file_system_helper.h"
#include "content/browser/gpu/shader_cache_factory.h"
@@ -40,6 +41,7 @@
#include "content/public/browser/indexed_db_context.h"
#include "content/public/browser/local_storage_usage_info.h"
#include "content/public/browser/network_service_instance.h"
+#include "content/public/browser/permission_controller.h"
#include "content/public/browser/session_storage_usage_info.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_features.h"
@@ -493,6 +495,7 @@ StoragePartitionImpl::StoragePartitionImpl(
storage::SpecialStoragePolicy* special_storage_policy)
: partition_path_(partition_path),
special_storage_policy_(special_storage_policy),
+ network_context_client_binding_(this),
browser_context_(browser_context),
deletion_helpers_running_(0),
weak_factory_(this) {}
@@ -551,7 +554,8 @@ StoragePartitionImpl::~StoragePartitionImpl() {
std::unique_ptr<StoragePartitionImpl> StoragePartitionImpl::Create(
BrowserContext* context,
bool in_memory,
- const base::FilePath& relative_partition_path) {
+ const base::FilePath& relative_partition_path,
+ const std::string& partition_domain) {
// Ensure that these methods are called on the UI thread, except for
// unittests where a UI thread might not have been created.
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
@@ -606,11 +610,12 @@ std::unique_ptr<StoragePartitionImpl> StoragePartitionImpl::Create(
partition->service_worker_context_ = new ServiceWorkerContextWrapper(context);
partition->service_worker_context_->set_storage_partition(partition.get());
- partition->shared_worker_service_ = std::make_unique<SharedWorkerServiceImpl>(
- partition.get(), partition->service_worker_context_);
-
partition->appcache_service_ =
- new ChromeAppCacheService(quota_manager_proxy.get());
+ base::MakeRefCounted<ChromeAppCacheService>(quota_manager_proxy.get());
+
+ partition->shared_worker_service_ = std::make_unique<SharedWorkerServiceImpl>(
+ partition.get(), partition->service_worker_context_,
+ partition->appcache_service_);
partition->push_messaging_context_ =
new PushMessagingContext(context, partition->service_worker_context_);
@@ -630,7 +635,7 @@ std::unique_ptr<StoragePartitionImpl> StoragePartitionImpl::Create(
partition->background_fetch_context_ =
base::MakeRefCounted<BackgroundFetchContext>(
context, partition->service_worker_context_,
- partition->cache_storage_context_);
+ partition->cache_storage_context_, quota_manager_proxy);
partition->background_sync_context_ =
base::MakeRefCounted<BackgroundSyncContext>();
@@ -670,6 +675,36 @@ std::unique_ptr<StoragePartitionImpl> StoragePartitionImpl::Create(
partition->cookie_store_context_->Initialize(
partition->service_worker_context_, base::DoNothing());
+ if (base::FeatureList::IsEnabled(features::kIsolatedCodeCache)) {
+ // TODO(crbug.com/867552): Currently we misuse GetCachePath to check if
+ // code caching is enabled. Fix this by having a better API.
+
+ // For Incognito mode, we should not persist anything on the disk so
+ // we do not create a code cache. Caching the generated code in memory
+ // is not useful, since V8 already maintains one copy in memory.
+ if (!in_memory && !context->GetCachePath().empty()) {
+ partition->generated_code_cache_context_ =
+ base::MakeRefCounted<GeneratedCodeCacheContext>();
+
+ base::FilePath code_cache_path;
+ if (partition_domain.empty()) {
+ code_cache_path = context->GetCachePath().AppendASCII("Code Cache");
+ } else {
+ // For site isolated partitions use the config directory.
+ code_cache_path = context->GetPath()
+ .Append(relative_partition_path)
+ .AppendASCII("Code Cache");
+ }
+
+ // TODO(crbug.com/867552): Currently we set it to 0 and let the disk_cache
+ // backend selects the size based on some heuristics. Add support to let
+ // the embedder override the default value.
+ constexpr int kSizeInBytes = 0;
+ partition->GetGeneratedCodeCacheContext()->Initialize(code_cache_path,
+ kSizeInBytes);
+ }
+ }
+
return partition;
}
@@ -687,23 +722,8 @@ StoragePartitionImpl::GetMediaURLRequestContext() {
}
network::mojom::NetworkContext* StoragePartitionImpl::GetNetworkContext() {
- if (!network_context_.is_bound() || network_context_.encountered_error()) {
- network_context_ = GetContentClient()->browser()->CreateNetworkContext(
- browser_context_, is_in_memory_, relative_partition_path_);
- if (!network_context_) {
- // TODO(mmenke): Remove once https://crbug.com/827928 is fixed.
- CHECK(url_request_context_);
-
- DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
- DCHECK(!network_context_owner_);
- network_context_owner_ = std::make_unique<NetworkContextOwner>();
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(&NetworkContextOwner::Initialize,
- base::Unretained(network_context_owner_.get()),
- MakeRequest(&network_context_), url_request_context_));
- }
- }
+ if (!network_context_.is_bound())
+ InitNetworkContext();
return network_context_.get();
}
@@ -830,6 +850,11 @@ CookieStoreContext* StoragePartitionImpl::GetCookieStoreContext() {
return cookie_store_context_.get();
}
+GeneratedCodeCacheContext*
+StoragePartitionImpl::GetGeneratedCodeCacheContext() {
+ return generated_code_cache_context_.get();
+}
+
void StoragePartitionImpl::OpenLocalStorage(
const url::Origin& origin,
blink::mojom::StorageAreaRequest request) {
@@ -848,9 +873,30 @@ void StoragePartitionImpl::OpenSessionStorage(
blink::mojom::SessionStorageNamespaceRequest request) {
int process_id = bindings_.dispatch_context();
dom_storage_context_->OpenSessionStorage(process_id, namespace_id,
+ bindings_.GetBadMessageCallback(),
std::move(request));
}
+void StoragePartitionImpl::OnCanSendReportingReports(
+ const std::vector<url::Origin>& origins,
+ OnCanSendReportingReportsCallback callback) {
+ PermissionController* permission_controller =
+ BrowserContext::GetPermissionController(browser_context_);
+ DCHECK(permission_controller);
+
+ std::vector<url::Origin> origins_out;
+ for (auto& origin : origins) {
+ GURL origin_url = origin.GetURL();
+ bool allowed = permission_controller->GetPermissionStatus(
+ PermissionType::BACKGROUND_SYNC, origin_url,
+ origin_url) == blink::mojom::PermissionStatus::GRANTED;
+ if (allowed)
+ origins_out.push_back(origin);
+ }
+
+ std::move(callback).Run(origins_out);
+}
+
void StoragePartitionImpl::ClearDataImpl(
uint32_t remove_mask,
uint32_t quota_storage_remove_mask,
@@ -1178,6 +1224,12 @@ void StoragePartitionImpl::Flush() {
GetDOMStorageContext()->Flush();
}
+void StoragePartitionImpl::ResetURLLoaderFactories() {
+ GetNetworkContext()->ResetURLLoaderFactories();
+ url_loader_factory_for_browser_process_.reset();
+ url_loader_factory_getter_->Initialize(this);
+}
+
void StoragePartitionImpl::ClearBluetoothAllowedDevicesMapForTesting() {
bluetooth_allowed_devices_map_->Clear();
}
@@ -1187,6 +1239,8 @@ void StoragePartitionImpl::FlushNetworkInterfaceForTesting() {
network_context_.FlushForTesting();
if (url_loader_factory_for_browser_process_)
url_loader_factory_for_browser_process_.FlushForTesting();
+ if (cookie_manager_for_browser_process_)
+ cookie_manager_for_browser_process_.FlushForTesting();
}
void StoragePartitionImpl::WaitForDeletionTasksForTesting() {
@@ -1197,10 +1251,6 @@ void StoragePartitionImpl::WaitForDeletionTasksForTesting() {
}
}
-void StoragePartitionImpl::ResetURLLoaderFactoryForBrowserProcessForTesting() {
- url_loader_factory_for_browser_process_.reset();
-}
-
BrowserContext* StoragePartitionImpl::browser_context() const {
return browser_context_;
}
@@ -1237,6 +1287,30 @@ void StoragePartitionImpl::GetQuotaSettings(
std::move(callback));
}
+void StoragePartitionImpl::InitNetworkContext() {
+ network_context_ = GetContentClient()->browser()->CreateNetworkContext(
+ browser_context_, is_in_memory_, relative_partition_path_);
+ if (!network_context_) {
+ // TODO(mmenke): Remove once https://crbug.com/827928 is fixed.
+ CHECK(url_request_context_);
+
+ DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
+ DCHECK(!network_context_owner_);
+ network_context_owner_ = std::make_unique<NetworkContextOwner>();
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&NetworkContextOwner::Initialize,
+ base::Unretained(network_context_owner_.get()),
+ MakeRequest(&network_context_), url_request_context_));
+ }
+ network::mojom::NetworkContextClientPtr client_ptr;
+ network_context_client_binding_.Close();
+ network_context_client_binding_.Bind(mojo::MakeRequest(&client_ptr));
+ network_context_->SetClient(std::move(client_ptr));
+ network_context_.set_connection_error_handler(base::BindOnce(
+ &StoragePartitionImpl::InitNetworkContext, weak_factory_.GetWeakPtr()));
+}
+
network::mojom::URLLoaderFactory*
StoragePartitionImpl::GetURLLoaderFactoryForBrowserProcessInternal() {
// Create the URLLoaderFactory as needed, but make sure not to reuse a
@@ -1257,8 +1331,12 @@ StoragePartitionImpl::GetURLLoaderFactoryForBrowserProcessInternal() {
switches::kDisableWebSecurity);
if (g_url_loader_factory_callback_for_test.Get().is_null()) {
auto request = mojo::MakeRequest(&url_loader_factory_for_browser_process_);
- GetContentClient()->browser()->WillCreateURLLoaderFactory(
- browser_context(), nullptr, false /* is_navigation */, &request);
+
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ GetContentClient()->browser()->WillCreateURLLoaderFactory(
+ browser_context(), nullptr, false /* is_navigation */, GURL(),
+ &request);
+ }
GetNetworkContext()->CreateURLLoaderFactory(std::move(request),
std::move(params));
is_test_url_loader_factory_for_browser_process_ = false;
diff --git a/chromium/content/browser/storage_partition_impl.h b/chromium/content/browser/storage_partition_impl.h
index e79f8775a1b..78110a30b23 100644
--- a/chromium/content/browser/storage_partition_impl.h
+++ b/chromium/content/browser/storage_partition_impl.h
@@ -34,6 +34,7 @@
#include "content/public/browser/storage_partition.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/network/public/mojom/cookie_manager.mojom.h"
+#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/network_service.mojom.h"
#include "storage/browser/quota/special_storage_policy.h"
#include "third_party/blink/public/mojom/dom_storage/storage_partition_service.mojom.h"
@@ -49,10 +50,12 @@ class CookieStoreContext;
class BlobRegistryWrapper;
class PrefetchURLLoaderService;
class WebPackageContextImpl;
+class GeneratedCodeCacheContext;
class CONTENT_EXPORT StoragePartitionImpl
: public StoragePartition,
- public blink::mojom::StoragePartitionService {
+ public blink::mojom::StoragePartitionService,
+ public network::mojom::NetworkContextClient {
public:
// It is guaranteed that storage partitions are destructed before the
// browser context starts shutting down its corresponding IO thread residents
@@ -99,6 +102,7 @@ class CONTENT_EXPORT StoragePartitionImpl
CacheStorageContextImpl* GetCacheStorageContext() override;
ServiceWorkerContextWrapper* GetServiceWorkerContext() override;
SharedWorkerServiceImpl* GetSharedWorkerService() override;
+ GeneratedCodeCacheContext* GetGeneratedCodeCacheContext() override;
#if !defined(OS_ANDROID)
HostZoomMap* GetHostZoomMap() override;
HostZoomLevelContext* GetHostZoomLevelContext() override;
@@ -129,10 +133,10 @@ class CONTENT_EXPORT StoragePartitionImpl
const base::Callback<bool(const GURL&)>& url_matcher,
base::OnceClosure callback) override;
void Flush() override;
+ void ResetURLLoaderFactories() override;
void ClearBluetoothAllowedDevicesMapForTesting() override;
void FlushNetworkInterfaceForTesting() override;
void WaitForDeletionTasksForTesting() override;
- void ResetURLLoaderFactoryForBrowserProcessForTesting() override;
BackgroundFetchContext* GetBackgroundFetchContext();
BackgroundSyncContext* GetBackgroundSyncContext();
@@ -150,6 +154,11 @@ class CONTENT_EXPORT StoragePartitionImpl
const std::string& namespace_id,
blink::mojom::SessionStorageNamespaceRequest request) override;
+ // network::mojom::NetworkContextClient interface.
+ void OnCanSendReportingReports(
+ const std::vector<url::Origin>& origins,
+ OnCanSendReportingReportsCallback callback) override;
+
scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter() {
return url_loader_factory_getter_;
}
@@ -234,7 +243,8 @@ class CONTENT_EXPORT StoragePartitionImpl
static std::unique_ptr<StoragePartitionImpl> Create(
BrowserContext* context,
bool in_memory,
- const base::FilePath& relative_partition_path);
+ const base::FilePath& relative_partition_path,
+ const std::string& partition_domain);
StoragePartitionImpl(BrowserContext* browser_context,
const base::FilePath& partition_path,
@@ -274,6 +284,10 @@ class CONTENT_EXPORT StoragePartitionImpl
// storage configuration info.
void GetQuotaSettings(storage::OptionalQuotaSettingsCallback callback);
+ // Called to initialize |network_context_| when |GetNetworkContext()| is
+ // first called or there is an error.
+ void InitNetworkContext();
+
network::mojom::URLLoaderFactory*
GetURLLoaderFactoryForBrowserProcessInternal();
@@ -310,6 +324,7 @@ class CONTENT_EXPORT StoragePartitionImpl
scoped_refptr<BlobRegistryWrapper> blob_registry_;
scoped_refptr<PrefetchURLLoaderService> prefetch_url_loader_service_;
scoped_refptr<CookieStoreContext> cookie_store_context_;
+ scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context_;
// BindingSet for StoragePartitionService, using the process id as the
// binding context type. The process id can subsequently be used during
@@ -324,6 +339,9 @@ class CONTENT_EXPORT StoragePartitionImpl
// by |network_context_owner_|.
network::mojom::NetworkContextPtr network_context_;
+ mojo::Binding<network::mojom::NetworkContextClient>
+ network_context_client_binding_;
+
scoped_refptr<URLLoaderFactoryForBrowserProcess>
shared_url_loader_factory_for_browser_process_;
diff --git a/chromium/content/browser/storage_partition_impl_map.cc b/chromium/content/browser/storage_partition_impl_map.cc
index 9f56c4c29c5..c93fd1e67ba 100644
--- a/chromium/content/browser/storage_partition_impl_map.cc
+++ b/chromium/content/browser/storage_partition_impl_map.cc
@@ -18,13 +18,14 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "content/browser/appcache/appcache_interceptor.h"
#include "content/browser/appcache/chrome_appcache_service.h"
#include "content/browser/background_fetch/background_fetch_context.h"
#include "content/browser/blob_storage/chrome_blob_storage_context.h"
+#include "content/browser/code_cache/generated_code_cache_context.h"
#include "content/browser/cookie_store/cookie_store_context.h"
#include "content/browser/devtools/devtools_url_request_interceptor.h"
#include "content/browser/fileapi/browser_file_system_helper.h"
@@ -44,6 +45,7 @@
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_constants.h"
+#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "crypto/sha2.h"
@@ -369,7 +371,7 @@ StoragePartitionImplMap::StoragePartitionImplMap(
BrowserContext* browser_context)
: browser_context_(browser_context),
file_access_runner_(base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::BACKGROUND})),
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT})),
resource_context_initialized_(false) {}
StoragePartitionImplMap::~StoragePartitionImplMap() {
@@ -396,7 +398,7 @@ StoragePartitionImpl* StoragePartitionImplMap::Get(
std::unique_ptr<StoragePartitionImpl> partition_ptr(
StoragePartitionImpl::Create(browser_context_, in_memory,
- relative_partition_path));
+ relative_partition_path, partition_domain));
StoragePartitionImpl* partition = partition_ptr.get();
partitions_[partition_config] = std::move(partition_ptr);
@@ -500,7 +502,7 @@ void StoragePartitionImplMap::AsyncObliterate(
GetStoragePartitionDomainPath(partition_domain));
base::PostTaskWithTraits(
- FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
base::BindOnce(&BlockingObliteratePath, browser_context_->GetPath(),
domain_root, paths_to_keep,
base::ThreadTaskRunnerHandle::Get(), on_gc_required));
diff --git a/chromium/content/browser/storage_partition_impl_unittest.cc b/chromium/content/browser/storage_partition_impl_unittest.cc
index b151ad3c097..d58a94c0a62 100644
--- a/chromium/content/browser/storage_partition_impl_unittest.cc
+++ b/chromium/content/browser/storage_partition_impl_unittest.cc
@@ -13,11 +13,14 @@
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/services/leveldb/public/cpp/util.h"
+#include "content/browser/code_cache/generated_code_cache.h"
+#include "content/browser/code_cache/generated_code_cache_context.h"
#include "content/browser/dom_storage/local_storage_database.pb.h"
#include "content/browser/gpu/shader_cache_factory.h"
#include "content/browser/storage_partition_impl.h"
#include "content/public/browser/local_storage_usage_info.h"
#include "content/public/browser/storage_partition.h"
+#include "content/public/common/content_features.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread.h"
#include "content/public/test/test_browser_thread_bundle.h"
@@ -58,6 +61,7 @@ const char kTestOrigin1[] = "http://host1:1/";
const char kTestOrigin2[] = "http://host2:1/";
const char kTestOrigin3[] = "http://host3:1/";
const char kTestOriginDevTools[] = "chrome-devtools://abcdefghijklmnopqrstuvw/";
+const char kTestURL[] = "http://host4/script.js";
#if BUILDFLAG(ENABLE_PLUGINS)
const char kWidevineCdmPluginId[] = "application_x-ppapi-widevine-cdm";
@@ -68,6 +72,7 @@ const GURL kOrigin1(kTestOrigin1);
const GURL kOrigin2(kTestOrigin2);
const GURL kOrigin3(kTestOrigin3);
const GURL kOriginDevTools(kTestOriginDevTools);
+const GURL kResourceURL(kTestURL);
const blink::mojom::StorageType kTemporary =
blink::mojom::StorageType::kTemporary;
@@ -272,6 +277,49 @@ class RemoveLocalStorageTester {
DISALLOW_COPY_AND_ASSIGN(RemoveLocalStorageTester);
};
+class RemoveCodeCacheTester {
+ public:
+ explicit RemoveCodeCacheTester(GeneratedCodeCacheContext* code_cache_context)
+ : code_cache_context_(code_cache_context) {}
+
+ bool ContainsEntry(GURL url, url::Origin origin) {
+ entry_exists_ = false;
+ GeneratedCodeCache::ReadDataCallback callback = base::BindRepeating(
+ &RemoveCodeCacheTester::FetchEntryCallback, base::Unretained(this));
+ code_cache_context_->generated_code_cache()->FetchEntry(url, origin,
+ callback);
+ await_completion_.BlockUntilNotified();
+ return entry_exists_;
+ }
+
+ void AddEntry(GURL url, url::Origin origin, const std::string& data) {
+ std::vector<uint8_t> data_vector(data.begin(), data.end());
+ code_cache_context_->generated_code_cache()->WriteData(
+ url, origin, base::Time::Now(), data_vector);
+ base::RunLoop().RunUntilIdle();
+ }
+
+ std::string received_data() { return received_data_; }
+
+ private:
+ void FetchEntryCallback(const base::Time& response_time,
+ const std::vector<uint8_t>& data) {
+ if (!response_time.is_null()) {
+ entry_exists_ = true;
+ received_data_ = std::string(data.begin(), data.end());
+ } else {
+ entry_exists_ = false;
+ }
+ await_completion_.Notify();
+ }
+
+ bool entry_exists_;
+ AwaitCompletionHelper await_completion_;
+ GeneratedCodeCacheContext* code_cache_context_;
+ std::string received_data_;
+ DISALLOW_COPY_AND_ASSIGN(RemoveCodeCacheTester);
+};
+
#if BUILDFLAG(ENABLE_PLUGINS)
class RemovePluginPrivateDataTester {
public:
@@ -605,6 +653,15 @@ void ClearData(content::StoragePartition* partition,
time, time, run_loop->QuitClosure());
}
+void ClearCodeCache(content::StoragePartition* partition,
+ base::RunLoop* run_loop) {
+ base::Time delete_begin;
+ base::Time delete_end;
+ partition->ClearHttpAndMediaCaches(
+ delete_begin, delete_end, base::RepeatingCallback<bool(const GURL&)>(),
+ run_loop->QuitClosure());
+}
+
#if BUILDFLAG(ENABLE_PLUGINS)
void ClearPluginPrivateData(content::StoragePartition* partition,
const GURL& storage_origin,
@@ -1255,6 +1312,32 @@ TEST_F(StoragePartitionImplTest, RemoveLocalStorageForLastWeek) {
EXPECT_TRUE(tester.DOMStorageExistsForOrigin(kOrigin3));
}
+TEST_F(StoragePartitionImplTest, ClearCodeCache) {
+ // Run this test only when the IsolatedCodeCache feature is enabled
+ if (!base::FeatureList::IsEnabled(features::kIsolatedCodeCache))
+ return;
+
+ StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
+ BrowserContext::GetDefaultStoragePartition(browser_context()));
+ // Ensure code cache is initialized.
+ base::RunLoop().RunUntilIdle();
+
+ RemoveCodeCacheTester tester(partition->GetGeneratedCodeCacheContext());
+
+ url::Origin origin = url::Origin::Create(kOrigin1);
+ std::string data("SomeData");
+ tester.AddEntry(kResourceURL, origin, data);
+ EXPECT_TRUE(tester.ContainsEntry(kResourceURL, origin));
+ EXPECT_EQ(tester.received_data(), data);
+
+ base::RunLoop run_loop;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&ClearCodeCache, partition, &run_loop));
+ run_loop.Run();
+
+ EXPECT_FALSE(tester.ContainsEntry(kResourceURL, origin));
+}
+
#if BUILDFLAG(ENABLE_PLUGINS)
TEST_F(StoragePartitionImplTest, RemovePluginPrivateDataForever) {
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
diff --git a/chromium/content/browser/tracing/DEPS b/chromium/content/browser/tracing/DEPS
index fddb5c8f0f1..1c6a0616ed7 100644
--- a/chromium/content/browser/tracing/DEPS
+++ b/chromium/content/browser/tracing/DEPS
@@ -1,7 +1,6 @@
include_rules = [
# Generated by the local tracing_resources.gyp:tracing_resources
"+grit/tracing_resources.h",
- "+tools/battor_agent",
]
specific_include_rules = {
diff --git a/chromium/content/browser/tracing/background_startup_tracing_observer.cc b/chromium/content/browser/tracing/background_startup_tracing_observer.cc
new file mode 100644
index 00000000000..307e5e5f44e
--- /dev/null
+++ b/chromium/content/browser/tracing/background_startup_tracing_observer.cc
@@ -0,0 +1,130 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/tracing/background_startup_tracing_observer.h"
+
+#include "components/tracing/common/trace_startup_config.h"
+#include "content/browser/tracing/background_tracing_rule.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+namespace {
+
+const char kStartupTracingConfig[] = "startup-config";
+
+class PreferenceManagerImpl
+ : public BackgroundStartupTracingObserver::PreferenceManager {
+ public:
+ void SetBackgroundStartupTracingEnabled(bool enabled) override {
+ tracing::TraceStartupConfig::GetInstance()
+ ->SetBackgroundStartupTracingEnabled(enabled);
+ }
+
+ bool GetBackgroundStartupTracingEnabled() const override {
+ return tracing::TraceStartupConfig::GetInstance()
+ ->GetBackgroundStartupTracingEnabled();
+ }
+};
+
+} // namespace
+
+// static
+BackgroundStartupTracingObserver*
+BackgroundStartupTracingObserver::GetInstance() {
+ static BackgroundStartupTracingObserver* instance =
+ new BackgroundStartupTracingObserver;
+ return instance;
+}
+
+// static
+const BackgroundTracingRule*
+BackgroundStartupTracingObserver::FindStartupRuleInConfig(
+ const BackgroundTracingConfigImpl& config) {
+ for (const auto& rule : config.rules()) {
+ if (rule->category_preset() ==
+ BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_STARTUP) {
+ return rule.get();
+ }
+ }
+ return nullptr;
+}
+
+BackgroundStartupTracingObserver::BackgroundStartupTracingObserver()
+ : enabled_in_current_session_(false),
+ preferences_(new PreferenceManagerImpl) {}
+
+BackgroundStartupTracingObserver::~BackgroundStartupTracingObserver() {}
+
+void BackgroundStartupTracingObserver::OnScenarioActivated(
+ const BackgroundTracingConfigImpl* config) {
+ if (!enabled_in_current_session_)
+ return;
+ const BackgroundTracingRule* startup_rule = FindStartupRuleInConfig(*config);
+ DCHECK(startup_rule);
+ // Post task to avoid reentrancy.
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::BindOnce(
+ &BackgroundTracingManagerImpl::OnRuleTriggered,
+ base::Unretained(BackgroundTracingManagerImpl::GetInstance()),
+ base::Unretained(startup_rule),
+ BackgroundTracingManager::StartedFinalizingCallback()));
+}
+
+void BackgroundStartupTracingObserver::OnScenarioAborted() {
+ enabled_in_current_session_ = false;
+}
+
+void BackgroundStartupTracingObserver::OnTracingEnabled(
+ BackgroundTracingConfigImpl::CategoryPreset preset) {}
+
+void BackgroundStartupTracingObserver::SetPreferenceManagerForTesting(
+ std::unique_ptr<PreferenceManager> preferences) {
+ preferences_ = std::move(preferences);
+}
+
+std::unique_ptr<BackgroundTracingConfigImpl>
+BackgroundStartupTracingObserver::IncludeStartupConfigIfNeeded(
+ std::unique_ptr<BackgroundTracingConfigImpl> config) {
+ enabled_in_current_session_ =
+ preferences_->GetBackgroundStartupTracingEnabled();
+
+ const BackgroundTracingRule* startup_rule = nullptr;
+ if (config)
+ startup_rule = FindStartupRuleInConfig(*config);
+ // Reset the flag if startup tracing was enabled again in current session.
+ if (startup_rule) {
+ preferences_->SetBackgroundStartupTracingEnabled(true);
+ } else {
+ preferences_->SetBackgroundStartupTracingEnabled(false);
+ }
+
+ // If enabled in current session and startup rule already exists, then do not
+ // add another rule.
+ if (!enabled_in_current_session_ || startup_rule)
+ return config;
+
+ std::unique_ptr<base::DictionaryValue> rules_dict(
+ new base::DictionaryValue());
+ rules_dict->SetString("rule", "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED");
+ rules_dict->SetString("trigger_name", kStartupTracingConfig);
+ rules_dict->SetInteger("trigger_delay", 30);
+ rules_dict->SetString("category", "BENCHMARK_STARTUP");
+
+ if (config) {
+ config->AddReactiveRule(
+ rules_dict.get(),
+ BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_STARTUP);
+ } else {
+ base::DictionaryValue dict;
+ std::unique_ptr<base::ListValue> rules_list(new base::ListValue());
+ rules_list->Append(std::move(rules_dict));
+ dict.Set("configs", std::move(rules_list));
+ config = BackgroundTracingConfigImpl::ReactiveFromDict(&dict);
+ }
+ DCHECK(FindStartupRuleInConfig(*config));
+ return config;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/tracing/background_startup_tracing_observer.h b/chromium/content/browser/tracing/background_startup_tracing_observer.h
new file mode 100644
index 00000000000..3acb9c602bb
--- /dev/null
+++ b/chromium/content/browser/tracing/background_startup_tracing_observer.h
@@ -0,0 +1,69 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_TRACING_BACKGROUND_STARTUP_TRACING_OBSERVER_H_
+#define CONTENT_BROWSER_TRACING_BACKGROUND_STARTUP_TRACING_OBSERVER_H_
+
+#include <memory>
+
+#include "content/browser/tracing/background_tracing_manager_impl.h"
+
+namespace content {
+
+// Observes for startup tracing config and sets up preferences to trace on next
+// startup.
+class CONTENT_EXPORT BackgroundStartupTracingObserver
+ : public BackgroundTracingManagerImpl::EnabledStateObserver {
+ public:
+ // Delegate to store and read application preferences for startup tracing, to
+ // isolate the feature for testing.
+ class PreferenceManager {
+ public:
+ virtual void SetBackgroundStartupTracingEnabled(bool enabled) = 0;
+ virtual bool GetBackgroundStartupTracingEnabled() const = 0;
+ virtual ~PreferenceManager() = default;
+ };
+
+ static BackgroundStartupTracingObserver* GetInstance();
+
+ // Returns startup tracing rule from the given config, null if doesn't exist.
+ static const BackgroundTracingRule* FindStartupRuleInConfig(
+ const BackgroundTracingConfigImpl& config);
+
+ // BackgroundTracingManagerImpl::EnabledStateObserver implementation.
+ void OnScenarioActivated(const BackgroundTracingConfigImpl* config) override;
+ void OnScenarioAborted() override;
+ void OnTracingEnabled(
+ BackgroundTracingConfigImpl::CategoryPreset preset) override;
+
+ // Reads the preference for startup tracing set on the previous startup and
+ // includes config for startup tracing if enabled. Also sets or resets the
+ // preference for next session based on current config containing startup
+ // rule. Returns the config after the changes.
+ std::unique_ptr<BackgroundTracingConfigImpl> IncludeStartupConfigIfNeeded(
+ std::unique_ptr<BackgroundTracingConfigImpl> config);
+
+ // Returns true if startup tracing was set on the previous session and is
+ // active now.
+ bool enabled_in_current_session() const {
+ return enabled_in_current_session_;
+ }
+
+ void SetPreferenceManagerForTesting(
+ std::unique_ptr<PreferenceManager> preferences);
+
+ private:
+ BackgroundStartupTracingObserver();
+ ~BackgroundStartupTracingObserver() override;
+
+ bool enabled_in_current_session_;
+
+ std::unique_ptr<PreferenceManager> preferences_;
+
+ DISALLOW_COPY_AND_ASSIGN(BackgroundStartupTracingObserver);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_TRACING_BACKGROUND_STARTUP_TRACING_OBSERVER_H_
diff --git a/chromium/content/browser/tracing/background_startup_tracing_observer_unittest.cc b/chromium/content/browser/tracing/background_startup_tracing_observer_unittest.cc
new file mode 100644
index 00000000000..b6ad697b018
--- /dev/null
+++ b/chromium/content/browser/tracing/background_startup_tracing_observer_unittest.cc
@@ -0,0 +1,135 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/tracing/background_startup_tracing_observer.h"
+
+#include "build/build_config.h"
+#include "content/browser/tracing/background_tracing_rule.h"
+#include "content/public/test/test_browser_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace {
+
+class TestPreferenceManagerImpl
+ : public BackgroundStartupTracingObserver::PreferenceManager {
+ public:
+ void SetBackgroundStartupTracingEnabled(bool enabled) override {
+ enabled_ = enabled;
+ }
+
+ bool GetBackgroundStartupTracingEnabled() const override { return enabled_; }
+
+ private:
+ bool enabled_ = false;
+};
+
+void TestStartupRuleExists(const BackgroundTracingConfigImpl& config,
+ bool exists) {
+ const auto* rule =
+ BackgroundStartupTracingObserver::FindStartupRuleInConfig(config);
+ if (exists) {
+ ASSERT_TRUE(rule);
+ EXPECT_EQ(BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_STARTUP,
+ rule->category_preset());
+ EXPECT_EQ(30, rule->GetTraceDelay());
+ EXPECT_FALSE(rule->stop_tracing_on_repeated_reactive());
+ } else {
+ EXPECT_FALSE(rule);
+ }
+}
+
+} // namespace
+
+TEST(BackgroundStartupTracingObserverTest, IncludeStartupConfigIfNeeded) {
+ BackgroundStartupTracingObserver* observer =
+ BackgroundStartupTracingObserver::GetInstance();
+ std::unique_ptr<TestPreferenceManagerImpl> test_preferences(
+ new TestPreferenceManagerImpl);
+ TestPreferenceManagerImpl* preferences = test_preferences.get();
+ observer->SetPreferenceManagerForTesting(std::move(test_preferences));
+
+ // Empty config without preference set should not do anything.
+ std::unique_ptr<content::BackgroundTracingConfigImpl> config_impl;
+ config_impl = observer->IncludeStartupConfigIfNeeded(std::move(config_impl));
+ EXPECT_FALSE(config_impl);
+ EXPECT_FALSE(observer->enabled_in_current_session());
+
+ // Empty config with preference set should create a startup config, and reset
+ // preference.
+ EXPECT_FALSE(preferences->GetBackgroundStartupTracingEnabled());
+ preferences->SetBackgroundStartupTracingEnabled(true);
+ config_impl = observer->IncludeStartupConfigIfNeeded(std::move(config_impl));
+ EXPECT_TRUE(observer->enabled_in_current_session());
+ EXPECT_FALSE(preferences->GetBackgroundStartupTracingEnabled());
+ ASSERT_TRUE(config_impl);
+ EXPECT_EQ(1u, config_impl->rules().size());
+ EXPECT_EQ(BackgroundTracingConfig::TracingMode::REACTIVE,
+ config_impl->tracing_mode());
+ TestStartupRuleExists(*config_impl, true);
+
+ // Startup config with preference set should keep config and preference same.
+ preferences->SetBackgroundStartupTracingEnabled(true);
+ config_impl = observer->IncludeStartupConfigIfNeeded(std::move(config_impl));
+ EXPECT_TRUE(observer->enabled_in_current_session());
+ EXPECT_TRUE(preferences->GetBackgroundStartupTracingEnabled());
+ ASSERT_TRUE(config_impl);
+ EXPECT_EQ(1u, config_impl->rules().size());
+ TestStartupRuleExists(*config_impl, true);
+
+ // Startup config without preference set should keep config and set
+ // preference.
+ preferences->SetBackgroundStartupTracingEnabled(false);
+ config_impl = observer->IncludeStartupConfigIfNeeded(std::move(config_impl));
+ EXPECT_FALSE(observer->enabled_in_current_session());
+ EXPECT_TRUE(preferences->GetBackgroundStartupTracingEnabled());
+ ASSERT_TRUE(config_impl);
+ EXPECT_EQ(1u, config_impl->rules().size());
+ TestStartupRuleExists(*config_impl, true);
+
+ // A GPU config without preference set should not set preference and keep
+ // config same.
+ std::unique_ptr<base::DictionaryValue> rules_dict(
+ new base::DictionaryValue());
+ rules_dict->SetString("rule", "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED");
+ rules_dict->SetString("trigger_name", "test");
+ rules_dict->SetString("category", "BENCHMARK_GPU");
+ base::DictionaryValue dict;
+ std::unique_ptr<base::ListValue> rules_list(new base::ListValue());
+ rules_list->Append(std::move(rules_dict));
+ dict.Set("configs", std::move(rules_list));
+ config_impl = BackgroundTracingConfigImpl::ReactiveFromDict(&dict);
+ ASSERT_TRUE(config_impl);
+
+ preferences->SetBackgroundStartupTracingEnabled(false);
+ config_impl = observer->IncludeStartupConfigIfNeeded(std::move(config_impl));
+ EXPECT_FALSE(observer->enabled_in_current_session());
+ EXPECT_FALSE(preferences->GetBackgroundStartupTracingEnabled());
+ EXPECT_EQ(1u, config_impl->rules().size());
+ TestStartupRuleExists(*config_impl, false);
+
+ // A GPU config with preference set should include startup config and disable
+ // preference.
+ preferences->SetBackgroundStartupTracingEnabled(true);
+ config_impl = observer->IncludeStartupConfigIfNeeded(std::move(config_impl));
+ EXPECT_TRUE(observer->enabled_in_current_session());
+ EXPECT_FALSE(preferences->GetBackgroundStartupTracingEnabled());
+ ASSERT_TRUE(config_impl);
+ EXPECT_EQ(2u, config_impl->rules().size());
+ EXPECT_EQ(BackgroundTracingConfig::TracingMode::REACTIVE,
+ config_impl->tracing_mode());
+ TestStartupRuleExists(*config_impl, true);
+
+ bool found_gpu = false;
+ for (const auto& rule : config_impl->rules()) {
+ if (rule->category_preset() ==
+ BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_GPU) {
+ found_gpu = true;
+ }
+ }
+ EXPECT_TRUE(found_gpu);
+ preferences->SetBackgroundStartupTracingEnabled(false);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/tracing/background_tracing_config_impl.cc b/chromium/content/browser/tracing/background_tracing_config_impl.cc
index b5d5c9afaa0..691e0c7d974 100644
--- a/chromium/content/browser/tracing/background_tracing_config_impl.cc
+++ b/chromium/content/browser/tracing/background_tracing_config_impl.cc
@@ -35,6 +35,7 @@ const char kConfigCategoryBenchmarkMemoryHeavy[] = "BENCHMARK_MEMORY_HEAVY";
const char kConfigCategoryBenchmarkMemoryLight[] = "BENCHMARK_MEMORY_LIGHT";
const char kConfigCategoryBenchmarkExecutionMetric[] =
"BENCHMARK_EXECUTION_METRIC";
+const char kConfigCategoryBenchmarkNavigation[] = "BENCHMARK_NAVIGATION";
const char kConfigCategoryBlinkStyle[] = "BLINK_STYLE";
} // namespace
@@ -67,6 +68,8 @@ std::string BackgroundTracingConfigImpl::CategoryPresetToString(
return kConfigCategoryBenchmarkMemoryLight;
case BackgroundTracingConfigImpl::BENCHMARK_EXECUTION_METRIC:
return kConfigCategoryBenchmarkExecutionMetric;
+ case BackgroundTracingConfigImpl::BENCHMARK_NAVIGATION:
+ return kConfigCategoryBenchmarkNavigation;
case BackgroundTracingConfigImpl::BLINK_STYLE:
return kConfigCategoryBlinkStyle;
case BackgroundTracingConfigImpl::CATEGORY_PRESET_UNSET:
@@ -124,6 +127,11 @@ bool BackgroundTracingConfigImpl::StringToCategoryPreset(
return true;
}
+ if (category_preset_string == kConfigCategoryBenchmarkNavigation) {
+ *category_preset = BackgroundTracingConfigImpl::BENCHMARK_NAVIGATION;
+ return true;
+ }
+
if (category_preset_string == kConfigCategoryBlinkStyle) {
*category_preset = BackgroundTracingConfigImpl::BLINK_STYLE;
return true;
@@ -279,4 +287,4 @@ BackgroundTracingConfigImpl::ReactiveFromDict(
return config;
}
-} // namspace content
+} // namespace content
diff --git a/chromium/content/browser/tracing/background_tracing_config_impl.h b/chromium/content/browser/tracing/background_tracing_config_impl.h
index 58ed5e87287..9d8915e1d4f 100644
--- a/chromium/content/browser/tracing/background_tracing_config_impl.h
+++ b/chromium/content/browser/tracing/background_tracing_config_impl.h
@@ -37,6 +37,7 @@ class CONTENT_EXPORT BackgroundTracingConfigImpl
BENCHMARK_MEMORY_HEAVY,
BENCHMARK_MEMORY_LIGHT,
BENCHMARK_EXECUTION_METRIC,
+ BENCHMARK_NAVIGATION,
BLINK_STYLE
};
diff --git a/chromium/content/browser/tracing/background_tracing_config_unittest.cc b/chromium/content/browser/tracing/background_tracing_config_unittest.cc
index 7124ddff9f0..12de19fa40d 100644
--- a/chromium/content/browser/tracing/background_tracing_config_unittest.cc
+++ b/chromium/content/browser/tracing/background_tracing_config_unittest.cc
@@ -287,6 +287,7 @@ TEST_F(BackgroundTracingConfigTest, ValidPreemptiveCategoryToString) {
BackgroundTracingConfigImpl::BENCHMARK_MEMORY_HEAVY,
BackgroundTracingConfigImpl::BENCHMARK_MEMORY_LIGHT,
BackgroundTracingConfigImpl::BENCHMARK_EXECUTION_METRIC,
+ BackgroundTracingConfigImpl::BENCHMARK_NAVIGATION,
BackgroundTracingConfigImpl::BLINK_STYLE,
};
@@ -299,6 +300,7 @@ TEST_F(BackgroundTracingConfigTest, ValidPreemptiveCategoryToString) {
"BENCHMARK_MEMORY_HEAVY",
"BENCHMARK_MEMORY_LIGHT",
"BENCHMARK_EXECUTION_METRIC",
+ "BENCHMARK_NAVIGATION",
"BLINK_STYLE"};
for (size_t i = 0;
i <
@@ -630,4 +632,4 @@ TEST_F(BackgroundTracingConfigTest, ValidReactiveConfigToString) {
}
}
-} // namspace content
+} // namespace content
diff --git a/chromium/content/browser/tracing/background_tracing_manager_browsertest.cc b/chromium/content/browser/tracing/background_tracing_manager_browsertest.cc
index d419bace500..cea17d06e49 100644
--- a/chromium/content/browser/tracing/background_tracing_manager_browsertest.cc
+++ b/chromium/content/browser/tracing/background_tracing_manager_browsertest.cc
@@ -16,6 +16,7 @@
#include "base/run_loop.h"
#include "base/strings/pattern.h"
#include "base/trace_event/trace_event.h"
+#include "content/browser/tracing/background_startup_tracing_observer.h"
#include "content/browser/tracing/background_tracing_manager_impl.h"
#include "content/browser/tracing/background_tracing_rule.h"
#include "content/public/browser/browser_thread.h"
@@ -95,6 +96,19 @@ void TestBackgroundTracingObserver::OnTracingEnabled(
tracing_enabled_callback_.Run();
}
+class TestStartupPreferenceManagerImpl
+ : public BackgroundStartupTracingObserver::PreferenceManager {
+ public:
+ void SetBackgroundStartupTracingEnabled(bool enabled) override {
+ enabled_ = enabled;
+ }
+
+ bool GetBackgroundStartupTracingEnabled() const override { return enabled_; }
+
+ private:
+ bool enabled_ = false;
+};
+
} // namespace
class BackgroundTracingManagerBrowserTest : public ContentBrowserTest {
@@ -1588,4 +1602,123 @@ IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
}
}
+IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
+ SetupStartupTracing) {
+ SetupBackgroundTracingManager();
+ std::unique_ptr<TestStartupPreferenceManagerImpl> preferences_moved(
+ new TestStartupPreferenceManagerImpl);
+ TestStartupPreferenceManagerImpl* preferences = preferences_moved.get();
+ BackgroundStartupTracingObserver::GetInstance()
+ ->SetPreferenceManagerForTesting(std::move(preferences_moved));
+ preferences->SetBackgroundStartupTracingEnabled(false);
+ BackgroundTracingManagerUploadConfigWrapper upload_config_wrapper(
+ (base::OnceClosure()));
+
+ base::DictionaryValue dict;
+ std::unique_ptr<base::ListValue> rules_list(new base::ListValue());
+ {
+ std::unique_ptr<base::DictionaryValue> rules_dict(
+ new base::DictionaryValue());
+ rules_dict->SetString("rule", "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED");
+ rules_dict->SetString("trigger_name", "startup-config");
+ rules_dict->SetBoolean("stop_tracing_on_repeated_reactive", false);
+ rules_dict->SetInteger("trigger_delay", 10);
+ rules_dict->SetString("category", "BENCHMARK_STARTUP");
+ rules_list->Append(std::move(rules_dict));
+ }
+ dict.Set("configs", std::move(rules_list));
+
+ std::unique_ptr<BackgroundTracingConfig> config(
+ BackgroundTracingConfigImpl::ReactiveFromDict(&dict));
+
+ base::RunLoop wait_for_tracing_enabled;
+ TestBackgroundTracingObserver observer(
+ wait_for_tracing_enabled.QuitClosure());
+ EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
+ std::move(config), upload_config_wrapper.get_receive_callback(),
+ BackgroundTracingManager::NO_DATA_FILTERING));
+
+ BackgroundTracingManager::GetInstance()->WhenIdle(
+ base::BindRepeating(&DisableScenarioWhenIdle));
+
+ base::RunLoop().RunUntilIdle();
+
+ // Since we specified a delay in the scenario, we should still be tracing
+ // at this point.
+ EXPECT_FALSE(
+ BackgroundTracingManagerImpl::GetInstance()->IsTracingForTesting());
+ EXPECT_TRUE(preferences->GetBackgroundStartupTracingEnabled());
+}
+
+IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest, RunStartupTracing) {
+ SetupBackgroundTracingManager();
+ std::unique_ptr<TestStartupPreferenceManagerImpl> preferences_moved(
+ new TestStartupPreferenceManagerImpl);
+ TestStartupPreferenceManagerImpl* preferences = preferences_moved.get();
+ BackgroundStartupTracingObserver::GetInstance()
+ ->SetPreferenceManagerForTesting(std::move(preferences_moved));
+ preferences->SetBackgroundStartupTracingEnabled(true);
+ TraceLog::GetInstance()->SetArgumentFilterPredicate(
+ base::BindRepeating(&IsTraceEventArgsWhitelisted));
+ base::RunLoop wait_for_trace_log_enabled;
+ std::unique_ptr<TestEnabledStateObserver> trace_log_observer(
+ new TestEnabledStateObserver(wait_for_trace_log_enabled.QuitClosure()));
+
+ base::RunLoop run_loop;
+ BackgroundTracingManagerUploadConfigWrapper upload_config_wrapper(
+ run_loop.QuitClosure());
+
+ base::DictionaryValue dict;
+ std::unique_ptr<base::ListValue> rules_list(new base::ListValue());
+ {
+ std::unique_ptr<base::DictionaryValue> rules_dict(
+ new base::DictionaryValue());
+ rules_dict->SetString("rule", "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED");
+ rules_dict->SetString("trigger_name", "gpu-config");
+ rules_dict->SetBoolean("stop_tracing_on_repeated_reactive", false);
+ rules_dict->SetInteger("trigger_delay", 10);
+ rules_dict->SetString("category", "BENCHMARK_GPU");
+ rules_list->Append(std::move(rules_dict));
+ }
+ dict.Set("configs", std::move(rules_list));
+
+ std::unique_ptr<BackgroundTracingConfig> config(
+ BackgroundTracingConfigImpl::ReactiveFromDict(&dict));
+
+ base::RunLoop wait_for_tracing_enabled;
+ TestBackgroundTracingObserver observer(
+ wait_for_tracing_enabled.QuitClosure());
+ EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
+ std::move(config), upload_config_wrapper.get_receive_callback(),
+ BackgroundTracingManager::NO_DATA_FILTERING));
+
+ BackgroundTracingManager::GetInstance()->WhenIdle(
+ base::BindRepeating(&DisableScenarioWhenIdle));
+
+ wait_for_tracing_enabled.Run();
+ wait_for_trace_log_enabled.Run();
+ trace_log_observer.reset();
+
+ EXPECT_TRUE(BackgroundTracingManagerImpl::GetInstance()
+ ->requires_anonymized_data_for_testing());
+ EXPECT_TRUE(base::trace_event::TraceLog::GetInstance()
+ ->GetCurrentTraceConfig()
+ .IsArgumentFilterEnabled());
+
+ // Since we specified a delay in the scenario, we should still be tracing
+ // at this point.
+ EXPECT_TRUE(
+ BackgroundTracingManagerImpl::GetInstance()->IsTracingForTesting());
+
+ BackgroundTracingManager::GetInstance()->FireTimerForTesting();
+
+ EXPECT_FALSE(
+ BackgroundTracingManagerImpl::GetInstance()->IsTracingForTesting());
+
+ run_loop.Run();
+
+ EXPECT_TRUE(upload_config_wrapper.get_receive_count() == 1);
+ EXPECT_FALSE(preferences->GetBackgroundStartupTracingEnabled());
+}
+
} // namespace content
diff --git a/chromium/content/browser/tracing/background_tracing_manager_impl.cc b/chromium/content/browser/tracing/background_tracing_manager_impl.cc
index 30d131e9d11..444fb27438d 100644
--- a/chromium/content/browser/tracing/background_tracing_manager_impl.cc
+++ b/chromium/content/browser/tracing/background_tracing_manager_impl.cc
@@ -16,7 +16,9 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "base/values.h"
+#include "components/tracing/common/trace_startup_config.h"
#include "content/browser/tracing/background_memory_tracing_observer.h"
+#include "content/browser/tracing/background_startup_tracing_observer.h"
#include "content/browser/tracing/background_tracing_rule.h"
#include "content/browser/tracing/trace_message_filter.h"
#include "content/browser/tracing/tracing_controller_impl.h"
@@ -27,6 +29,8 @@
#include "content/public/common/content_switches.h"
#include "services/tracing/public/cpp/trace_event_agent.h"
+using base::trace_event::TraceConfig;
+
namespace content {
namespace {
@@ -48,6 +52,7 @@ enum BackgroundTracingMetrics {
SCENARIO_ACTION_FAILED_LOWRES_CLOCK = 9,
UPLOAD_FAILED = 10,
UPLOAD_SUCCEEDED = 11,
+ STARTUP_SCENARIO_TRIGGERED = 12,
NUMBER_OF_BACKGROUND_TRACING_METRICS,
};
@@ -100,6 +105,7 @@ BackgroundTracingManagerImpl::BackgroundTracingManagerImpl()
trigger_handle_ids_(0),
triggered_named_event_handle_(-1) {
AddEnabledStateObserver(BackgroundMemoryTracingObserver::GetInstance());
+ AddEnabledStateObserver(BackgroundStartupTracingObserver::GetInstance());
}
BackgroundTracingManagerImpl::~BackgroundTracingManagerImpl() {
@@ -125,7 +131,8 @@ bool BackgroundTracingManagerImpl::SetActiveScenario(
BackgroundTracingManager::ReceiveCallback receive_callback,
DataFiltering data_filtering) {
CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- RecordBackgroundTracingMetric(SCENARIO_ACTIVATION_REQUESTED);
+ if (config)
+ RecordBackgroundTracingMetric(SCENARIO_ACTIVATION_REQUESTED);
if (is_tracing_)
return false;
@@ -133,10 +140,31 @@ bool BackgroundTracingManagerImpl::SetActiveScenario(
// If we don't have a high resolution timer available, traces will be
// too inaccurate to be useful.
if (!base::TimeTicks::IsHighResolution()) {
- RecordBackgroundTracingMetric(SCENARIO_ACTION_FAILED_LOWRES_CLOCK);
+ if (config)
+ RecordBackgroundTracingMetric(SCENARIO_ACTION_FAILED_LOWRES_CLOCK);
return false;
}
+ std::unique_ptr<content::BackgroundTracingConfigImpl> config_impl(
+ static_cast<BackgroundTracingConfigImpl*>(config.release()));
+ config_impl = BackgroundStartupTracingObserver::GetInstance()
+ ->IncludeStartupConfigIfNeeded(std::move(config_impl));
+ if (BackgroundStartupTracingObserver::GetInstance()
+ ->enabled_in_current_session()) {
+ // Anonymize data for startup tracing by default. We currently do not
+ // support storing the config in preferences for next session.
+ data_filtering = DataFiltering::ANONYMIZE_DATA;
+ RecordBackgroundTracingMetric(STARTUP_SCENARIO_TRIGGERED);
+ } else {
+ // If startup config was not set and tracing was enabled, then do not set
+ // any scenario.
+ if (base::trace_event::TraceLog::GetInstance()->IsEnabled())
+ return false;
+ }
+
+ if (!config_impl)
+ return false;
+
bool requires_anonymized_data = (data_filtering == ANONYMIZE_DATA);
// If the profile hasn't loaded or been created yet, this is a startup
@@ -144,9 +172,9 @@ bool BackgroundTracingManagerImpl::SetActiveScenario(
// that the scenario can run.
if (!delegate_ || delegate_->IsProfileLoaded()) {
// TODO(oysteine): Retry when time_until_allowed has elapsed.
- if (config && delegate_ &&
+ if (config_impl && delegate_ &&
!delegate_->IsAllowedToBeginBackgroundScenario(
- *config.get(), requires_anonymized_data)) {
+ *config_impl.get(), requires_anonymized_data)) {
return false;
}
} else {
@@ -156,9 +184,6 @@ bool BackgroundTracingManagerImpl::SetActiveScenario(
base::Unretained(this)));
}
- std::unique_ptr<const content::BackgroundTracingConfigImpl> config_impl(
- static_cast<BackgroundTracingConfigImpl*>(config.release()));
-
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (config_impl) {
@@ -185,20 +210,18 @@ bool BackgroundTracingManagerImpl::SetActiveScenario(
receive_callback_ = std::move(receive_callback);
requires_anonymized_data_ = requires_anonymized_data;
- if (config_) {
- DCHECK(!config_->rules().empty());
- for (const auto& rule : config_->rules())
- rule->Install();
+ DCHECK(!config_->rules().empty());
+ for (const auto& rule : config_->rules())
+ rule->Install();
- if (!config_->enable_blink_features().empty()) {
- command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures,
- config_->enable_blink_features());
- }
+ if (!config_->enable_blink_features().empty()) {
+ command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures,
+ config_->enable_blink_features());
+ }
- if (!config_->disable_blink_features().empty()) {
- command_line->AppendSwitchASCII(switches::kDisableBlinkFeatures,
- config_->disable_blink_features());
- }
+ if (!config_->disable_blink_features().empty()) {
+ command_line->AppendSwitchASCII(switches::kDisableBlinkFeatures,
+ config_->disable_blink_features());
}
// Notify observers before starting tracing.
@@ -374,7 +397,11 @@ void BackgroundTracingManagerImpl::TriggerNamedEvent(
void BackgroundTracingManagerImpl::OnRuleTriggered(
const BackgroundTracingRule* triggered_rule,
StartedFinalizingCallback callback) {
- CHECK(config_);
+ // Config can be null here if scenario was aborted when validation and rule
+ // was triggered just before validation. If validation kicked in after this
+ // point, we still check before uploading.
+ if (!config_)
+ return;
double trigger_chance = triggered_rule->trigger_chance();
if (trigger_chance < 1.0 && base::RandDouble() > trigger_chance) {
@@ -472,27 +499,13 @@ void BackgroundTracingManagerImpl::FireTimerForTesting() {
void BackgroundTracingManagerImpl::StartTracing(
BackgroundTracingConfigImpl::CategoryPreset preset,
base::trace_event::TraceRecordMode record_mode) {
- base::trace_event::TraceConfig trace_config(
- GetCategoryFilterStringForCategoryPreset(preset), record_mode);
+ TraceConfig config = GetConfigForCategoryPreset(preset, record_mode);
if (requires_anonymized_data_)
- trace_config.EnableArgumentFilter();
-
- if (preset ==
- BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_MEMORY_LIGHT) {
- // On memory light mode, the periodic memory dumps are disabled.
- // TODO(ssid): Remove this when memory-infra supports peak detection
- // crbug.com/609935.
- base::trace_event::TraceConfig::MemoryDumpConfig memory_config;
- memory_config.allowed_dump_modes =
- std::set<base::trace_event::MemoryDumpLevelOfDetail>(
- {base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND});
- trace_config.ResetMemoryDumpConfig(memory_config);
- }
+ config.EnableArgumentFilter();
is_tracing_ = TracingControllerImpl::GetInstance()->StartTracing(
- trace_config,
- base::Bind(&BackgroundTracingManagerImpl::OnStartTracingDone,
- base::Unretained(this), preset));
+ config, base::Bind(&BackgroundTracingManagerImpl::OnStartTracingDone,
+ base::Unretained(this), preset));
RecordBackgroundTracingMetric(RECORDING_ENABLED);
}
@@ -561,8 +574,7 @@ bool BackgroundTracingManagerImpl::IsAllowedFinalization() const {
std::unique_ptr<base::DictionaryValue>
BackgroundTracingManagerImpl::GenerateMetadataDict() {
- if (!IsAllowedFinalization())
- return nullptr;
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto metadata_dict = std::make_unique<base::DictionaryValue>();
if (config_) {
@@ -627,39 +639,65 @@ void BackgroundTracingManagerImpl::AbortScenario() {
observer->OnScenarioAborted();
}
-std::string
-BackgroundTracingManagerImpl::GetCategoryFilterStringForCategoryPreset(
- BackgroundTracingConfigImpl::CategoryPreset preset) const {
+TraceConfig BackgroundTracingManagerImpl::GetConfigForCategoryPreset(
+ BackgroundTracingConfigImpl::CategoryPreset preset,
+ base::trace_event::TraceRecordMode record_mode) const {
switch (preset) {
case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK:
- return "benchmark,toplevel";
+ return TraceConfig("benchmark,toplevel", record_mode);
case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_DEEP:
- return "*,disabled-by-default-benchmark.detailed,"
- "disabled-by-default-v8.cpu_profile,"
- "disabled-by-default-v8.runtime_stats";
+ return TraceConfig(
+ "*,disabled-by-default-benchmark.detailed,"
+ "disabled-by-default-v8.cpu_profile,"
+ "disabled-by-default-v8.runtime_stats",
+ record_mode);
case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_GPU:
- return "benchmark,toplevel,gpu";
+ return TraceConfig("benchmark,toplevel,gpu", record_mode);
case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_IPC:
- return "benchmark,toplevel,ipc";
- case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_STARTUP:
- return "benchmark,toplevel,startup,disabled-by-default-file,"
- "disabled-by-default-toplevel.flow,"
- "disabled-by-default-ipc.flow";
+ return TraceConfig("benchmark,toplevel,ipc", record_mode);
+ case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_STARTUP: {
+ auto config =
+ tracing::TraceStartupConfig::GetDefaultBrowserStartupConfig();
+ config.SetTraceRecordMode(record_mode);
+ return config;
+ }
case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_BLINK_GC:
- return "blink_gc,disabled-by-default-blink_gc";
- case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_MEMORY_HEAVY:
- case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_MEMORY_LIGHT:
- return "-*,disabled-by-default-memory-infra";
+ return TraceConfig("blink_gc,disabled-by-default-blink_gc", record_mode);
case BackgroundTracingConfigImpl::CategoryPreset::
BENCHMARK_EXECUTION_METRIC:
- return "blink.console,v8";
+ return TraceConfig("blink.console,v8", record_mode);
+ case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_NAVIGATION: {
+ auto config = TraceConfig(
+ "benchmark,toplevel,ipc,base,browser,navigation,omnibox,"
+ "safe_browsing,disabled-by-default-system_stats",
+ record_mode);
+ // Filter only browser process events.
+ base::trace_event::TraceConfig::ProcessFilterConfig process_config(
+ {base::GetCurrentProcId()});
+ config.SetProcessFilterConfig(process_config);
+ return config;
+ }
case BackgroundTracingConfigImpl::CategoryPreset::BLINK_STYLE:
- return "blink_style";
+ return TraceConfig("blink_style", record_mode);
+
+ case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_MEMORY_HEAVY:
+ return TraceConfig("-*,disabled-by-default-memory-infra", record_mode);
+ case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_MEMORY_LIGHT: {
+ // On memory light mode, the periodic memory dumps are disabled.
+ base::trace_event::TraceConfig::MemoryDumpConfig memory_config;
+ memory_config.allowed_dump_modes =
+ std::set<base::trace_event::MemoryDumpLevelOfDetail>(
+ {base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND});
+ TraceConfig config("-*,disabled-by-default-memory-infra", record_mode);
+ config.ResetMemoryDumpConfig(memory_config);
+ return config;
+ }
+
case BackgroundTracingConfigImpl::CategoryPreset::CATEGORY_PRESET_UNSET:
NOTREACHED();
}
NOTREACHED();
- return "";
+ return TraceConfig();
}
-} // namspace content
+} // namespace content
diff --git a/chromium/content/browser/tracing/background_tracing_manager_impl.h b/chromium/content/browser/tracing/background_tracing_manager_impl.h
index d5c8fe92c1b..d242895ccdb 100644
--- a/chromium/content/browser/tracing/background_tracing_manager_impl.h
+++ b/chromium/content/browser/tracing/background_tracing_manager_impl.h
@@ -93,6 +93,9 @@ class BackgroundTracingManagerImpl : public BackgroundTracingManager {
const base::Closure& callback);
void FireTimerForTesting() override;
CONTENT_EXPORT bool IsTracingForTesting();
+ CONTENT_EXPORT bool requires_anonymized_data_for_testing() const {
+ return requires_anonymized_data_;
+ }
private:
BackgroundTracingManagerImpl();
@@ -118,8 +121,9 @@ class BackgroundTracingManagerImpl : public BackgroundTracingManager {
TriggerHandle handle) const;
bool IsSupportedConfig(BackgroundTracingConfigImpl* config);
- std::string GetCategoryFilterStringForCategoryPreset(
- BackgroundTracingConfigImpl::CategoryPreset) const;
+ base::trace_event::TraceConfig GetConfigForCategoryPreset(
+ BackgroundTracingConfigImpl::CategoryPreset,
+ base::trace_event::TraceRecordMode) const;
class TracingTimer {
public:
diff --git a/chromium/content/browser/tracing/background_tracing_rule.cc b/chromium/content/browser/tracing/background_tracing_rule.cc
index f69616755c8..88b260a0bcf 100644
--- a/chromium/content/browser/tracing/background_tracing_rule.cc
+++ b/chromium/content/browser/tracing/background_tracing_rule.cc
@@ -267,6 +267,12 @@ class HistogramRule
return;
}
+ // Add the histogram name and its corresponding value to the trace.
+ TRACE_EVENT_INSTANT2("toplevel",
+ "BackgroundTracingRule::OnHistogramTrigger",
+ TRACE_EVENT_SCOPE_THREAD, "histogram_name",
+ histogram_name, "value", actual_value);
+
OnHistogramTrigger(histogram_name);
}
@@ -373,9 +379,10 @@ class TraceAtRandomIntervalsRule : public BackgroundTracingRule {
void StartTimer() {
int time_to_wait = base::RandInt(kReactiveTraceRandomStartTimeMin,
kReactiveTraceRandomStartTimeMax);
- trigger_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(time_to_wait),
- base::Bind(&TraceAtRandomIntervalsRule::OnTriggerTimer,
- base::Unretained(this)));
+ trigger_timer_.Start(
+ FROM_HERE, base::TimeDelta::FromSeconds(time_to_wait),
+ base::BindOnce(&TraceAtRandomIntervalsRule::OnTriggerTimer,
+ base::Unretained(this)));
}
int GetTraceDelay() const override {
diff --git a/chromium/content/browser/tracing/cast_tracing_agent.cc b/chromium/content/browser/tracing/cast_tracing_agent.cc
index 29e016250bc..77909801efc 100644
--- a/chromium/content/browser/tracing/cast_tracing_agent.cc
+++ b/chromium/content/browser/tracing/cast_tracing_agent.cc
@@ -9,7 +9,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h"
-#include "base/task_scheduler/task_scheduler.h"
+#include "base/task/post_task.h"
#include "base/trace_event/trace_config.h"
#include "chromecast/tracing/system_tracing_common.h"
#include "content/public/browser/browser_thread.h"
@@ -47,10 +47,9 @@ CastTracingAgent::CastTracingAgent(service_manager::Connector* connector)
tracing::mojom::TraceDataType::STRING,
false /* supports_explicit_clock_sync */,
base::kNullProcessId) {
- task_runner_ =
- base::TaskScheduler::GetInstance()->CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::BACKGROUND,
- base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
+ task_runner_ = base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
}
CastTracingAgent::~CastTracingAgent() = default;
diff --git a/chromium/content/browser/tracing/cros_tracing_agent.cc b/chromium/content/browser/tracing/cros_tracing_agent.cc
index 7a1cb3536ab..476789e6f4a 100644
--- a/chromium/content/browser/tracing/cros_tracing_agent.cc
+++ b/chromium/content/browser/tracing/cros_tracing_agent.cc
@@ -10,7 +10,7 @@
#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/memory/ref_counted_memory.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/trace_event/trace_config.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/debug_daemon_client.h"
diff --git a/chromium/content/browser/tracing/power_tracing_agent.cc b/chromium/content/browser/tracing/power_tracing_agent.cc
deleted file mode 100644
index c1b6bb29b29..00000000000
--- a/chromium/content/browser/tracing/power_tracing_agent.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 "content/browser/tracing/power_tracing_agent.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/lazy_instance.h"
-#include "base/memory/singleton.h"
-#include "base/task_scheduler/post_task.h"
-#include "base/task_scheduler/task_traits.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "base/trace_event/trace_config.h"
-#include "base/trace_event/trace_event_impl.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
-#include "services/service_manager/public/cpp/connector.h"
-#include "services/tracing/public/mojom/constants.mojom.h"
-#include "tools/battor_agent/battor_finder.h"
-
-namespace content {
-
-namespace {
-
-const char kPowerTraceLabel[] = "powerTraceAsString";
-
-} // namespace
-
-// static
-PowerTracingAgent* PowerTracingAgent::GetInstance() {
- return base::Singleton<PowerTracingAgent>::get();
-}
-
-PowerTracingAgent::PowerTracingAgent(service_manager::Connector* connector)
- : binding_(this) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- // Connect to the agent registry interface.
- tracing::mojom::AgentRegistryPtr agent_registry;
- connector->BindInterface(tracing::mojom::kServiceName, &agent_registry);
-
- // Register this agent.
- tracing::mojom::AgentPtr agent;
- binding_.Bind(mojo::MakeRequest(&agent));
- agent_registry->RegisterAgent(
- std::move(agent), kPowerTraceLabel, tracing::mojom::TraceDataType::STRING,
- true /* supports_explicit_clock_sync */, base::kNullProcessId);
-}
-
-PowerTracingAgent::PowerTracingAgent() : binding_(this) {}
-PowerTracingAgent::~PowerTracingAgent() = default;
-
-void PowerTracingAgent::StartTracing(const std::string& config,
- base::TimeTicks coordinator_time,
- Agent::StartTracingCallback callback) {
- base::trace_event::TraceConfig trace_config(config);
- if (!trace_config.IsSystraceEnabled()) {
- std::move(callback).Run(false /* success */);
- return;
- }
-
- base::PostTaskWithTraits(
- FROM_HERE, {base::TaskPriority::BACKGROUND, base::MayBlock()},
- base::BindOnce(&PowerTracingAgent::FindBattOrOnBackgroundThread,
- base::Unretained(this), std::move(callback)));
-}
-
-void PowerTracingAgent::FindBattOrOnBackgroundThread(
- Agent::StartTracingCallback callback) {
- std::string path = battor::BattOrFinder::FindBattOr();
- if (path.empty()) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::BindOnce(std::move(callback), false /* success */));
- return;
- }
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(&PowerTracingAgent::StartTracingOnIOThread,
- base::Unretained(this), path, std::move(callback)));
-}
-
-void PowerTracingAgent::StartTracingOnIOThread(
- const std::string& path,
- Agent::StartTracingCallback callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- battor_agent_.reset(new battor::BattOrAgent(
- path, this, BrowserThread::GetTaskRunnerForThread(BrowserThread::UI)));
-
- start_tracing_callback_ = std::move(callback);
- battor_agent_->StartTracing();
-}
-
-void PowerTracingAgent::OnStartTracingComplete(battor::BattOrError error) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- bool success = (error == battor::BATTOR_ERROR_NONE);
- if (!success)
- battor_agent_.reset();
-
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::BindOnce(std::move(start_tracing_callback_), success));
-}
-
-void PowerTracingAgent::StopAndFlush(tracing::mojom::RecorderPtr recorder) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(&PowerTracingAgent::StopAndFlushOnIOThread,
- base::Unretained(this), std::move(recorder)));
-}
-
-void PowerTracingAgent::StopAndFlushOnIOThread(
- tracing::mojom::RecorderPtr recorder) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- // This makes sense only when the battor agent exists.
- if (battor_agent_) {
- recorder_ = std::move(recorder);
- battor_agent_->StopTracing();
- }
-}
-
-void PowerTracingAgent::OnStopTracingComplete(
- const battor::BattOrResults& results,
- battor::BattOrError error) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- if (error == battor::BATTOR_ERROR_NONE)
- recorder_->AddChunk(results.ToString());
- recorder_.reset();
- battor_agent_.reset();
-}
-
-void PowerTracingAgent::RequestClockSyncMarker(
- const std::string& sync_id,
- Agent::RequestClockSyncMarkerCallback callback) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(&PowerTracingAgent::RequestClockSyncMarkerOnIOThread,
- base::Unretained(this), sync_id, std::move(callback)));
-}
-
-void PowerTracingAgent::RequestClockSyncMarkerOnIOThread(
- const std::string& sync_id,
- Agent::RequestClockSyncMarkerCallback callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- // This makes sense only when the battor agent exists.
- if (!battor_agent_) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::BindOnce(std::move(callback), base::TimeTicks(),
- base::TimeTicks()));
- return;
- }
-
- request_clock_sync_marker_callback_ = std::move(callback);
- request_clock_sync_marker_start_time_ = TRACE_TIME_TICKS_NOW();
- battor_agent_->RecordClockSyncMarker(sync_id);
-}
-
-void PowerTracingAgent::OnRecordClockSyncMarkerComplete(
- battor::BattOrError error) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- base::TimeTicks issue_start_ts = request_clock_sync_marker_start_time_;
- base::TimeTicks issue_end_ts = TRACE_TIME_TICKS_NOW();
-
- if (error != battor::BATTOR_ERROR_NONE)
- issue_start_ts = issue_end_ts = base::TimeTicks();
-
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::BindOnce(std::move(request_clock_sync_marker_callback_),
- issue_start_ts, issue_end_ts));
- request_clock_sync_marker_start_time_ = base::TimeTicks();
-}
-
-void PowerTracingAgent::OnGetFirmwareGitHashComplete(
- const std::string& version, battor::BattOrError error) {
- return;
-}
-
-void PowerTracingAgent::GetCategories(Agent::GetCategoriesCallback callback) {
- std::move(callback).Run("");
-}
-
-void PowerTracingAgent::RequestBufferStatus(
- Agent::RequestBufferStatusCallback callback) {
- std::move(callback).Run(0, 0);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/tracing/power_tracing_agent.h b/chromium/content/browser/tracing/power_tracing_agent.h
deleted file mode 100644
index 6623bc121d5..00000000000
--- a/chromium/content/browser/tracing/power_tracing_agent.h
+++ /dev/null
@@ -1,98 +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 CONTENT_BROWSER_TRACING_POWER_TRACING_AGENT_H_
-#define CONTENT_BROWSER_TRACING_POWER_TRACING_AGENT_H_
-
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted_memory.h"
-#include "base/threading/thread.h"
-#include "content/public/browser/browser_thread.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "services/tracing/public/mojom/tracing.mojom.h"
-#include "tools/battor_agent/battor_agent.h"
-#include "tools/battor_agent/battor_error.h"
-
-namespace base {
-template <typename Type>
-struct DefaultSingletonTraits;
-} // namespace base
-
-namespace service_manager {
-class Connector;
-} // namespace service_manager
-
-namespace content {
-
-using tracing::mojom::Agent;
-
-class PowerTracingAgent : public Agent, public battor::BattOrAgent::Listener {
- public:
- // Retrieve the singleton instance.
- static PowerTracingAgent* GetInstance();
-
- explicit PowerTracingAgent(service_manager::Connector* connector);
-
- // BattOrAgent::Listener implementation.
- void OnStartTracingComplete(battor::BattOrError error) override;
- void OnStopTracingComplete(const battor::BattOrResults& results,
- battor::BattOrError error) override;
- void OnRecordClockSyncMarkerComplete(battor::BattOrError error) override;
- void OnGetFirmwareGitHashComplete(const std::string& version,
- battor::BattOrError error) override;
-
- private:
- // This allows constructor and destructor to be private and usable only
- // by the Singleton class.
- friend struct base::DefaultSingletonTraits<PowerTracingAgent>;
- friend std::default_delete<PowerTracingAgent>;
-
- PowerTracingAgent();
- ~PowerTracingAgent() override;
-
- // tracing::mojom::Agent. Called by Mojo internals on the UI thread.
- void StartTracing(const std::string& config,
- base::TimeTicks coordinator_time,
- Agent::StartTracingCallback callback) override;
- void StopAndFlush(tracing::mojom::RecorderPtr recorder) override;
- void RequestClockSyncMarker(
- const std::string& sync_id,
- Agent::RequestClockSyncMarkerCallback callback) override;
- void GetCategories(Agent::GetCategoriesCallback callback) override;
- void RequestBufferStatus(
- Agent::RequestBufferStatusCallback callback) override;
-
- void FindBattOrOnBackgroundThread(Agent::StartTracingCallback callback);
- void StartTracingOnIOThread(const std::string& path,
- Agent::StartTracingCallback callback);
- void StopAndFlushOnIOThread(tracing::mojom::RecorderPtr recorder);
- void RequestClockSyncMarkerOnIOThread(
- const std::string& sync_id,
- Agent::RequestClockSyncMarkerCallback callback);
-
- // Returns the path of a BattOr (e.g. /dev/ttyUSB0), or an empty string if
- // none are found.
- std::string GetBattOrPath();
-
- // All interactions with the BattOrAgent (after construction) must happen on
- // the IO thread.
- std::unique_ptr<battor::BattOrAgent, BrowserThread::DeleteOnIOThread>
- battor_agent_;
-
- Agent::StartTracingCallback start_tracing_callback_;
- tracing::mojom::RecorderPtr recorder_;
- base::TimeTicks request_clock_sync_marker_start_time_;
- Agent::RequestClockSyncMarkerCallback request_clock_sync_marker_callback_;
-
- mojo::Binding<tracing::mojom::Agent> binding_;
-
- DISALLOW_COPY_AND_ASSIGN(PowerTracingAgent);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_TRACING_POWER_TRACING_AGENT_H_
diff --git a/chromium/content/browser/tracing/tracing_controller_browsertest.cc b/chromium/content/browser/tracing/tracing_controller_browsertest.cc
index 680c54845a5..40ee6778dd5 100644
--- a/chromium/content/browser/tracing/tracing_controller_browsertest.cc
+++ b/chromium/content/browser/tracing/tracing_controller_browsertest.cc
@@ -23,6 +23,7 @@
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "content/test/test_content_browser_client.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/tracing/public/cpp/trace_event_agent.h"
using base::trace_event::RECORD_CONTINUOUSLY;
@@ -104,7 +105,7 @@ class TracingTestBrowserClient : public TestContentBrowserClient {
class TestTracingDelegate : public TracingDelegate {
public:
std::unique_ptr<TraceUploader> GetTraceUploader(
- net::URLRequestContextGetter* request_context) override {
+ scoped_refptr<network::SharedURLLoaderFactory>) override {
return nullptr;
}
MetadataFilterPredicate GetMetadataFilterPredicate() override {
@@ -161,7 +162,7 @@ class TracingControllerTest : public ContentBrowserTest {
const base::FilePath& file_path) {
disable_recording_done_callback_count_++;
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_test_verifications;
+ base::ScopedAllowBlockingForTesting allow_blocking;
EXPECT_TRUE(PathExists(file_path));
int64_t file_size;
base::GetFileSize(file_path, &file_size);
@@ -357,7 +358,13 @@ class TracingControllerTest : public ContentBrowserTest {
std::string last_data_;
};
-IN_PROC_BROWSER_TEST_F(TracingControllerTest, GetCategories) {
+// TODO(crbug.com/871770): Disabled for failing on ASAN.
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_GetCategories DISABLED_GetCategories
+#else
+#define MAYBE_GetCategories GetCategories
+#endif
+IN_PROC_BROWSER_TEST_F(TracingControllerTest, MAYBE_GetCategories) {
Navigate(shell());
TracingController* controller = TracingController::GetInstance();
@@ -372,11 +379,25 @@ IN_PROC_BROWSER_TEST_F(TracingControllerTest, GetCategories) {
EXPECT_EQ(get_categories_done_callback_count(), 1);
}
-IN_PROC_BROWSER_TEST_F(TracingControllerTest, EnableAndStopTracing) {
+// TODO(crbug.com/871770): Disabled for failing on ASAN.
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_EnableAndStopTracing DISABLED_EnableAndStopTracing
+#else
+#define MAYBE_EnableAndStopTracing EnableAndStopTracing
+#endif
+IN_PROC_BROWSER_TEST_F(TracingControllerTest, MAYBE_EnableAndStopTracing) {
TestStartAndStopTracingString();
}
-IN_PROC_BROWSER_TEST_F(TracingControllerTest, DisableRecordingStoresMetadata) {
+// TODO(crbug.com/871770): Disabled for failing on ASAN.
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_DisableRecordingStoresMetadata \
+ DISABLED_DisableRecordingStoresMetadata
+#else
+#define MAYBE_DisableRecordingStoresMetadata DisableRecordingStoresMetadata
+#endif
+IN_PROC_BROWSER_TEST_F(TracingControllerTest,
+ MAYBE_DisableRecordingStoresMetadata) {
TestStartAndStopTracingString();
// Check that a number of important keys exist in the metadata dictionary. The
// values are not checked to ensure the test is robust.
@@ -434,24 +455,47 @@ IN_PROC_BROWSER_TEST_F(TracingControllerTest,
EXPECT_TRUE(last_data().find("this_not_found") == std::string::npos);
}
+// TODO(crbug.com/871770): Disabled for failing on ASAN.
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_EnableAndStopTracingWithFilePath \
+ DISABLED_EnableAndStopTracingWithFilePath
+#else
+#define MAYBE_EnableAndStopTracingWithFilePath EnableAndStopTracingWithFilePath
+#endif
IN_PROC_BROWSER_TEST_F(TracingControllerTest,
- EnableAndStopTracingWithFilePath) {
+ MAYBE_EnableAndStopTracingWithFilePath) {
base::FilePath file_path;
{
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_creating_test_file;
+ base::ScopedAllowBlockingForTesting allow_blocking;
base::CreateTemporaryFile(&file_path);
}
TestStartAndStopTracingFile(file_path);
EXPECT_EQ(file_path.value(), last_actual_recording_file_path().value());
}
+// TODO(crbug.com/871770): Disabled for failing on ASAN.
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_EnableAndStopTracingWithCompression \
+ DISABLED_EnableAndStopTracingWithCompression
+#else
+#define MAYBE_EnableAndStopTracingWithCompression \
+ EnableAndStopTracingWithCompression
+#endif
IN_PROC_BROWSER_TEST_F(TracingControllerTest,
- EnableAndStopTracingWithCompression) {
+ MAYBE_EnableAndStopTracingWithCompression) {
TestStartAndStopTracingCompressed();
}
+// TODO(crbug.com/871770): Disabled for failing on ASAN.
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_EnableAndStopTracingWithEmptyFile \
+ DISABLED_EnableAndStopTracingWithEmptyFile
+#else
+#define MAYBE_EnableAndStopTracingWithEmptyFile \
+ EnableAndStopTracingWithEmptyFile
+#endif
IN_PROC_BROWSER_TEST_F(TracingControllerTest,
- EnableAndStopTracingWithEmptyFile) {
+ MAYBE_EnableAndStopTracingWithEmptyFile) {
Navigate(shell());
base::RunLoop run_loop;
@@ -470,7 +514,13 @@ IN_PROC_BROWSER_TEST_F(TracingControllerTest,
run_loop.Run();
}
-IN_PROC_BROWSER_TEST_F(TracingControllerTest, DoubleStopTracing) {
+// TODO(crbug.com/871770): Disabled for failing on ASAN.
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_DoubleStopTracing DISABLED_DoubleStopTracing
+#else
+#define MAYBE_DoubleStopTracing DoubleStopTracing
+#endif
+IN_PROC_BROWSER_TEST_F(TracingControllerTest, MAYBE_DoubleStopTracing) {
Navigate(shell());
base::RunLoop run_loop;
diff --git a/chromium/content/browser/tracing/tracing_controller_impl.cc b/chromium/content/browser/tracing/tracing_controller_impl.cc
index ee4fa86896e..424c2447cc0 100644
--- a/chromium/content/browser/tracing/tracing_controller_impl.cc
+++ b/chromium/content/browser/tracing/tracing_controller_impl.cc
@@ -38,15 +38,6 @@
#include "services/tracing/public/mojom/constants.mojom.h"
#include "v8/include/v8-version-string.h"
-#if (defined(OS_POSIX) && defined(USE_UDEV)) || defined(OS_WIN) || \
- defined(OS_MACOSX)
-#define ENABLE_POWER_TRACING
-#endif
-
-#if defined(ENABLE_POWER_TRACING)
-#include "content/browser/tracing/power_tracing_agent.h"
-#endif
-
#if defined(OS_CHROMEOS)
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/debug_daemon_client.h"
@@ -140,11 +131,6 @@ void TracingControllerImpl::AddAgents() {
content::ServiceManagerConnection::GetForProcess()->GetConnector();
connector->BindInterface(tracing::mojom::kServiceName, &coordinator_);
-// Register tracing agents.
-#if defined(ENABLE_POWER_TRACING)
- agents_.push_back(std::make_unique<PowerTracingAgent>(connector));
-#endif
-
#if defined(OS_CHROMEOS)
agents_.push_back(std::make_unique<CrOSTracingAgent>(connector));
#elif defined(CAST_TRACING_AGENT)
@@ -175,6 +161,7 @@ tracing::TraceEventAgent* TracingControllerImpl::GetTraceEventAgent() const {
std::unique_ptr<base::DictionaryValue>
TracingControllerImpl::GenerateMetadataDict() const {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto metadata_dict = std::make_unique<base::DictionaryValue>();
// trace_config_ can be null if the tracing controller finishes flushing
diff --git a/chromium/content/browser/tracing/tracing_controller_impl_data_endpoint.cc b/chromium/content/browser/tracing/tracing_controller_impl_data_endpoint.cc
index 4fcd026465f..6f3d4facd74 100644
--- a/chromium/content/browser/tracing/tracing_controller_impl_data_endpoint.cc
+++ b/chromium/content/browser/tracing/tracing_controller_impl_data_endpoint.cc
@@ -10,7 +10,7 @@
#include "base/memory/ref_counted_memory.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/pattern.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "content/browser/tracing/tracing_controller_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/tracing_controller.h"
@@ -118,7 +118,7 @@ class FileTraceDataEndpoint : public TracingController::TraceDataEndpoint {
FILE* file_;
const scoped_refptr<base::SequencedTaskRunner> background_task_runner_ =
base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::BACKGROUND});
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
DISALLOW_COPY_AND_ASSIGN(FileTraceDataEndpoint);
};
@@ -132,7 +132,7 @@ class CompressedTraceDataEndpoint
already_tried_open_(false),
background_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
{compress_with_background_priority
- ? base::TaskPriority::BACKGROUND
+ ? base::TaskPriority::BEST_EFFORT
: base::TaskPriority::USER_VISIBLE})) {}
void ReceiveTraceChunk(std::unique_ptr<std::string> chunk) override {
diff --git a/chromium/content/browser/tracing/tracing_ui.cc b/chromium/content/browser/tracing/tracing_ui.cc
index fd922b3e90f..dec9a194057 100644
--- a/chromium/content/browser/tracing/tracing_ui.cc
+++ b/chromium/content/browser/tracing/tracing_ui.cc
@@ -237,14 +237,13 @@ void TracingUI::DoUploadInternal(const std::string& file_contents,
TraceUploader::UploadProgressCallback progress_callback =
base::Bind(&TracingUI::OnTraceUploadProgress,
weak_factory_.GetWeakPtr());
- TraceUploader::UploadDoneCallback done_callback =
- base::Bind(&TracingUI::OnTraceUploadComplete,
- weak_factory_.GetWeakPtr());
+ TraceUploader::UploadDoneCallback done_callback = base::BindOnce(
+ &TracingUI::OnTraceUploadComplete, weak_factory_.GetWeakPtr());
trace_uploader_ = delegate_->GetTraceUploader(
BrowserContext::GetDefaultStoragePartition(
- web_ui()->GetWebContents()->GetBrowserContext())->
- GetURLRequestContext());
+ web_ui()->GetWebContents()->GetBrowserContext())
+ ->GetURLLoaderFactoryForBrowserProcess());
DCHECK(trace_uploader_);
trace_uploader_->DoUpload(file_contents, upload_mode, nullptr,
std::move(progress_callback),
diff --git a/chromium/content/browser/url_loader_factory_getter.cc b/chromium/content/browser/url_loader_factory_getter.cc
index d3f03804253..abcd580a115 100644
--- a/chromium/content/browser/url_loader_factory_getter.cc
+++ b/chromium/content/browser/url_loader_factory_getter.cc
@@ -111,13 +111,18 @@ URLLoaderFactoryGetter::URLLoaderFactoryForIOThreadInfo::CreateFactory() {
// -----------------------------------------------------------------------------
-URLLoaderFactoryGetter::URLLoaderFactoryGetter() {}
+URLLoaderFactoryGetter::URLLoaderFactoryGetter() = default;
void URLLoaderFactoryGetter::Initialize(StoragePartitionImpl* partition) {
DCHECK(partition);
- DCHECK(!pending_network_factory_request_.is_pending());
-
partition_ = partition;
+
+ // Create a URLLoaderFactoryPtr synchronously and push it to the IO thread. If
+ // the pipe errors out later due to a network service crash, the pipe is
+ // created on the IO thread, and the request send back to the UI thread.
+ // TODO(mmenke): Is one less thread hop on startup worth the extra complexity
+ // of two different pipe creation paths?
+ DCHECK(!pending_network_factory_request_.is_pending());
network::mojom::URLLoaderFactoryPtr network_factory;
pending_network_factory_request_ = MakeRequest(&network_factory);
@@ -160,19 +165,26 @@ URLLoaderFactoryGetter::GetNetworkFactoryInfo() {
network::mojom::URLLoaderFactory*
URLLoaderFactoryGetter::GetURLLoaderFactory() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (g_get_network_factory_callback.Get() && !test_factory_)
- g_get_network_factory_callback.Get().Run(this);
- if (test_factory_)
- return test_factory_;
-
- if (!network_factory_.is_bound() || network_factory_.encountered_error()) {
+ // This needs to be done before returning |test_factory_|, as the
+ // |test_factory_| may fall back to |network_factory_|. The |is_bound()| check
+ // is only needed by unit tests.
+ if (network_factory_.encountered_error() || !network_factory_.is_bound()) {
+ network::mojom::URLLoaderFactoryPtr network_factory;
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::BindOnce(
&URLLoaderFactoryGetter::HandleNetworkFactoryRequestOnUIThread,
- this, mojo::MakeRequest(&network_factory_)));
+ this, mojo::MakeRequest(&network_factory)));
+ ReinitializeOnIOThread(std::move(network_factory));
}
+
+ if (g_get_network_factory_callback.Get() && !test_factory_)
+ g_get_network_factory_callback.Get().Run(this);
+
+ if (test_factory_)
+ return test_factory_;
+
return network_factory_.get();
}
@@ -201,25 +213,40 @@ void URLLoaderFactoryGetter::SetGetNetworkFactoryCallbackForTesting(
void URLLoaderFactoryGetter::FlushNetworkInterfaceOnIOThreadForTesting() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::RunLoop run_loop;
- BrowserThread::PostTaskAndReply(
+ BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::BindOnce(&URLLoaderFactoryGetter::FlushNetworkInterfaceForTesting,
- this),
- run_loop.QuitClosure());
+ this, run_loop.QuitClosure()));
run_loop.Run();
}
-void URLLoaderFactoryGetter::FlushNetworkInterfaceForTesting() {
+void URLLoaderFactoryGetter::FlushNetworkInterfaceForTesting(
+ base::OnceClosure callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (network_factory_)
- network_factory_.FlushForTesting();
+ network_factory_.FlushAsyncForTesting(std::move(callback));
}
URLLoaderFactoryGetter::~URLLoaderFactoryGetter() {}
void URLLoaderFactoryGetter::InitializeOnIOThread(
network::mojom::URLLoaderFactoryPtrInfo network_factory) {
- network_factory_.Bind(std::move(network_factory));
+ ReinitializeOnIOThread(
+ network::mojom::URLLoaderFactoryPtr(std::move(network_factory)));
+}
+
+void URLLoaderFactoryGetter::ReinitializeOnIOThread(
+ network::mojom::URLLoaderFactoryPtr network_factory) {
+ DCHECK(network_factory.is_bound());
+ network_factory_ = std::move(network_factory);
+ // Set a connection error handle so that connection errors on the pipes are
+ // noticed, but the class doesn't actually do anything when the error is
+ // observed - instead, a new pipe is created in GetURLLoaderFactory() as
+ // needed. This is to avoid incrementing the reference count of |this| in the
+ // callback, as that could result in increasing the reference count from 0 to
+ // 1 while there's a pending task to delete |this|. See
+ // https://crbug.com/870942 for more details.
+ network_factory_.set_connection_error_handler(base::DoNothing());
}
void URLLoaderFactoryGetter::HandleNetworkFactoryRequestOnUIThread(
diff --git a/chromium/content/browser/url_loader_factory_getter.h b/chromium/content/browser/url_loader_factory_getter.h
index 39bfbab5b7e..dc998f3e6ad 100644
--- a/chromium/content/browser/url_loader_factory_getter.h
+++ b/chromium/content/browser/url_loader_factory_getter.h
@@ -99,6 +99,10 @@ class URLLoaderFactoryGetter
void InitializeOnIOThread(
network::mojom::URLLoaderFactoryPtrInfo network_factory);
+ // Moves |network_factory| to |network_factory_| and sets up an error handler.
+ void ReinitializeOnIOThread(
+ network::mojom::URLLoaderFactoryPtr network_factory);
+
// Send |network_factory_request| to cached |StoragePartitionImpl|.
void HandleNetworkFactoryRequestOnUIThread(
network::mojom::URLLoaderFactoryRequest network_factory_request);
@@ -107,8 +111,9 @@ class URLLoaderFactoryGetter
// The pointer shouldn't be cached.
network::mojom::URLLoaderFactory* GetURLLoaderFactory();
- // Call |network_factory_.FlushForTesting()|. For test use only.
- void FlushNetworkInterfaceForTesting();
+ // Call |network_factory_.FlushForTesting()|. For test use only. When the
+ // flush is complete, |callback| will be called.
+ void FlushNetworkInterfaceForTesting(base::OnceClosure callback);
// Bound with appropriate URLLoaderFactories at HandleFactoryRequests().
network::mojom::URLLoaderFactoryRequest pending_network_factory_request_;
diff --git a/chromium/content/browser/utility_process_host.cc b/chromium/content/browser/utility_process_host.cc
index 9d7c9791bd9..da650c76a0a 100644
--- a/chromium/content/browser/utility_process_host.cc
+++ b/chromium/content/browser/utility_process_host.cc
@@ -30,6 +30,7 @@
#include "content/public/common/service_manager_connection.h"
#include "content/public/common/service_names.mojom.h"
#include "media/base/media_switches.h"
+#include "media/webrtc/webrtc_switches.h"
#include "services/network/public/cpp/network_switches.h"
#include "services/service_manager/embedder/switches.h"
#include "services/service_manager/public/cpp/interface_provider.h"
@@ -85,6 +86,12 @@ class UtilitySandboxedProcessLauncherDelegate
~UtilitySandboxedProcessLauncherDelegate() override {}
#if defined(OS_WIN)
+ bool DisableDefaultPolicy() override {
+ // Default policy is disabled for audio process to allow audio drivers
+ // to read device properties (https://crbug.com/883326).
+ return sandbox_type_ == service_manager::SANDBOX_TYPE_AUDIO;
+ }
+
bool ShouldLaunchElevated() override {
return sandbox_type_ ==
service_manager::SANDBOX_TYPE_NO_SANDBOX_AND_ELEVATED_PRIVILEGES;
@@ -104,7 +111,8 @@ class UtilitySandboxedProcessLauncherDelegate
#if BUILDFLAG(USE_ZYGOTE_HANDLE)
service_manager::ZygoteHandle GetZygote() override {
if (service_manager::IsUnsandboxedSandboxType(sandbox_type_) ||
- sandbox_type_ == service_manager::SANDBOX_TYPE_NETWORK) {
+ sandbox_type_ == service_manager::SANDBOX_TYPE_NETWORK ||
+ sandbox_type_ == service_manager::SANDBOX_TYPE_AUDIO) {
return nullptr;
}
return service_manager::GetGenericZygote();
@@ -313,6 +321,8 @@ bool UtilityProcessHost::StartProcess() {
switches::kFailAudioStreamCreation,
switches::kMuteAudio,
switches::kUseFileForFakeAudioCapture,
+ switches::kAecRefinedAdaptiveFilter,
+ switches::kAgcStartupMinVolume,
#if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_SOLARIS)
switches::kAlsaInputDevice,
switches::kAlsaOutputDevice,
diff --git a/chromium/content/browser/web_contents/web_contents_android.cc b/chromium/content/browser/web_contents/web_contents_android.cc
index 8cb3bf4b93e..b0d3fea4d0f 100644
--- a/chromium/content/browser/web_contents/web_contents_android.cc
+++ b/chromium/content/browser/web_contents/web_contents_android.cc
@@ -19,7 +19,8 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/metrics/user_metrics.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
+#include "base/threading/scoped_blocking_call.h"
#include "content/browser/accessibility/browser_accessibility_android.h"
#include "content/browser/accessibility/browser_accessibility_manager_android.h"
#include "content/browser/android/java/gin_java_bridge_dispatcher_host.h"
@@ -142,7 +143,7 @@ void AXTreeSnapshotCallback(const ScopedJavaGlobalRef<jobject>& callback,
std::string CompressAndSaveBitmap(const std::string& dir,
const SkBitmap& bitmap) {
- base::AssertBlockingAllowed();
+ base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::WILL_BLOCK);
std::vector<unsigned char> data;
if (!gfx::JPEGCodec::Encode(bitmap, 85, &data)) {
@@ -860,16 +861,6 @@ bool WebContentsAndroid::IsBeingDestroyed(JNIEnv* env,
return web_contents_->IsBeingDestroyed();
}
-int WebContentsAndroid::GetTopControlsShrinkBlinkHeightPixForTesting(
- JNIEnv* env,
- const JavaParamRef<jobject>& obj) {
- RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
- float scale = web_contents_->GetNativeView()->GetDipScale();
- return (rwhva && rwhva->DoBrowserControlsShrinkBlinkSize())
- ? rwhva->GetTopControlsHeight() * scale
- : 0;
-}
-
void WebContentsAndroid::SetDisplayCutoutSafeArea(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
diff --git a/chromium/content/browser/web_contents/web_contents_android.h b/chromium/content/browser/web_contents/web_contents_android.h
index d5094a6ad5c..6e55efc61f7 100644
--- a/chromium/content/browser/web_contents/web_contents_android.h
+++ b/chromium/content/browser/web_contents/web_contents_android.h
@@ -243,12 +243,6 @@ class CONTENT_EXPORT WebContentsAndroid
bool IsBeingDestroyed(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj);
- // Returns the amount of the top controls height if controls are in the state
- // of shrinking Blink's view size, otherwise 0.
- int GetTopControlsShrinkBlinkHeightPixForTesting(
- JNIEnv* env,
- const base::android::JavaParamRef<jobject>& obj);
-
void SetDisplayCutoutSafeArea(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
int top,
@@ -256,9 +250,9 @@ class CONTENT_EXPORT WebContentsAndroid
int bottom,
int right);
- private:
RenderWidgetHostViewAndroid* GetRenderWidgetHostViewAndroid();
+ private:
void OnFinishGetContentBitmap(const base::android::JavaRef<jobject>& obj,
const base::android::JavaRef<jobject>& callback,
const std::string& path,
diff --git a/chromium/content/browser/web_contents/web_contents_impl.cc b/chromium/content/browser/web_contents/web_contents_impl.cc
index 26384f823b5..499c8c0a2e8 100644
--- a/chromium/content/browser/web_contents/web_contents_impl.cc
+++ b/chromium/content/browser/web_contents/web_contents_impl.cc
@@ -35,6 +35,8 @@
#include "components/download/public/common/download_stats.h"
#include "components/rappor/public/rappor_utils.h"
#include "components/url_formatter/url_formatter.h"
+#include "content/browser/accessibility/accessibility_tree_formatter.h"
+#include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
#include "content/browser/accessibility/browser_accessibility_state_impl.h"
#include "content/browser/bad_message.h"
#include "content/browser/browser_plugin/browser_plugin_embedder.h"
@@ -540,7 +542,7 @@ WebContentsImpl::WebContentsImpl(BrowserContext* browser_context)
force_disable_overscroll_content_(false),
last_dialog_suppressed_(false),
accessibility_mode_(
- BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode()),
+ BrowserAccessibilityStateImpl::GetInstance()->GetAccessibilityMode()),
audio_stream_monitor_(this),
bluetooth_connected_device_count_(0),
media_device_group_id_salt_base_(
@@ -570,11 +572,8 @@ WebContentsImpl::WebContentsImpl(BrowserContext* browser_context)
#endif // !defined(OS_ANDROID)
#if defined(OS_ANDROID)
- if (base::FeatureList::IsEnabled(features::kDisplayCutoutAPI)) {
- display_cutout_host_impl_ = std::make_unique<DisplayCutoutHostImpl>(
- this, base::BindRepeating(&WebContentsImpl::NotifyViewportFitChanged,
- base::Unretained(this)));
- }
+ if (base::FeatureList::IsEnabled(features::kDisplayCutoutAPI))
+ display_cutout_host_impl_ = std::make_unique<DisplayCutoutHostImpl>(this);
#endif
registry_.AddInterface(base::BindRepeating(
@@ -682,6 +681,9 @@ WebContentsImpl::~WebContentsImpl() {
for (auto& observer : observers_)
observer.WebContentsDestroyed();
+ if (display_cutout_host_impl_)
+ display_cutout_host_impl_->WebContentsDestroyed();
+
for (auto& observer : observers_)
observer.ResetWebContents();
@@ -802,6 +804,8 @@ bool WebContentsImpl::OnMessageReceived(RenderViewHostImpl* render_view_host,
IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(WebContentsImpl, message, render_view_host)
IPC_MESSAGE_HANDLER(ViewHostMsg_DidFirstVisuallyNonEmptyPaint,
OnFirstVisuallyNonEmptyPaint)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DidCommitAndDrawCompositorFrame,
+ OnCommitAndDrawCompositorFrame)
IPC_MESSAGE_HANDLER(ViewHostMsg_GoToEntryAtOffset, OnGoToEntryAtOffset)
IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateZoomLimits, OnUpdateZoomLimits)
IPC_MESSAGE_HANDLER(ViewHostMsg_PageScaleFactorChanged,
@@ -861,7 +865,6 @@ bool WebContentsImpl::OnMessageReceived(RenderFrameHostImpl* render_frame_host,
OnUnregisterProtocolHandler)
IPC_MESSAGE_HANDLER(FrameHostMsg_UpdatePageImportanceSignals,
OnUpdatePageImportanceSignals)
- IPC_MESSAGE_HANDLER(FrameHostMsg_Find_Reply, OnFindReply)
IPC_MESSAGE_HANDLER(FrameHostMsg_UpdateFaviconURL, OnUpdateFaviconURL)
#if BUILDFLAG(ENABLE_PLUGINS)
IPC_MESSAGE_HANDLER(FrameHostMsg_PepperInstanceCreated,
@@ -1117,10 +1120,10 @@ void WebContentsImpl::RequestAXTreeSnapshot(AXTreeSnapshotCallback callback,
// them into a single tree and call |callback| with that result, then
// delete |combiner|.
FrameTreeNode* root_node = frame_tree_.root();
- AXTreeSnapshotCombiner* combiner =
- new AXTreeSnapshotCombiner(std::move(callback));
+ auto combiner =
+ base::MakeRefCounted<AXTreeSnapshotCombiner>(std::move(callback));
- RecursiveRequestAXTreeSnapshotOnFrame(root_node, combiner, ax_mode);
+ RecursiveRequestAXTreeSnapshotOnFrame(root_node, combiner.get(), ax_mode);
}
void WebContentsImpl::RecursiveRequestAXTreeSnapshotOnFrame(
@@ -1493,6 +1496,8 @@ void WebContentsImpl::SetHasPictureInPictureVideo(
return;
has_picture_in_picture_video_ = has_picture_in_picture_video;
NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
+ for (auto& observer : observers_)
+ observer.MediaPictureInPictureChanged(has_picture_in_picture_video_);
}
bool WebContentsImpl::IsCrashed() const {
@@ -1660,6 +1665,10 @@ bool WebContentsImpl::HasRecentInteractiveInputEvent() const {
return delta <= kMaxInterval;
}
+void WebContentsImpl::SetIgnoreInputEvents(bool ignore_input_events) {
+ ignore_input_events_ = ignore_input_events;
+}
+
#if defined(OS_ANDROID)
void WebContentsImpl::SetMainFrameImportance(
ChildProcessImportance importance) {
@@ -2326,6 +2335,9 @@ void WebContentsImpl::ExitFullscreenMode(bool will_cause_resize) {
observer.DidToggleFullscreenModeForTab(IsFullscreenForCurrentTab(),
will_cause_resize);
}
+
+ if (display_cutout_host_impl_)
+ display_cutout_host_impl_->DidExitFullscreen();
}
void WebContentsImpl::FullscreenStateChanged(RenderFrameHost* rfh,
@@ -2390,6 +2402,9 @@ void WebContentsImpl::FullscreenStateChanged(RenderFrameHost* rfh,
for (auto& observer : observers_)
observer.DidAcquireFullscreen(max_depth_rfh);
+
+ if (display_cutout_host_impl_)
+ display_cutout_host_impl_->DidAcquireFullscreen(max_depth_rfh);
} else if (fullscreen_frame_tree_nodes_.size() == 0) {
current_fullscreen_frame_tree_node_id_ =
RenderFrameHost::kNoFrameTreeNodeId;
@@ -2661,8 +2676,8 @@ void WebContentsImpl::CreateNewWindow(
// FrameTreeNode id instead of the routing id of the Widget for the main
// frame. https://crbug.com/545684
DCHECK_NE(MSG_ROUTING_NONE, main_frame_widget_route_id);
- pending_contents_[std::make_pair(render_process_id,
- main_frame_widget_route_id)] =
+ pending_contents_[GlobalRoutingID(render_process_id,
+ main_frame_widget_route_id)] =
std::move(new_contents);
AddDestructionObserver(raw_new_contents);
}
@@ -2673,20 +2688,17 @@ void WebContentsImpl::CreateNewWindow(
params.target_url, raw_new_contents);
}
- if (opener) {
- for (auto& observer : observers_) {
- observer.DidOpenRequestedURL(raw_new_contents, opener, params.target_url,
- params.referrer, params.disposition,
- ui::PAGE_TRANSITION_LINK,
- false, // started_from_context_menu
- true); // renderer_initiated
- }
+ for (auto& observer : observers_) {
+ observer.DidOpenRequestedURL(raw_new_contents, opener, params.target_url,
+ params.referrer, params.disposition,
+ ui::PAGE_TRANSITION_LINK,
+ false, // started_from_context_menu
+ true); // renderer_initiated
}
// Any new WebContents opened while this WebContents is in fullscreen can be
// used to confuse the user, so drop fullscreen.
- if (IsFullscreenForCurrentTab())
- ExitFullscreen(true);
+ ForSecurityDropFullscreen();
if (params.opener_suppressed) {
// When the opener is suppressed, the original renderer cannot access the
@@ -2767,7 +2779,7 @@ void WebContentsImpl::CreateNewWidget(int32_t render_process_id,
widget_view->SetPopupType(popup_type);
}
// Save the created widget associated with the route so we can show it later.
- pending_widget_views_[std::make_pair(render_process_id, route_id)] =
+ pending_widget_views_[GlobalRoutingID(render_process_id, route_id)] =
widget_view;
}
@@ -2860,7 +2872,7 @@ void WebContentsImpl::ShowCreatedWidget(int process_id,
std::unique_ptr<WebContents> WebContentsImpl::GetCreatedWindow(
int process_id,
int main_frame_widget_route_id) {
- auto key = std::make_pair(process_id, main_frame_widget_route_id);
+ auto key = GlobalRoutingID(process_id, main_frame_widget_route_id);
auto iter = pending_contents_.find(key);
// Certain systems can block the creation of new windows. If we didn't succeed
@@ -2888,14 +2900,14 @@ std::unique_ptr<WebContents> WebContentsImpl::GetCreatedWindow(
RenderWidgetHostView* WebContentsImpl::GetCreatedWidget(int process_id,
int route_id) {
- auto iter = pending_widget_views_.find(std::make_pair(process_id, route_id));
+ auto iter = pending_widget_views_.find(GlobalRoutingID(process_id, route_id));
if (iter == pending_widget_views_.end()) {
DCHECK(false);
return nullptr;
}
RenderWidgetHostView* widget_host_view = iter->second;
- pending_widget_views_.erase(std::make_pair(process_id, route_id));
+ pending_widget_views_.erase(GlobalRoutingID(process_id, route_id));
RenderWidgetHost* widget_host = widget_host_view->GetRenderWidgetHost();
if (!widget_host->GetProcess()->IsInitializedAndNotDead()) {
@@ -2981,6 +2993,13 @@ void WebContentsImpl::AccessibilityLocationChangesReceived(
observer.AccessibilityLocationChangesReceived(details);
}
+base::string16 WebContentsImpl::DumpAccessibilityTree(bool internal) {
+ auto* ax_mgr = GetOrCreateRootBrowserAccessibilityManager();
+ DCHECK(ax_mgr);
+ return AccessibilityTreeFormatter::DumpAccessibilityTreeFromManager(ax_mgr,
+ internal);
+}
+
RenderFrameHost* WebContentsImpl::GetGuestByInstanceID(
RenderFrameHost* render_frame_host,
int browser_plugin_instance_id) {
@@ -3139,9 +3158,10 @@ void WebContentsImpl::SelectRange(const gfx::Point& base,
#if defined(OS_MACOSX)
void WebContentsImpl::DidChangeTextSelection(const base::string16& text,
- const gfx::Range& range) {
+ const gfx::Range& range,
+ size_t offset) {
for (auto& observer : observers_)
- observer.DidChangeTextSelection(text, range);
+ observer.DidChangeTextSelection(text, range, offset);
}
#endif
@@ -3228,10 +3248,10 @@ WebContents* WebContentsImpl::OpenURL(const OpenURLParams& params) {
if (new_contents && source_render_frame_host && new_contents != this) {
for (auto& observer : observers_) {
- observer.DidOpenRequestedURL(new_contents, source_render_frame_host,
- params.url, params.referrer,
- params.disposition, params.transition,
- params.started_from_context_menu, false);
+ observer.DidOpenRequestedURL(
+ new_contents, source_render_frame_host, params.url, params.referrer,
+ params.disposition, params.transition,
+ params.started_from_context_menu, params.is_renderer_initiated);
}
}
@@ -4015,6 +4035,9 @@ void WebContentsImpl::DidStartNavigation(NavigationHandle* navigation_handle) {
"navigation_handle", navigation_handle);
for (auto& observer : observers_)
observer.DidStartNavigation(navigation_handle);
+
+ if (display_cutout_host_impl_)
+ display_cutout_host_impl_->DidStartNavigation(navigation_handle);
}
void WebContentsImpl::DidRedirectNavigation(
@@ -4068,9 +4091,13 @@ void WebContentsImpl::ReadyToCommitNavigation(
if (navigation_handle->IsSameDocument())
return;
- controller_.ssl_manager()->DidStartResourceResponse(
- navigation_handle->GetURL(),
- net::IsCertStatusError(navigation_handle->GetSSLInfo().cert_status));
+ // SSLInfo is not needed on subframe navigations since the main-frame
+ // certificate is the only one that can be inspected (using the info
+ // bubble) without refreshing the page with DevTools open.
+ if (navigation_handle->IsInMainFrame())
+ controller_.ssl_manager()->DidStartResourceResponse(
+ navigation_handle->GetURL(),
+ net::IsCertStatusError(navigation_handle->GetSSLInfo().cert_status));
SetNotWaitingForResponse();
}
@@ -4082,6 +4109,9 @@ void WebContentsImpl::DidFinishNavigation(NavigationHandle* navigation_handle) {
for (auto& observer : observers_)
observer.DidFinishNavigation(navigation_handle);
+ if (display_cutout_host_impl_)
+ display_cutout_host_impl_->DidFinishNavigation(navigation_handle);
+
if (navigation_handle->HasCommitted()) {
BrowserAccessibilityManager* manager =
static_cast<RenderFrameHostImpl*>(
@@ -4338,8 +4368,7 @@ void WebContentsImpl::ViewSource(RenderFrameHostImpl* frame) {
// Any new WebContents opened while this WebContents is in fullscreen can be
// used to confuse the user, so drop fullscreen.
- if (IsFullscreenForCurrentTab())
- ExitFullscreen(true);
+ ForSecurityDropFullscreen();
// We intentionally don't share the SiteInstance with the original frame so
// that view source has a consistent process model and always ends up in a new
@@ -4399,9 +4428,11 @@ void WebContentsImpl::SubresourceResponseStarted(const GURL& url,
void WebContentsImpl::ResourceLoadComplete(
RenderFrameHost* render_frame_host,
+ const GlobalRequestID& request_id,
mojom::ResourceLoadInfoPtr resource_load_info) {
for (auto& observer : observers_) {
- observer.ResourceLoadComplete(render_frame_host, *resource_load_info);
+ observer.ResourceLoadComplete(render_frame_host, request_id,
+ *resource_load_info);
}
}
@@ -4561,22 +4592,6 @@ void WebContentsImpl::OnUpdatePageImportanceSignals(
page_importance_signals_ = signals;
}
-void WebContentsImpl::OnFindReply(RenderFrameHostImpl* source,
- int request_id,
- int number_of_matches,
- const gfx::Rect& selection_rect,
- int active_match_ordinal,
- bool final_update) {
- if (active_match_ordinal > 0)
- SetFocusedFrame(source->frame_tree_node(), source->GetSiteInstance());
-
- // Forward the find reply to the FindRequestManager, along with the
- // RenderFrameHost associated with the frame that the reply came from.
- GetOrCreateFindRequestManager()->OnFindReply(
- source, request_id, number_of_matches, selection_rect,
- active_match_ordinal, final_update);
-}
-
#if defined(OS_ANDROID)
void WebContentsImpl::OnOpenDateTimeDialog(
RenderViewHostImpl* source,
@@ -4753,6 +4768,12 @@ void WebContentsImpl::OnFirstVisuallyNonEmptyPaint(RenderViewHostImpl* source) {
}
}
+void WebContentsImpl::OnCommitAndDrawCompositorFrame(
+ RenderViewHostImpl* source) {
+ for (auto& observer : observers_)
+ observer.DidCommitAndDrawCompositorFrame();
+}
+
void WebContentsImpl::NotifyBeforeFormRepostWarningShow() {
for (auto& observer : observers_)
observer.BeforeFormRepostWarningShow();
@@ -4879,6 +4900,11 @@ void WebContentsImpl::NotifyViewSwapped(RenderViewHost* old_host,
view_->RenderViewHostChanged(old_host, new_host);
+ // If this is an inner WebContents that has swapped views, we need to reattach
+ // it to its outer WebContents.
+ if (node_.outer_web_contents())
+ ReattachToOuterWebContentsFrame();
+
// Ensure that the associated embedder gets cleared after a RenderViewHost
// gets swapped, so we don't reuse the same embedder next time a
// RenderViewHost is attached to this WebContents.
@@ -4974,6 +5000,9 @@ void WebContentsImpl::RenderFrameCreated(RenderFrameHost* render_frame_host) {
observer.RenderFrameCreated(render_frame_host);
UpdateAccessibilityModeOnFrame(render_frame_host);
+ if (display_cutout_host_impl_)
+ display_cutout_host_impl_->RenderFrameCreated(render_frame_host);
+
if (!render_frame_host->IsRenderFrameLive() || render_frame_host->GetParent())
return;
@@ -4994,6 +5023,9 @@ void WebContentsImpl::RenderFrameDeleted(RenderFrameHost* render_frame_host) {
pepper_playback_observer_->RenderFrameDeleted(render_frame_host);
#endif
+ if (display_cutout_host_impl_)
+ display_cutout_host_impl_->RenderFrameDeleted(render_frame_host);
+
// Remove any fullscreen state that the frame has stored.
FullscreenStateChanged(render_frame_host, false /* is_fullscreen */);
}
@@ -5031,8 +5063,7 @@ void WebContentsImpl::RunJavaScriptDialog(RenderFrameHost* render_frame_host,
// Running a dialog causes an exit to webpage-initiated fullscreen.
// http://crbug.com/728276
- if (IsFullscreenForCurrentTab())
- ExitFullscreen(true);
+ ForSecurityDropFullscreen();
auto callback =
base::BindOnce(&WebContentsImpl::OnDialogClosed, base::Unretained(this),
@@ -5101,8 +5132,7 @@ void WebContentsImpl::RunBeforeUnloadConfirm(
// Running a dialog causes an exit to webpage-initiated fullscreen.
// http://crbug.com/728276
- if (IsFullscreenForCurrentTab())
- ExitFullscreen(true);
+ ForSecurityDropFullscreen();
RenderFrameHostImpl* rfhi =
static_cast<RenderFrameHostImpl*>(render_frame_host);
@@ -5150,6 +5180,10 @@ void WebContentsImpl::RunBeforeUnloadConfirm(
void WebContentsImpl::RunFileChooser(RenderFrameHost* render_frame_host,
const FileChooserParams& params) {
+ // Any explicit focusing of another window while this WebContents is in
+ // fullscreen can be used to confuse the user, so drop fullscreen.
+ ForSecurityDropFullscreen();
+
if (delegate_)
delegate_->RunFileChooser(render_frame_host, params);
}
@@ -5684,6 +5718,15 @@ void WebContentsImpl::EnsureOpenerProxiesExist(RenderFrameHost* source_rfh) {
}
}
+void WebContentsImpl::ForSecurityDropFullscreen() {
+ WebContentsImpl* web_contents = this;
+ while (web_contents) {
+ if (web_contents->IsFullscreenForCurrentTab())
+ web_contents->ExitFullscreen(true);
+ web_contents = web_contents->GetOuterWebContents();
+ }
+}
+
void WebContentsImpl::SetAsFocusedWebContentsIfNecessary() {
// Only change focus if we are not currently focused.
WebContentsImpl* old_contents = GetFocusedWebContents();
@@ -5751,8 +5794,7 @@ void WebContentsImpl::SetFocusedFrame(FrameTreeNode* node,
void WebContentsImpl::DidCallFocus() {
// Any explicit focusing of another window while this WebContents is in
// fullscreen can be used to confuse the user, so drop fullscreen.
- if (IsFullscreenForCurrentTab())
- ExitFullscreen(true);
+ ForSecurityDropFullscreen();
}
RenderFrameHost* WebContentsImpl::GetFocusedFrameIncludingInnerWebContents() {
@@ -5848,6 +5890,17 @@ void WebContentsImpl::DidReceiveInputEvent(
SendUserGestureForResourceDispatchHost();
}
+bool WebContentsImpl::ShouldIgnoreInputEvents() {
+ WebContentsImpl* web_contents = this;
+ while (web_contents) {
+ if (web_contents->ignore_input_events_)
+ return true;
+ web_contents = web_contents->GetOuterWebContents();
+ }
+
+ return false;
+}
+
void WebContentsImpl::FocusOwningWebContents(
RenderWidgetHostImpl* render_widget_host) {
// The PDF plugin still runs as a BrowserPlugin and must go through the
@@ -5874,15 +5927,22 @@ void WebContentsImpl::OnIgnoredUIEvent() {
void WebContentsImpl::RendererUnresponsive(
RenderWidgetHostImpl* render_widget_host,
base::RepeatingClosure hang_monitor_restarter) {
- for (auto& observer : observers_)
- observer.OnRendererUnresponsive(render_widget_host->GetProcess());
-
if (ShouldIgnoreUnresponsiveRenderer())
return;
+ // Do not report hangs (to task manager, to hang renderer dialog, etc.) for
+ // invisible tabs (like extension background page, background tabs). See
+ // https://crbug.com/881812 for rationale and for choosing the visibility
+ // (rather than process priority) as the signal here.
+ if (GetVisibility() != Visibility::VISIBLE)
+ return;
+
if (!render_widget_host->renderer_initialized())
return;
+ for (auto& observer : observers_)
+ observer.OnRendererUnresponsive(render_widget_host->GetProcess());
+
if (delegate_)
delegate_->RendererUnresponsive(this, render_widget_host,
std::move(hang_monitor_restarter));
@@ -6105,12 +6165,12 @@ bool WebContentsImpl::GetAllowOtherViews() {
return view_->GetAllowOtherViews();
}
+#endif
+
bool WebContentsImpl::CompletedFirstVisuallyNonEmptyPaint() const {
return did_first_visually_non_empty_paint_;
}
-#endif
-
void WebContentsImpl::OnDidDownloadImage(
ImageDownloadCallback callback,
int id,
@@ -6458,6 +6518,20 @@ int WebContentsImpl::GetCurrentlyPlayingVideoCount() {
return currently_playing_video_count_;
}
+void WebContentsImpl::AudioContextPlaybackStarted(RenderFrameHost* host,
+ int context_id) {
+ WebContentsObserver::AudioContextId audio_context_id(host, context_id);
+ for (auto& observer : observers_)
+ observer.AudioContextPlaybackStarted(audio_context_id);
+}
+
+void WebContentsImpl::AudioContextPlaybackStopped(RenderFrameHost* host,
+ int context_id) {
+ WebContentsObserver::AudioContextId audio_context_id(host, context_id);
+ for (auto& observer : observers_)
+ observer.AudioContextPlaybackStopped(audio_context_id);
+}
+
void WebContentsImpl::UpdateWebContentsVisibility(Visibility visibility) {
// Occlusion is disabled when |features::kWebContentsOcclusion| is disabled
// (for power and speed impact assessment) or when
@@ -6532,11 +6606,6 @@ void WebContentsImpl::FocusedNodeTouched(bool editable) {
#endif
}
-void WebContentsImpl::DidReceiveCompositorFrame() {
- for (auto& observer : observers_)
- observer.DidReceiveCompositorFrame();
-}
-
void WebContentsImpl::ShowInsecureLocalhostWarningIfNeeded() {
bool allow_localhost = base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kAllowInsecureLocalhost);
diff --git a/chromium/content/browser/web_contents/web_contents_impl.h b/chromium/content/browser/web_contents/web_contents_impl.h
index d16a9912277..2687e87ea2d 100644
--- a/chromium/content/browser/web_contents/web_contents_impl.h
+++ b/chromium/content/browser/web_contents/web_contents_impl.h
@@ -41,6 +41,7 @@
#include "content/browser/wake_lock/wake_lock_context_host.h"
#include "content/common/content_export.h"
#include "content/public/browser/color_chooser.h"
+#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/web_contents.h"
@@ -176,10 +177,6 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
// TODO(creis): Remove this now that we can get to it via FrameTreeNode.
RenderFrameHostManager* GetRenderManagerForTesting();
- // Returns guest browser plugin object, or NULL if this WebContents is not a
- // guest.
- BrowserPluginGuest* GetBrowserPluginGuest() const;
-
// Sets a BrowserPluginGuest object for this WebContents. If this WebContents
// has a BrowserPluginGuest then that implies that it is being hosted by
// a BrowserPlugin object in an embedder renderer process.
@@ -229,9 +226,6 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
return screen_orientation_provider_.get();
}
- // Broadcasts the mode change to all frames.
- void SetAccessibilityMode(ui::AXMode mode);
-
// Adds the given accessibility mode to the current accessibility mode
// bitmap.
void AddAccessibilityMode(ui::AXMode mode);
@@ -366,6 +360,7 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
WebContents* outer_web_contents,
RenderFrameHost* outer_contents_frame) override;
WebContentsImpl* GetOuterWebContents() override;
+ WebContentsImpl* GetOutermostWebContents() override;
void DidChangeVisibleSecurityState() override;
void NotifyPreferencesChanged() override;
@@ -459,6 +454,8 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
bool IsShowingContextMenu() const override;
void SetShowingContextMenu(bool showing) override;
void PausePageScheduledTasks(bool paused) override;
+ BrowserPluginGuest* GetBrowserPluginGuest() const override;
+ bool CompletedFirstVisuallyNonEmptyPaint() const override;
#if defined(OS_ANDROID)
base::android::ScopedJavaLocalRef<jobject> GetJavaWebContents() override;
@@ -469,10 +466,10 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
#elif defined(OS_MACOSX)
void SetAllowOtherViews(bool allow) override;
bool GetAllowOtherViews() override;
- bool CompletedFirstVisuallyNonEmptyPaint() const override;
#endif
bool HasRecentInteractiveInputEvent() const override;
+ void SetIgnoreInputEvents(bool ignore_input_events) override;
// Implementation of PageNavigator.
WebContents* OpenURL(const OpenURLParams& params) override;
@@ -519,10 +516,13 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
WebContents* GetAsWebContents() override;
bool IsNeverVisible() override;
ui::AXMode GetAccessibilityMode() const override;
+ // Broadcasts the mode change to all frames.
+ void SetAccessibilityMode(ui::AXMode mode) override;
void AccessibilityEventReceived(
const AXEventNotificationDetails& details) override;
void AccessibilityLocationChangesReceived(
const std::vector<AXLocationChangeNotificationDetails>& details) override;
+ base::string16 DumpAccessibilityTree(bool internal) override;
RenderFrameHost* GetGuestByInstanceID(
RenderFrameHost* render_frame_host,
int browser_plugin_instance_id) override;
@@ -582,7 +582,16 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
net::CertStatus cert_status) override;
void ResourceLoadComplete(
RenderFrameHost* render_frame_host,
+ const GlobalRequestID& request_id,
mojom::ResourceLoadInfoPtr resource_load_information) override;
+
+ // Called when WebAudio starts or stops playing audible audio in an
+ // AudioContext.
+ void AudioContextPlaybackStarted(RenderFrameHost* host,
+ int context_id) override;
+ void AudioContextPlaybackStopped(RenderFrameHost* host,
+ int context_id) override;
+
// RenderViewHostDelegate ----------------------------------------------------
RenderViewHostDelegateView* GetDelegateView() override;
bool OnMessageReceived(RenderViewHostImpl* render_view_host,
@@ -610,6 +619,7 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
BrowserContext* browser_context) const override;
void DidReceiveInputEvent(RenderWidgetHostImpl* render_widget_host,
const blink::WebInputEvent::Type type) override;
+ bool ShouldIgnoreInputEvents() override;
void OnIgnoredUIEvent() override;
void Activate() override;
void UpdatePreferredSize(const gfx::Size& pref_size) override;
@@ -714,7 +724,8 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
void SelectRange(const gfx::Point& base, const gfx::Point& extent) override;
#if defined(OS_MACOSX)
void DidChangeTextSelection(const base::string16& text,
- const gfx::Range& range) override;
+ const gfx::Range& range,
+ size_t offset) override;
#endif
void MoveCaret(const gfx::Point& extent) override;
void AdjustSelectionByCharacterOffset(int start_adjust,
@@ -754,7 +765,6 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
bool IsWidgetForMainFrame(RenderWidgetHostImpl* render_widget_host) override;
bool AddDomainInfoToRapporSample(rappor::Sample* sample) override;
void FocusedNodeTouched(bool editable) override;
- void DidReceiveCompositorFrame() override;
bool IsShowingContextMenuOnPage() const override;
// RenderFrameHostManager::Delegate ------------------------------------------
@@ -925,6 +935,11 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
// |IsFullscreen| must return |true| when this method is called.
bool IsPictureInPictureAllowedForFullscreenVideo() const;
+ // The WebContents is trying to take some action that would cause user
+ // confusion if taken while in fullscreen. If this WebContents or any outer
+ // WebContents is in fullscreen, drop it.
+ void ForSecurityDropFullscreen();
+
// When inner or outer WebContents are present, become the focused
// WebContentsImpl. This will activate this content's main frame RenderWidget
// and indirectly all its subframe widgets. GetFocusedRenderWidgetHost will
@@ -968,6 +983,10 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
void SetDisplayCutoutSafeArea(gfx::Insets insets);
#endif
+ // Notify observers that the viewport fit value changed. This is called by
+ // |DisplayCutoutHostImpl|.
+ void NotifyViewportFitChanged(blink::mojom::ViewportFit value);
+
private:
friend class WebContentsObserver;
friend class WebContents; // To implement factory methods.
@@ -997,6 +1016,8 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
NotifyFullscreenAcquired_Navigate);
FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest,
NotifyFullscreenAcquired_SameOrigin);
+ FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest,
+ FullscreenAfterFrameSwap);
FRIEND_TEST_ALL_PREFIXES(FormStructureBrowserTest, HTMLFiles);
FRIEND_TEST_ALL_PREFIXES(NavigationControllerTest, HistoryNavigate);
FRIEND_TEST_ALL_PREFIXES(RenderFrameHostManagerTest, PageDoesBackAndReload);
@@ -1012,6 +1033,10 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest,
DialogsFromJavaScriptEndFullscreen);
FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest,
+ DialogsFromJavaScriptEndFullscreenEvenInInnerWC);
+ FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest,
+ FileChooserEndsFullscreen);
+ FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest,
PopupsFromJavaScriptEndFullscreen);
FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest,
FocusFromJavaScriptEndsFullscreen);
@@ -1174,12 +1199,6 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
const std::string& protocol,
const GURL& url,
bool user_gesture);
- void OnFindReply(RenderFrameHostImpl* source,
- int request_id,
- int number_of_matches,
- const gfx::Rect& selection_rect,
- int active_match_ordinal,
- bool final_update);
#if defined(OS_ANDROID)
void OnOpenDateTimeDialog(
RenderViewHostImpl* source,
@@ -1223,6 +1242,7 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
void OnUpdateFaviconURL(RenderFrameHostImpl* source,
const std::vector<FaviconURL>& candidates);
void OnFirstVisuallyNonEmptyPaint(RenderViewHostImpl* source);
+ void OnCommitAndDrawCompositorFrame(RenderViewHostImpl* source);
void OnShowValidationMessage(RenderViewHostImpl* source,
const gfx::Rect& anchor_in_root_view,
const base::string16& main_text,
@@ -1251,9 +1271,6 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
// focused WebContents.
bool ContainsOrIsFocusedWebContents();
- // Returns the root of the WebContents tree.
- WebContentsImpl* GetOutermostWebContents();
-
// Walks up the outer WebContents chain and focuses the FrameTreeNode where
// each inner WebContents is attached.
void FocusOuterAttachmentFrameChain();
@@ -1390,10 +1407,6 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
AXTreeSnapshotCombiner* combiner,
ui::AXMode ax_mode);
- // Notify observers that the viewport fit value changed. This is called by
- // |DisplayCutoutHostImpl|.
- void NotifyViewportFitChanged(blink::mojom::ViewportFit value);
-
// Data for core operation ---------------------------------------------------
// Delegate for notifying our owner about stuff. Not owned by us.
@@ -1412,13 +1425,11 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
// Tracks created WebContentsImpl objects that have not been shown yet. They
// are identified by the process ID and routing ID passed to CreateNewWindow.
- typedef std::pair<int, int> ProcessRoutingIdPair;
- std::map<ProcessRoutingIdPair, std::unique_ptr<WebContents>>
- pending_contents_;
+ std::map<GlobalRoutingID, std::unique_ptr<WebContents>> pending_contents_;
// This map holds widgets that were created on behalf of the renderer but
// haven't been shown yet.
- std::map<ProcessRoutingIdPair, RenderWidgetHostView*> pending_widget_views_;
+ std::map<GlobalRoutingID, RenderWidgetHostView*> pending_widget_views_;
std::map<WebContentsImpl*, std::unique_ptr<DestructionObserver>>
destruction_observers_;
@@ -1427,7 +1438,7 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
// This MUST be listed above frame_tree_ since at destruction time the
// latter might cause RenderViewHost's destructor to call us and we might use
// the observer list then.
- base::ObserverList<WebContentsObserver> observers_;
+ base::ObserverList<WebContentsObserver>::Unchecked observers_;
// Associated interface binding sets attached to this WebContents.
std::map<std::string, WebContentsBindingSet*> binding_sets_;
@@ -1547,6 +1558,9 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
// once.
bool notify_disconnection_;
+ // Set to true if we shouldn't send input events.
+ bool ignore_input_events_ = false;
+
// Pointer to the JavaScript dialog manager, lazily assigned. Used because the
// delegate of this WebContentsImpl is nulled before its destructor is called.
JavaScriptDialogManager* dialog_manager_;
diff --git a/chromium/content/browser/web_contents/web_contents_impl_browsertest.cc b/chromium/content/browser/web_contents/web_contents_impl_browsertest.cc
index 4286d9a5c62..78857bccaea 100644
--- a/chromium/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/chromium/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -57,6 +57,7 @@
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/controllable_http_response.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "services/network/public/cpp/features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "url/gurl.h"
@@ -551,8 +552,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
NavigateToURL(shell(), kWebUIUrl);
- bool js_executed = content::ExecuteScript(shell(), kJSCodeForAppendingFrame);
- EXPECT_TRUE(js_executed);
+ EXPECT_TRUE(content::ExecuteScript(shell(), kJSCodeForAppendingFrame));
}
// Observer class to track the creation of RenderFrameHost objects. It is used
@@ -745,6 +745,7 @@ class ResourceLoadObserver : public WebContentsObserver {
// WebContentsObserver implementation:
void ResourceLoadComplete(
content::RenderFrameHost* render_frame_host,
+ const GlobalRequestID& request_id,
const mojom::ResourceLoadInfo& resource_load_info) override {
EXPECT_NE(nullptr, render_frame_host);
resource_load_infos_.push_back(resource_load_info.Clone());
@@ -1557,8 +1558,10 @@ class TestWCDelegateForDialogsAndFullscreen : public JavaScriptDialogManager,
void ExitFullscreenModeForTab(WebContents*) override {
is_fullscreen_ = false;
- if (waiting_for_ == kFullscreenExit)
+ if (waiting_for_ == kFullscreenExit) {
+ waiting_for_ = kNothing;
run_loop_->Quit();
+ }
}
bool IsFullscreenForTabOrPending(
@@ -1574,8 +1577,10 @@ class TestWCDelegateForDialogsAndFullscreen : public JavaScriptDialogManager,
bool* was_blocked) override {
popup_ = std::move(new_contents);
- if (waiting_for_ == kNewContents)
+ if (waiting_for_ == kNewContents) {
+ waiting_for_ = kNothing;
run_loop_->Quit();
+ }
}
// JavaScriptDialogManager
@@ -1590,8 +1595,10 @@ class TestWCDelegateForDialogsAndFullscreen : public JavaScriptDialogManager,
last_message_ = base::UTF16ToUTF8(message_text);
*did_suppress_message = true;
- if (waiting_for_ == kDialog)
+ if (waiting_for_ == kDialog) {
+ waiting_for_ = kNothing;
run_loop_->Quit();
+ }
}
void RunBeforeUnloadDialog(WebContents* web_contents,
@@ -1600,8 +1607,10 @@ class TestWCDelegateForDialogsAndFullscreen : public JavaScriptDialogManager,
DialogClosedCallback callback) override {
std::move(callback).Run(true, base::string16());
- if (waiting_for_ == kDialog)
+ if (waiting_for_ == kDialog) {
+ waiting_for_ = kNothing;
run_loop_->Quit();
+ }
}
bool HandleJavaScriptDialog(WebContents* web_contents,
@@ -1614,7 +1623,12 @@ class TestWCDelegateForDialogsAndFullscreen : public JavaScriptDialogManager,
bool reset_state) override {}
private:
- enum { kDialog, kNewContents, kFullscreenExit } waiting_for_;
+ enum {
+ kNothing,
+ kDialog,
+ kNewContents,
+ kFullscreenExit
+ } waiting_for_ = kNothing;
std::string last_message_;
@@ -2132,6 +2146,68 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
}
IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+ DialogsFromJavaScriptEndFullscreenEvenInInnerWC) {
+ WebContentsImpl* top_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ TestWCDelegateForDialogsAndFullscreen top_test_delegate;
+ top_contents->SetDelegate(&top_test_delegate);
+
+ GURL url("about:blank");
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+
+ FrameTreeNode* root = top_contents->GetFrameTree()->root();
+ ASSERT_EQ(0U, root->child_count());
+
+ std::string script =
+ "var iframe = document.createElement('iframe');"
+ "document.body.appendChild(iframe);";
+ EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+ ASSERT_EQ(1U, root->child_count());
+ RenderFrameHost* frame = root->child_at(0)->current_frame_host();
+ ASSERT_NE(nullptr, frame);
+
+ WebContentsImpl* inner_contents =
+ static_cast<WebContentsImpl*>(CreateAndAttachInnerContents(frame));
+ TestWCDelegateForDialogsAndFullscreen inner_test_delegate;
+ inner_contents->SetDelegate(&inner_test_delegate);
+
+ // A dialog from the inner WebContents should make the outer contents lose
+ // fullscreen.
+ top_contents->EnterFullscreenMode(url, blink::WebFullscreenOptions());
+ EXPECT_TRUE(top_contents->IsFullscreenForCurrentTab());
+ script = "alert('hi')";
+ inner_test_delegate.WillWaitForDialog();
+ EXPECT_TRUE(content::ExecuteScript(inner_contents, script));
+ inner_test_delegate.Wait();
+ EXPECT_FALSE(top_contents->IsFullscreenForCurrentTab());
+
+ inner_contents->SetDelegate(nullptr);
+ inner_contents->SetJavaScriptDialogManagerForTesting(nullptr);
+
+ top_contents->SetDelegate(nullptr);
+ top_contents->SetJavaScriptDialogManagerForTesting(nullptr);
+}
+
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, FileChooserEndsFullscreen) {
+ WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
+ TestWCDelegateForDialogsAndFullscreen test_delegate;
+ wc->SetDelegate(&test_delegate);
+
+ GURL url("about:blank");
+ EXPECT_TRUE(NavigateToURL(shell(), url));
+
+ wc->EnterFullscreenMode(url, blink::WebFullscreenOptions());
+ EXPECT_TRUE(wc->IsFullscreenForCurrentTab());
+ wc->RunFileChooser(wc->GetMainFrame(), FileChooserParams());
+ EXPECT_FALSE(wc->IsFullscreenForCurrentTab());
+
+ wc->SetDelegate(nullptr);
+ wc->SetJavaScriptDialogManagerForTesting(nullptr);
+}
+
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
PopupsFromJavaScriptEndFullscreen) {
WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
TestWCDelegateForDialogsAndFullscreen test_delegate;
@@ -2367,7 +2443,12 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, UpdateLoadState) {
// Wait for the response to be ready, but never finish it.
EXPECT_TRUE(frame_pauser.WaitForResponse());
EXPECT_FALSE(frame_pauser.was_successful());
- waiter.Wait(net::LOAD_STATE_WAITING_FOR_DELEGATE, paused_host);
+ // Note: the pausing only works for the non-network service path because of
+ // http://crbug.com/791049.
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService))
+ waiter.Wait(net::LOAD_STATE_IDLE, base::string16());
+ else
+ waiter.Wait(net::LOAD_STATE_WAITING_FOR_DELEGATE, paused_host);
load_resource(a_frame, "/a_img");
a_response->WaitForRequest();
@@ -2390,10 +2471,12 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, UpdateLoadState) {
waiter.Wait(net::LOAD_STATE_READING_RESPONSE, a_host);
a_response->Done();
- // Now the only request in flight should be the delayed frame.
- waiter.Wait(net::LOAD_STATE_WAITING_FOR_DELEGATE, paused_host);
- frame_pauser.ResumeNavigation();
- waiter.Wait(net::LOAD_STATE_IDLE, base::string16());
+ if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ // Now the only request in flight should be the delayed frame.
+ waiter.Wait(net::LOAD_STATE_WAITING_FOR_DELEGATE, paused_host);
+ frame_pauser.ResumeNavigation();
+ waiter.Wait(net::LOAD_STATE_IDLE, base::string16());
+ }
}
IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, NotifyPreferencesChanged) {
@@ -2630,6 +2713,40 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, NotifyFullscreenAcquired) {
}
}
+// Regression test for https://crbug.com/855018.
+// RenderFrameHostImpls exit fullscreen as soon as they are swapped out.
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, FullscreenAfterFrameSwap) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+
+ GURL url_a = embedded_test_server()->GetURL("a.com", "/title1.html");
+ GURL url_b = embedded_test_server()->GetURL("b.com", "/title1.html");
+
+ // 1) Navigate. There is initially no fullscreen frame.
+ EXPECT_TRUE(NavigateToURL(shell(), url_a));
+ RenderFrameHostImpl* main_frame =
+ static_cast<RenderFrameHostImpl*>(web_contents->GetMainFrame());
+ EXPECT_EQ(0u, web_contents->fullscreen_frame_tree_nodes_.size());
+
+ // 2) Make it fullscreen.
+ FullscreenWebContentsObserver observer(web_contents, main_frame);
+ EXPECT_TRUE(
+ ExecuteScript(main_frame, "document.body.webkitRequestFullscreen();"));
+ observer.Wait();
+ EXPECT_EQ(1u, web_contents->fullscreen_frame_tree_nodes_.size());
+
+ // 3) Navigate cross origin. Act as if the old frame was very slow delivering
+ // the swapout ack and stayed in pending deletion for a while. Even if the
+ // frame is still present, it must be removed from the list of frame in
+ // fullscreen immediately.
+ auto filter = base::MakeRefCounted<SwapoutACKMessageFilter>();
+ main_frame->GetProcess()->AddFilter(filter.get());
+ main_frame->DisableSwapOutTimerForTesting();
+ EXPECT_TRUE(NavigateToURL(shell(), url_b));
+ EXPECT_EQ(0u, web_contents->fullscreen_frame_tree_nodes_.size());
+}
+
IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
NotifyFullscreenAcquired_Navigate) {
ASSERT_TRUE(embedded_test_server()->Start());
@@ -2746,4 +2863,63 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
web_contents->current_fullscreen_frame_tree_node_id_);
}
+class MockDidOpenRequestedURLObserver : public WebContentsObserver {
+ public:
+ explicit MockDidOpenRequestedURLObserver(Shell* shell)
+ : WebContentsObserver(shell->web_contents()) {}
+
+ MOCK_METHOD8(DidOpenRequestedURL,
+ void(WebContents* new_contents,
+ RenderFrameHost* source_render_frame_host,
+ const GURL& url,
+ const Referrer& referrer,
+ WindowOpenDisposition disposition,
+ ui::PageTransition transition,
+ bool started_from_context_menu,
+ bool renderer_initiated));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockDidOpenRequestedURLObserver);
+};
+
+// Test WebContentsObserver::DidOpenRequestedURL for ctrl-click-ed links.
+// This is a regression test for https://crbug.com/864736 (although it also
+// covers slightly more ground than just the |is_renderer_initiated| value).
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, CtrlClickSubframeLink) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+
+ // Load a page with a subframe link.
+ GURL main_url(
+ embedded_test_server()->GetURL("/ctrl-click-subframe-link.html"));
+ NavigateToURL(shell(), main_url);
+
+ // Start intercepting the DidOpenRequestedURL callback.
+ MockDidOpenRequestedURLObserver mock_observer(shell());
+ WebContents* new_web_contents1 = nullptr;
+ RenderFrameHost* subframe = shell()->web_contents()->GetAllFrames()[1];
+ EXPECT_CALL(mock_observer,
+ DidOpenRequestedURL(
+ ::testing::_, // new_contents (captured via SaveArg below)
+ subframe, // source_render_frame_host
+ embedded_test_server()->GetURL("/title1.html"),
+ ::testing::Field(&Referrer::url, main_url),
+ WindowOpenDisposition::NEW_FOREGROUND_TAB,
+ ::testing::Truly([](ui::PageTransition arg) {
+ return ui::PageTransitionCoreTypeIs(
+ arg, ui::PAGE_TRANSITION_LINK);
+ }),
+ false, // started_from_context_menu
+ true)) // is_renderer_initiated
+ .WillOnce(testing::SaveArg<0>(&new_web_contents1));
+
+ // Simulate a ctrl click on the link and ask GMock to verify that the
+ // MockDidOpenRequestedURLObserver got called with the expected args.
+ WebContentsAddedObserver new_web_contents_observer;
+ EXPECT_TRUE(ExecuteScript(
+ shell(), "window.domAutomationController.send(ctrlClickLink());"));
+ WebContents* new_web_contents2 = new_web_contents_observer.GetWebContents();
+ EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(&mock_observer));
+ EXPECT_EQ(new_web_contents1, new_web_contents2);
+}
+
} // namespace content
diff --git a/chromium/content/browser/web_contents/web_contents_impl_unittest.cc b/chromium/content/browser/web_contents/web_contents_impl_unittest.cc
index c403c397331..aa74c714540 100644
--- a/chromium/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/chromium/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -3415,6 +3415,9 @@ class TestOverlayWindow : public OverlayWindow {
void Close() override {}
void Show() override {}
void Hide() override {}
+ void SetPictureInPictureCustomControls(
+ const std::vector<blink::PictureInPictureControlInfo>& controls)
+ override {}
bool IsVisible() const override { return false; }
bool IsAlwaysOnTop() const override { return false; }
ui::Layer* GetLayer() override { return nullptr; }
diff --git a/chromium/content/browser/web_contents/web_contents_user_data_unittest.cc b/chromium/content/browser/web_contents/web_contents_user_data_unittest.cc
index 81b65023bd4..f967c37e3d0 100644
--- a/chromium/content/browser/web_contents/web_contents_user_data_unittest.cc
+++ b/chromium/content/browser/web_contents/web_contents_user_data_unittest.cc
@@ -33,9 +33,6 @@ class WebContentsAttachedClass2
friend class WebContentsUserData<WebContentsAttachedClass2>;
};
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(WebContentsAttachedClass1);
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(WebContentsAttachedClass2);
-
typedef RenderViewHostTestHarness WebContentsUserDataTest;
TEST_F(WebContentsUserDataTest, OneInstanceTwoAttachments) {
diff --git a/chromium/content/browser/web_contents/web_contents_view_android.cc b/chromium/content/browser/web_contents/web_contents_view_android.cc
index 8990bc7bf6c..fe977804cb8 100644
--- a/chromium/content/browser/web_contents/web_contents_view_android.cc
+++ b/chromium/content/browser/web_contents/web_contents_view_android.cc
@@ -107,11 +107,6 @@ void WebContentsViewAndroid::SetContentUiEventHandler(
content_ui_event_handler_ = std::move(handler);
}
-void WebContentsViewAndroid::SetSelectPopup(
- std::unique_ptr<SelectPopup> select_popup) {
- select_popup_ = std::move(select_popup);
-}
-
void WebContentsViewAndroid::SetOverscrollRefreshHandler(
std::unique_ptr<ui::OverscrollRefreshHandler> overscroll_refresh_handler) {
overscroll_refresh_handler_ = std::move(overscroll_refresh_handler);
@@ -323,6 +318,12 @@ void WebContentsViewAndroid::ShowContextMenu(
delegate_->ShowContextMenu(render_frame_host, params);
}
+SelectPopup* WebContentsViewAndroid::GetSelectPopup() {
+ if (!select_popup_)
+ select_popup_ = std::make_unique<SelectPopup>(web_contents_);
+ return select_popup_.get();
+}
+
void WebContentsViewAndroid::ShowPopupMenu(
RenderFrameHost* render_frame_host,
const gfx::Rect& bounds,
@@ -332,15 +333,12 @@ void WebContentsViewAndroid::ShowPopupMenu(
const std::vector<MenuItem>& items,
bool right_aligned,
bool allow_multiple_selection) {
- if (select_popup_) {
- select_popup_->ShowMenu(render_frame_host, bounds, items, selected_item,
- allow_multiple_selection, right_aligned);
- }
+ GetSelectPopup()->ShowMenu(render_frame_host, bounds, items, selected_item,
+ allow_multiple_selection, right_aligned);
}
void WebContentsViewAndroid::HidePopupMenu() {
- if (select_popup_)
- select_popup_->HideMenu();
+ GetSelectPopup()->HideMenu();
}
void WebContentsViewAndroid::StartDragging(
diff --git a/chromium/content/browser/web_contents/web_contents_view_android.h b/chromium/content/browser/web_contents/web_contents_view_android.h
index 088fedea3fa..53d1898347c 100644
--- a/chromium/content/browser/web_contents/web_contents_view_android.h
+++ b/chromium/content/browser/web_contents/web_contents_view_android.h
@@ -38,9 +38,6 @@ class WebContentsViewAndroid : public WebContentsView,
void SetContentUiEventHandler(std::unique_ptr<ContentUiEventHandler> handler);
- // Sets the object that show/hide popup view for <select> tag.
- void SetSelectPopup(std::unique_ptr<SelectPopup> select_popup);
-
void set_synchronous_compositor_client(SynchronousCompositorClient* client) {
synchronous_compositor_client_ = client;
}
@@ -142,6 +139,8 @@ class WebContentsViewAndroid : public WebContentsView,
void OnDragEnded();
void OnSystemDragEnded();
+ SelectPopup* GetSelectPopup();
+
// The WebContents whose contents we display.
WebContentsImpl* web_contents_;
diff --git a/chromium/content/browser/web_contents/web_contents_view_aura.cc b/chromium/content/browser/web_contents/web_contents_view_aura.cc
index 713b17948ef..e471459007a 100644
--- a/chromium/content/browser/web_contents/web_contents_view_aura.cc
+++ b/chromium/content/browser/web_contents/web_contents_view_aura.cc
@@ -350,6 +350,26 @@ GlobalRoutingID GetRenderViewHostID(RenderViewHost* rvh) {
return GlobalRoutingID(rvh->GetProcess()->GetID(), rvh->GetRoutingID());
}
+// Returns the host window for |window|, or nullpr if it has no host window.
+aura::Window* GetHostWindow(aura::Window* window) {
+ aura::Window* host_window = window->GetProperty(aura::client::kHostWindowKey);
+ if (host_window)
+ return host_window;
+ return window->parent();
+}
+
+// Returns true iff the aura::client::kMirroringEnabledKey property is set for
+// |window| or its parent. That indicates that |window| is being displayed in
+// Alt-Tab view on ChromeOS.
+bool WindowIsMirrored(aura::Window* window) {
+ if (window->GetProperty(aura::client::kMirroringEnabledKey))
+ return true;
+
+ aura::Window* const host_window = GetHostWindow(window);
+ return host_window &&
+ host_window->GetProperty(aura::client::kMirroringEnabledKey);
+}
+
} // namespace
class WebContentsViewAura::WindowObserver
@@ -373,10 +393,7 @@ class WebContentsViewAura::WindowObserver
if (window != view_->window_.get())
return;
- aura::Window* host_window =
- window->GetProperty(aura::client::kHostWindowKey);
- if (!host_window)
- host_window = parent;
+ aura::Window* const host_window = GetHostWindow(window);
if (host_window_)
host_window_->RemoveObserver(this);
@@ -422,12 +439,8 @@ class WebContentsViewAura::WindowObserver
void OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old) override {
- if (key != aura::client::kMirroringEnabledKey)
- return;
- if (window->GetProperty(aura::client::kMirroringEnabledKey))
- view_->web_contents_->IncrementCapturerCount(gfx::Size());
- else
- view_->web_contents_->DecrementCapturerCount();
+ if (key == aura::client::kMirroringEnabledKey)
+ view_->UpdateWebContentsVisibility();
}
// Overridden WindowTreeHostObserver:
@@ -467,7 +480,7 @@ WebContentsViewAura::WebContentsViewAura(WebContentsImpl* web_contents,
WebContentsViewDelegate* delegate)
: is_mus_browser_plugin_guest_(web_contents->GetBrowserPluginGuest() !=
nullptr &&
- !features::IsAshInBrowserProcess()),
+ features::IsUsingWindowService()),
web_contents_(web_contents),
delegate_(delegate),
current_drag_op_(blink::kWebDragOperationNone),
@@ -729,7 +742,7 @@ gfx::Rect WebContentsViewAura::GetViewBounds() const {
}
void WebContentsViewAura::CreateAuraWindow(aura::Window* context) {
- DCHECK(aura::Env::GetInstanceDontCreate());
+ DCHECK(aura::Env::HasInstance());
DCHECK(!window_);
window_ = std::make_unique<aura::Window>(this);
window_->set_owned_by_parent(false);
@@ -761,6 +774,23 @@ void WebContentsViewAura::CreateAuraWindow(aura::Window* context) {
window_observer_.reset(new WindowObserver(this));
}
+void WebContentsViewAura::UpdateWebContentsVisibility() {
+ web_contents_->UpdateWebContentsVisibility(GetVisibility());
+}
+
+Visibility WebContentsViewAura::GetVisibility() const {
+ if (window_->occlusion_state() == aura::Window::OcclusionState::VISIBLE ||
+ WindowIsMirrored(window_.get())) {
+ return Visibility::VISIBLE;
+ }
+
+ if (window_->occlusion_state() == aura::Window::OcclusionState::OCCLUDED)
+ return Visibility::OCCLUDED;
+
+ DCHECK_EQ(window_->occlusion_state(), aura::Window::OcclusionState::HIDDEN);
+ return Visibility::HIDDEN;
+}
+
////////////////////////////////////////////////////////////////////////////////
// WebContentsViewAura, WebContentsView implementation:
@@ -1100,12 +1130,7 @@ void WebContentsViewAura::OnWindowTargetVisibilityChanged(bool visible) {
void WebContentsViewAura::OnWindowOcclusionChanged(
aura::Window::OcclusionState occlusion_state) {
- web_contents_->UpdateWebContentsVisibility(
- occlusion_state == aura::Window::OcclusionState::VISIBLE
- ? content::Visibility::VISIBLE
- : (occlusion_state == aura::Window::OcclusionState::OCCLUDED
- ? content::Visibility::OCCLUDED
- : content::Visibility::HIDDEN));
+ UpdateWebContentsVisibility();
}
bool WebContentsViewAura::HasHitTestMask() const {
diff --git a/chromium/content/browser/web_contents/web_contents_view_aura.h b/chromium/content/browser/web_contents/web_contents_view_aura.h
index 058f3e00d6f..212da86e253 100644
--- a/chromium/content/browser/web_contents/web_contents_view_aura.h
+++ b/chromium/content/browser/web_contents/web_contents_view_aura.h
@@ -12,12 +12,13 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
-#include "content/browser/loader/global_routing_id.h"
#include "content/browser/renderer_host/overscroll_controller_delegate.h"
#include "content/browser/renderer_host/render_view_host_delegate_view.h"
#include "content/browser/web_contents/web_contents_view.h"
#include "content/common/buildflags.h"
#include "content/common/content_export.h"
+#include "content/public/browser/global_routing_id.h"
+#include "content/public/browser/visibility.h"
#include "ui/aura/client/drag_drop_delegate.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
@@ -97,6 +98,12 @@ class CONTENT_EXPORT WebContentsViewAura
// Called from CreateView() to create |window_|.
void CreateAuraWindow(aura::Window* context);
+ // Computes the view's visibility updates the WebContents accordingly.
+ void UpdateWebContentsVisibility();
+
+ // Computes the view's visibility.
+ Visibility GetVisibility() const;
+
// Overridden from WebContentsView:
gfx::NativeView GetNativeView() const override;
gfx::NativeView GetContentNativeView() const override;
diff --git a/chromium/content/browser/web_contents/web_contents_view_aura_unittest.cc b/chromium/content/browser/web_contents/web_contents_view_aura_unittest.cc
index 03d3de9320f..2982638ad0a 100644
--- a/chromium/content/browser/web_contents/web_contents_view_aura_unittest.cc
+++ b/chromium/content/browser/web_contents/web_contents_view_aura_unittest.cc
@@ -7,12 +7,14 @@
#include <memory>
#include "base/command_line.h"
+#include "base/macros.h"
#include "base/test/scoped_command_line.h"
#include "base/test/scoped_feature_list.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/common/content_features.h"
#include "content/public/test/test_renderer_host.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/client/aura_constants.h"
#include "ui/aura/test/test_windows.h"
#include "ui/aura/window.h"
#include "ui/display/display_switches.h"
@@ -25,22 +27,39 @@ constexpr gfx::Rect kBounds = gfx::Rect(0, 0, 20, 20);
} // namespace
class WebContentsViewAuraTest : public RenderViewHostTestHarness {
- public:
+ protected:
WebContentsViewAuraTest() = default;
~WebContentsViewAuraTest() override = default;
void SetUp() override {
RenderViewHostTestHarness::SetUp();
root_window()->SetBounds(kBounds);
- web_contents()->GetNativeView()->SetBounds(kBounds);
- web_contents()->GetNativeView()->Show();
- root_window()->AddChild(web_contents()->GetNativeView());
+ GetNativeView()->SetBounds(kBounds);
+ GetNativeView()->Show();
+ root_window()->AddChild(GetNativeView());
+
+ occluding_window_.reset(aura::test::CreateTestWindowWithDelegateAndType(
+ nullptr, aura::client::WINDOW_TYPE_NORMAL, 0, kBounds, root_window(),
+ false));
+ }
+
+ void TearDown() override {
+ occluding_window_.reset();
+ RenderViewHostTestHarness::TearDown();
}
WebContentsViewAura* view() {
WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents());
return static_cast<WebContentsViewAura*>(contents->GetView());
}
+
+ aura::Window* GetNativeView() { return web_contents()->GetNativeView(); }
+
+ // |occluding_window_| occludes |web_contents()| when it's shown.
+ std::unique_ptr<aura::Window> occluding_window_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WebContentsViewAuraTest);
};
TEST_F(WebContentsViewAuraTest, EnableDisableOverscroll) {
@@ -63,17 +82,122 @@ TEST_F(WebContentsViewAuraTest, OccludeView) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kWebContentsOcclusion);
- // |other_window| occludes |web_contents()| when it's shown.
- std::unique_ptr<aura::Window> other_window(
+ EXPECT_EQ(web_contents()->GetVisibility(), Visibility::VISIBLE);
+ occluding_window_->Show();
+ EXPECT_EQ(web_contents()->GetVisibility(), Visibility::OCCLUDED);
+ occluding_window_->Hide();
+ EXPECT_EQ(web_contents()->GetVisibility(), Visibility::VISIBLE);
+}
+
+TEST_F(WebContentsViewAuraTest, MirroringEnabledForHiddenView) {
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
+ root_window()->Hide();
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::HIDDEN);
+ GetNativeView()->SetProperty(aura::client::kMirroringEnabledKey, true);
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
+ GetNativeView()->SetProperty(aura::client::kMirroringEnabledKey, false);
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::HIDDEN);
+ root_window()->Show();
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
+ GetNativeView()->SetProperty(aura::client::kMirroringEnabledKey, true);
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
+ GetNativeView()->SetProperty(aura::client::kMirroringEnabledKey, false);
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
+}
+
+TEST_F(WebContentsViewAuraTest, MirroringEnabledForOccludedView) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(features::kWebContentsOcclusion);
+
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
+ occluding_window_->Show();
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::OCCLUDED);
+ GetNativeView()->SetProperty(aura::client::kMirroringEnabledKey, true);
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
+ GetNativeView()->SetProperty(aura::client::kMirroringEnabledKey, false);
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::OCCLUDED);
+}
+
+TEST_F(WebContentsViewAuraTest, MirroringEnabledForHiddenViewParent) {
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
+ root_window()->Hide();
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::HIDDEN);
+ root_window()->SetProperty(aura::client::kMirroringEnabledKey, true);
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
+ root_window()->SetProperty(aura::client::kMirroringEnabledKey, false);
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::HIDDEN);
+ root_window()->Show();
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
+ root_window()->SetProperty(aura::client::kMirroringEnabledKey, true);
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
+ root_window()->SetProperty(aura::client::kMirroringEnabledKey, false);
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
+}
+
+TEST_F(WebContentsViewAuraTest, MirroringEnabledForOccludedViewParent) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(features::kWebContentsOcclusion);
+
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
+ occluding_window_->Show();
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::OCCLUDED);
+ root_window()->SetProperty(aura::client::kMirroringEnabledKey, true);
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
+ root_window()->SetProperty(aura::client::kMirroringEnabledKey, false);
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::OCCLUDED);
+}
+
+TEST_F(WebContentsViewAuraTest, MirroringEnabledForHiddenViewHost) {
+ // Make root_window() the host of GetNativeView(), and introduce an
+ // |intermediate_window| in the hierarchy between root_window() and
+ // GetNativeView().
+ std::unique_ptr<aura::Window> intermediate_window(
aura::test::CreateTestWindowWithDelegateAndType(
nullptr, aura::client::WINDOW_TYPE_NORMAL, 0, kBounds, root_window(),
false));
+ GetNativeView()->SetProperty(aura::client::kHostWindowKey, root_window());
+ intermediate_window->AddChild(GetNativeView());
+ root_window()->StackChildAtBottom(intermediate_window.get());
+ intermediate_window->Show();
- EXPECT_EQ(web_contents()->GetVisibility(), Visibility::VISIBLE);
- other_window->Show();
- EXPECT_EQ(web_contents()->GetVisibility(), Visibility::OCCLUDED);
- other_window->Hide();
- EXPECT_EQ(web_contents()->GetVisibility(), Visibility::VISIBLE);
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
+ root_window()->Hide();
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::HIDDEN);
+ root_window()->SetProperty(aura::client::kMirroringEnabledKey, true);
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
+ root_window()->SetProperty(aura::client::kMirroringEnabledKey, false);
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::HIDDEN);
+ root_window()->Show();
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
+ root_window()->SetProperty(aura::client::kMirroringEnabledKey, true);
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
+ root_window()->SetProperty(aura::client::kMirroringEnabledKey, false);
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
+}
+
+TEST_F(WebContentsViewAuraTest, MirroringEnabledForOccludedViewHost) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(features::kWebContentsOcclusion);
+
+ // Make root_window() the host of GetNativeView(), and introduce an
+ // |intermediate_window| in the hierarchy between root_window() and
+ // GetNativeView().
+ std::unique_ptr<aura::Window> intermediate_window(
+ aura::test::CreateTestWindowWithDelegateAndType(
+ nullptr, aura::client::WINDOW_TYPE_NORMAL, 0, kBounds, root_window(),
+ false));
+ GetNativeView()->SetProperty(aura::client::kHostWindowKey, root_window());
+ intermediate_window->AddChild(GetNativeView());
+ root_window()->StackChildAtBottom(intermediate_window.get());
+ intermediate_window->Show();
+
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
+ occluding_window_->Show();
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::OCCLUDED);
+ root_window()->SetProperty(aura::client::kMirroringEnabledKey, true);
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE);
+ root_window()->SetProperty(aura::client::kMirroringEnabledKey, false);
+ EXPECT_EQ(web_contents()->GetVisibility(), content::Visibility::OCCLUDED);
}
} // namespace content
diff --git a/chromium/content/browser/web_contents/web_contents_view_guest.cc b/chromium/content/browser/web_contents/web_contents_view_guest.cc
index 44c68ed25b6..12f6817499e 100644
--- a/chromium/content/browser/web_contents/web_contents_view_guest.cc
+++ b/chromium/content/browser/web_contents/web_contents_view_guest.cc
@@ -72,14 +72,14 @@ void WebContentsViewGuest::OnGuestAttached(WebContentsView* parent_view) {
// view hierarchy. We add this view as embedder's child here.
// This would go in WebContentsViewGuest::CreateView, but that is too early to
// access embedder_web_contents(). Therefore, we do it here.
- if (features::IsAshInBrowserProcess())
+ if (!features::IsUsingWindowService())
parent_view->GetNativeView()->AddChild(platform_view_->GetNativeView());
#endif // defined(USE_AURA)
}
void WebContentsViewGuest::OnGuestDetached(WebContentsView* old_parent_view) {
#if defined(USE_AURA)
- if (features::IsAshInBrowserProcess()) {
+ if (!features::IsUsingWindowService()) {
old_parent_view->GetNativeView()->RemoveChild(
platform_view_->GetNativeView());
}
diff --git a/chromium/content/browser/web_contents/web_contents_view_overscroll_animator_mac.h b/chromium/content/browser/web_contents/web_contents_view_overscroll_animator_mac.h
deleted file mode 100644
index 0603a9b99e3..00000000000
--- a/chromium/content/browser/web_contents/web_contents_view_overscroll_animator_mac.h
+++ /dev/null
@@ -1,61 +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 CONTENT_BROWSER_WEB_CONTENTS_WEB_CONTENTS_VIEW_OVERSCROLL_ANIMATOR_MAC_H_
-#define CONTENT_BROWSER_WEB_CONTENTS_WEB_CONTENTS_VIEW_OVERSCROLL_ANIMATOR_MAC_H_
-
-#import <Cocoa/Cocoa.h>
-
-namespace content {
-class WebContentsImpl;
-
-// The direction of the overscroll animations. Backwards means that the user
-// wants to navigate backwards in the navigation history. The opposite applies
-// to forwards.
-enum OverscrollAnimatorDirection {
- OVERSCROLL_ANIMATOR_DIRECTION_BACKWARDS,
- OVERSCROLL_ANIMATOR_DIRECTION_FORWARDS,
-};
-} // namespace content
-
-// NSViews that intend to manage the animation associated with an overscroll
-// must implement this protocol.
-@protocol WebContentsOverscrollAnimator
-// Some implementations require the WebContentsView to supply a snapshot of a
-// previous navigation state. This method determines whether the snapshot passed
-// to the overscroll animator is expected to be non-nil.
-- (BOOL)needsNavigationSnapshot;
-
-// Begin an overscroll animation. The method -needsNavigationSnapshot determines
-// whether |snapshot| can be nil.
-- (void)beginOverscrollInDirection:
- (content::OverscrollAnimatorDirection)direction
- navigationSnapshot:(NSImage*)snapshot;
-
-// Due to the nature of some of the overscroll animations, implementators of
-// this protocol must have control over the layout of the RenderWidgetHost's
-// NativeView. When there is no overscroll animation in progress, the
-// implementor must guarantee that the frame of the RenderWidgetHost's
-// NativeView in screen coordinates is the same as its own frame in screen
-// coordinates.
-// Due to the odd ownership cycles of the RenderWidgetHost's NativeView, it is
-// important that its presence in the NSView hierarchy is the only strong
-// reference, and that when it gets removed from the NSView hierarchy, it will
-// be dealloc'ed shortly thereafter.
-- (void)addRenderWidgetHostNativeView:(NSView*)view;
-
-// During an overscroll animation, |progress| ranges from 0 to 2, and indicates
-// how close the overscroll is to completing. If the overscroll ends with
-// |progress| >= 1, then the overscroll is considered completed.
-- (void)updateOverscrollProgress:(CGFloat)progress;
-
-// Animate the finish of the overscroll and perform a navigation. The navigation
-// may not happen synchronously, but is guaranteed to eventually occur.
-- (void)completeOverscroll:(content::WebContentsImpl*)webContents;
-
-// Animate the cancellation of the overscroll.
-- (void)cancelOverscroll;
-@end
-
-#endif // CONTENT_BROWSER_WEB_CONTENTS_WEB_CONTENTS_VIEW_OVERSCROLL_ANIMATOR_MAC_H_
diff --git a/chromium/content/browser/web_contents/web_contents_view_overscroll_animator_slider_mac.h b/chromium/content/browser/web_contents/web_contents_view_overscroll_animator_slider_mac.h
deleted file mode 100644
index 326c868b41c..00000000000
--- a/chromium/content/browser/web_contents/web_contents_view_overscroll_animator_slider_mac.h
+++ /dev/null
@@ -1,60 +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 CONTENT_BROWSER_WEB_CONTENTS_WEB_CONTENTS_VIEW_OVERSCROLL_ANIMATOR_SLIDER_MAC_H_
-#define CONTENT_BROWSER_WEB_CONTENTS_WEB_CONTENTS_VIEW_OVERSCROLL_ANIMATOR_SLIDER_MAC_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include <memory>
-
-#include "base/mac/scoped_nsobject.h"
-#include "content/browser/web_contents/web_contents_view_overscroll_animator_mac.h"
-
-namespace overscroll_animator {
-class WebContentsPaintObserver;
-} // namespace overscroll_animator
-
-@interface OverscrollAnimatorSliderView
- : NSView<WebContentsOverscrollAnimator> {
- // This container view holds the RenderWidgetHost's NativeViews. Most of the
- // time, its frame in screen coordinates is the same as SliderView's frame in
- // screen coordinates. During an overscroll animation, it may temporarily be
- // relocated, but it will return to its original position after the overscroll
- // animation is finished.
- base::scoped_nsobject<NSView> middleView_;
-
- // This view is a sibling of middleView_, and is guaranteed to live below it.
- // Most of the time, it is hidden. During a backwards overscroll animation,
- // middleView_ is slid to the right, and bottomView_ peeks out from the
- // original position of middleView_.
- base::scoped_nsobject<NSImageView> bottomView_;
-
- // This view is a sibling of middleView_, and is guaranteed to live above it.
- // Most of the time, it is hidden. During a forwards overscroll animation,
- // topView_ is slid to the left from off screen, its final position exactly
- // covering middleView_.
- base::scoped_nsobject<NSImageView> topView_;
-
- // The direction of the current overscroll animation. This property has no
- // meaning when inOverscroll_ is false.
- content::OverscrollAnimatorDirection direction_;
-
- // Indicates that this view is completing or cancelling the overscroll. This
- // animation cannot be cancelled.
- BOOL animating_;
-
- // Reflects whether this view is in the process of handling an overscroll.
- BOOL inOverscroll_;
-
- // The most recent value passed to -updateOverscrollProgress:.
- CGFloat progress_;
-
- // An observer that reports the first non-empty paint of a WebContents. This
- // is used when completing an overscroll animation.
- std::unique_ptr<overscroll_animator::WebContentsPaintObserver> observer_;
-}
-@end
-
-#endif // CONTENT_BROWSER_WEB_CONTENTS_WEB_CONTENTS_VIEW_OVERSCROLL_ANIMATOR_SLIDER_MAC_H_
diff --git a/chromium/content/browser/web_contents/web_contents_view_overscroll_animator_slider_mac.mm b/chromium/content/browser/web_contents/web_contents_view_overscroll_animator_slider_mac.mm
deleted file mode 100644
index b614fb13dea..00000000000
--- a/chromium/content/browser/web_contents/web_contents_view_overscroll_animator_slider_mac.mm
+++ /dev/null
@@ -1,259 +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.
-
-#import <QuartzCore/QuartzCore.h>
-
-#include "content/browser/web_contents/web_contents_view_overscroll_animator_slider_mac.h"
-
-#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/public/browser/web_contents_observer.h"
-
-namespace {
-// The minimum possible progress of an overscroll animation.
-CGFloat kMinProgress = 0;
-// The maximum possible progress of an overscroll animation.
-CGFloat kMaxProgress = 2.0;
-// The maximum duration of the completion or cancellation animations. The
-// effective maximum is half of this value, since the longest animation is from
-// progress = 1.0 to progress = 2.0;
-CGFloat kMaxAnimationDuration = 0.2;
-} // namespace
-
-// OverscrollAnimatorSliderView Private Category -------------------------------
-
-@interface OverscrollAnimatorSliderView ()
-// Callback from WebContentsPaintObserver.
-- (void)webContentsFinishedNonEmptyPaint;
-
-// Resets overscroll animation state.
-- (void)reset;
-
-// Given a |progress| from 0 to 2, the expected frame origin of the -movingView.
-- (NSPoint)frameOriginWithProgress:(CGFloat)progress;
-
-// The NSView that is moving during the overscroll animation.
-- (NSView*)movingView;
-
-// The expected duration of an animation from progress_ to |progress|
-- (CGFloat)animationDurationForProgress:(CGFloat)progress;
-
-// NSView override. During an overscroll animation, the cursor may no longer
-// rest on the RenderWidgetHost's NativeView, which prevents wheel events from
-// reaching the NativeView. The overscroll animation is driven by wheel events
-// so they must be explicitly forwarded to the NativeView.
-- (void)scrollWheel:(NSEvent*)event;
-@end
-
-// Helper Class (ResizingView) -------------------------------------------------
-
-// This NSView subclass is intended to be the RenderWidgetHost's NativeView's
-// parent NSView. It is possible for the RenderWidgetHost's NativeView's size to
-// become out of sync with its parent NSView. The override of
-// -resizeSubviewsWithOldSize: ensures that the sizes will eventually become
-// consistent.
-// http://crbug.com/264207
-@interface ResizingView : NSView
-@end
-
-@implementation ResizingView
-- (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize {
- for (NSView* subview in self.subviews)
- [subview setFrame:self.bounds];
-}
-@end
-
-// Helper Class (WebContentsPaintObserver) -------------------------------------
-
-namespace overscroll_animator {
-class WebContentsPaintObserver : public content::WebContentsObserver {
- public:
- WebContentsPaintObserver(content::WebContents* web_contents,
- OverscrollAnimatorSliderView* slider_view)
- : WebContentsObserver(web_contents), slider_view_(slider_view) {}
-
- void DidFirstVisuallyNonEmptyPaint() override {
- [slider_view_ webContentsFinishedNonEmptyPaint];
- }
-
- private:
- OverscrollAnimatorSliderView* slider_view_; // Weak reference.
-};
-} // namespace overscroll_animator
-
-// OverscrollAnimatorSliderView Implementation ---------------------------------
-
-@implementation OverscrollAnimatorSliderView
-
-- (instancetype)initWithFrame:(NSRect)frame {
- self = [super initWithFrame:frame];
- if (self) {
- bottomView_.reset([[NSImageView alloc] initWithFrame:self.bounds]);
- bottomView_.get().imageScaling = NSImageScaleNone;
- bottomView_.get().autoresizingMask =
- NSViewWidthSizable | NSViewHeightSizable;
- bottomView_.get().imageAlignment = NSImageAlignTop;
- [self addSubview:bottomView_];
- middleView_.reset([[ResizingView alloc] initWithFrame:self.bounds]);
- middleView_.get().autoresizingMask =
- NSViewWidthSizable | NSViewHeightSizable;
- [self addSubview:middleView_];
- topView_.reset([[NSImageView alloc] initWithFrame:self.bounds]);
- topView_.get().autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
- topView_.get().imageScaling = NSImageScaleNone;
- topView_.get().imageAlignment = NSImageAlignTop;
- [self addSubview:topView_];
-
- [self reset];
- }
- return self;
-}
-
-- (void)webContentsFinishedNonEmptyPaint {
- observer_.reset();
- [self reset];
-}
-
-- (void)reset {
- DCHECK(!animating_);
- inOverscroll_ = NO;
- progress_ = kMinProgress;
-
- [CATransaction begin];
- [CATransaction setDisableActions:YES];
- bottomView_.get().hidden = YES;
- middleView_.get().hidden = NO;
- topView_.get().hidden = YES;
-
- [bottomView_ setFrameOrigin:NSMakePoint(0, 0)];
- [middleView_ setFrameOrigin:NSMakePoint(0, 0)];
- [topView_ setFrameOrigin:NSMakePoint(0, 0)];
- [CATransaction commit];
-}
-
-- (NSPoint)frameOriginWithProgress:(CGFloat)progress {
- if (direction_ == content::OVERSCROLL_ANIMATOR_DIRECTION_BACKWARDS)
- return NSMakePoint(progress / kMaxProgress * self.bounds.size.width, 0);
- return NSMakePoint((1 - progress / kMaxProgress) * self.bounds.size.width, 0);
-}
-
-- (NSView*)movingView {
- if (direction_ == content::OVERSCROLL_ANIMATOR_DIRECTION_BACKWARDS)
- return middleView_;
- return topView_;
-}
-
-- (CGFloat)animationDurationForProgress:(CGFloat)progress {
- CGFloat progressPercentage =
- fabs(progress_ - progress) / (kMaxProgress - kMinProgress);
- return progressPercentage * kMaxAnimationDuration;
-}
-
-- (void)scrollWheel:(NSEvent*)event {
- NSView* latestRenderWidgetHostView = [[middleView_ subviews] lastObject];
- [latestRenderWidgetHostView scrollWheel:event];
-}
-
-// WebContentsOverscrollAnimator Implementation --------------------------------
-
-- (BOOL)needsNavigationSnapshot {
- return YES;
-}
-
-- (void)beginOverscrollInDirection:
- (content::OverscrollAnimatorDirection)direction
- navigationSnapshot:(NSImage*)snapshot {
- // TODO(erikchen): If snapshot is nil, need a placeholder.
- if (animating_ || inOverscroll_)
- return;
-
- inOverscroll_ = YES;
- direction_ = direction;
- if (direction_ == content::OVERSCROLL_ANIMATOR_DIRECTION_BACKWARDS) {
- // The middleView_ will slide to the right, revealing bottomView_.
- bottomView_.get().hidden = NO;
- [bottomView_ setImage:snapshot];
- } else {
- // The topView_ will slide in from the right, concealing middleView_.
- topView_.get().hidden = NO;
- [topView_ setFrameOrigin:NSMakePoint(self.bounds.size.width, 0)];
- [topView_ setImage:snapshot];
- }
-
- [self updateOverscrollProgress:kMinProgress];
-}
-
-- (void)addRenderWidgetHostNativeView:(NSView*)view {
- [middleView_ addSubview:view];
-}
-
-- (void)updateOverscrollProgress:(CGFloat)progress {
- if (animating_)
- return;
- DCHECK_LE(progress, kMaxProgress);
- DCHECK_GE(progress, kMinProgress);
- progress_ = progress;
- [[self movingView] setFrameOrigin:[self frameOriginWithProgress:progress]];
-}
-
-- (void)completeOverscroll:(content::WebContentsImpl*)webContents {
- if (animating_ || !inOverscroll_)
- return;
-
- animating_ = YES;
-
- NSView* view = [self movingView];
- [NSAnimationContext beginGrouping];
- [NSAnimationContext currentContext].duration =
- [self animationDurationForProgress:kMaxProgress];
- [[NSAnimationContext currentContext] setCompletionHandler:^{
- animating_ = NO;
-
- // Animation is complete. Now perform page load.
- if (direction_ == content::OVERSCROLL_ANIMATOR_DIRECTION_BACKWARDS)
- webContents->GetController().GoBack();
- else
- webContents->GetController().GoForward();
-
- // Reset the position of the middleView_, but wait for the page to paint
- // before showing it.
- middleView_.get().hidden = YES;
- [middleView_ setFrameOrigin:NSMakePoint(0, 0)];
- observer_.reset(
- new overscroll_animator::WebContentsPaintObserver(webContents, self));
- }];
-
- // Animate the moving view to its final position.
- [[view animator] setFrameOrigin:[self frameOriginWithProgress:kMaxProgress]];
-
- [NSAnimationContext endGrouping];
-}
-
-- (void)cancelOverscroll {
- if (animating_)
- return;
-
- if (!inOverscroll_) {
- [self reset];
- return;
- }
-
- animating_ = YES;
-
- NSView* view = [self movingView];
- [NSAnimationContext beginGrouping];
- [NSAnimationContext currentContext].duration =
- [self animationDurationForProgress:kMinProgress];
- [[NSAnimationContext currentContext] setCompletionHandler:^{
- // Animation is complete. Reset the state.
- animating_ = NO;
- [self reset];
- }];
-
- // Animate the moving view to its initial position.
- [[view animator] setFrameOrigin:[self frameOriginWithProgress:kMinProgress]];
-
- [NSAnimationContext endGrouping];
-}
-
-@end
diff --git a/chromium/content/browser/web_contents/web_drag_dest_mac.h b/chromium/content/browser/web_contents/web_drag_dest_mac.h
index c81c2a89ab8..6d6ae69232f 100644
--- a/chromium/content/browser/web_contents/web_drag_dest_mac.h
+++ b/chromium/content/browser/web_contents/web_drag_dest_mac.h
@@ -10,8 +10,8 @@
#include <memory>
#include "base/strings/string16.h"
-#include "content/browser/loader/global_routing_id.h"
#include "content/common/content_export.h"
+#include "content/public/browser/global_routing_id.h"
#include "content/public/common/drop_data.h"
#include "ui/gfx/geometry/point_f.h"
diff --git a/chromium/content/browser/web_contents/web_drag_source_mac.mm b/chromium/content/browser/web_contents/web_drag_source_mac.mm
index 4ef9fcdda1c..1ebcedb0875 100644
--- a/chromium/content/browser/web_contents/web_drag_source_mac.mm
+++ b/chromium/content/browser/web_contents/web_drag_source_mac.mm
@@ -16,7 +16,7 @@
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "content/browser/download/drag_download_file.h"
@@ -145,8 +145,9 @@ void PromiseWriterHelper(const DropData& drop_data,
// If NSURL creation failed, check for a badly-escaped JavaScript URL.
// Strip out any existing escapes and then re-escape uniformly.
if (!url && dropData_->url.SchemeIs(url::kJavaScriptScheme)) {
- std::string unescapedUrlString =
- net::UnescapeBinaryURLComponent(dropData_->url.spec());
+ std::string unescapedUrlString;
+ net::UnescapeBinaryURLComponent(dropData_->url.spec(),
+ &unescapedUrlString);
std::string escapedUrlString =
net::EscapeUrlEncodedData(unescapedUrlString, false);
url = [NSURL URLWithString:SysUTF8ToNSString(escapedUrlString)];
diff --git a/chromium/content/browser/web_package/signed_exchange_cert_fetcher_unittest.cc b/chromium/content/browser/web_package/signed_exchange_cert_fetcher_unittest.cc
index 9e5ea4406c0..104dbe1498c 100644
--- a/chromium/content/browser/web_package/signed_exchange_cert_fetcher_unittest.cc
+++ b/chromium/content/browser/web_package/signed_exchange_cert_fetcher_unittest.cc
@@ -40,16 +40,17 @@ class DeferringURLLoaderThrottle final : public URLLoaderThrottle {
}
void WillRedirectRequest(
- const net::RedirectInfo& redirect_info,
- const network::ResourceResponseHead& response_head,
+ const net::RedirectInfo& /* redirect_info */,
+ const network::ResourceResponseHead& /* response_head */,
bool* defer,
- std::vector<std::string>* to_be_removed_headers) override {
+ std::vector<std::string>* /* to_be_removed_headers */,
+ net::HttpRequestHeaders* /* modified_headers */) override {
will_redirect_request_called_ = true;
*defer = true;
}
void WillProcessResponse(const GURL& response_url_,
- const network::ResourceResponseHead& response_head,
+ network::ResourceResponseHead* response_head,
bool* defer) override {
will_process_response_called_ = true;
*defer = true;
@@ -211,7 +212,7 @@ class SignedExchangeCertFetcherTest : public testing::Test {
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&mock_loader_factory_),
std::move(throttles_), url, request_initiator_, force_fetch,
- SignedExchangeVersion::kB1, std::move(callback),
+ SignedExchangeVersion::kB2, std::move(callback),
nullptr /* devtools_proxy */,
base::nullopt /* throttling_profile_id */);
}
diff --git a/chromium/content/browser/web_package/signed_exchange_certificate_chain.cc b/chromium/content/browser/web_package/signed_exchange_certificate_chain.cc
index 1fd297d9512..c8e35ff3dee 100644
--- a/chromium/content/browser/web_package/signed_exchange_certificate_chain.cc
+++ b/chromium/content/browser/web_package/signed_exchange_certificate_chain.cc
@@ -17,12 +17,12 @@ namespace content {
namespace {
-// https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#cert-chain-format
-std::unique_ptr<SignedExchangeCertificateChain> ParseB1(
+// https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#cert-chain-format
+std::unique_ptr<SignedExchangeCertificateChain> ParseB2(
base::span<const uint8_t> message,
SignedExchangeDevToolsProxy* devtools_proxy) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
- "SignedExchangeCertificateChain::ParseB1");
+ "SignedExchangeCertificateChain::ParseB2");
cbor::CBORReader::DecoderError error;
base::Optional<cbor::CBORValue> value =
@@ -94,9 +94,9 @@ std::unique_ptr<SignedExchangeCertificateChain> ParseB1(
auto ocsp_iter = cert_map.find(cbor::CBORValue(kOcspKey));
if (i == 1) {
- // Step 2. The first certificate’s ocsp value if any MUST be a complete,
+ // Step 2. The first certificate’s ocsp value MUST be a complete,
// DER-encoded OCSP response for that certificate (using the ASN.1 type
- // OCSPResponse defined in [RFC2560]). ... [spec text]
+ // OCSPResponse defined in [RFC6960]). ... [spec text]
if (ocsp_iter == cert_map.end() || !ocsp_iter->second.is_bytestring()) {
signed_exchange_utils::ReportErrorAndTraceEvent(
devtools_proxy,
@@ -119,13 +119,11 @@ std::unique_ptr<SignedExchangeCertificateChain> ParseB1(
return nullptr;
}
- // Step 3. Each certificate’s sct value MUST be a
+ // Step 3. Each certificate’s sct value if any MUST be a
// SignedCertificateTimestampList for that certificate as defined by Section
// 3.3 of [RFC6962]. [spec text]
//
// We use SCTs only of the main certificate.
- // TODO(crbug.com/815025): Update the spec text once
- // https://github.com/WICG/webpackage/issues/175 is resolved.
if (i == 1) {
auto sct_iter = cert_map.find(cbor::CBORValue(kSctKey));
if (sct_iter != cert_map.end()) {
@@ -162,8 +160,8 @@ SignedExchangeCertificateChain::Parse(
SignedExchangeVersion version,
base::span<const uint8_t> cert_response_body,
SignedExchangeDevToolsProxy* devtools_proxy) {
- DCHECK_EQ(version, SignedExchangeVersion::kB1);
- return ParseB1(cert_response_body, devtools_proxy);
+ DCHECK_EQ(version, SignedExchangeVersion::kB2);
+ return ParseB2(cert_response_body, devtools_proxy);
}
SignedExchangeCertificateChain::SignedExchangeCertificateChain(
diff --git a/chromium/content/browser/web_package/signed_exchange_certificate_chain_fuzzer.cc b/chromium/content/browser/web_package/signed_exchange_certificate_chain_fuzzer.cc
index 8d718db5f0a..e6dc41086f8 100644
--- a/chromium/content/browser/web_package/signed_exchange_certificate_chain_fuzzer.cc
+++ b/chromium/content/browser/web_package/signed_exchange_certificate_chain_fuzzer.cc
@@ -9,7 +9,7 @@
namespace content {
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- SignedExchangeCertificateChain::Parse(SignedExchangeVersion::kB1,
+ SignedExchangeCertificateChain::Parse(SignedExchangeVersion::kB2,
base::make_span(data, size), nullptr);
return 0;
}
diff --git a/chromium/content/browser/web_package/signed_exchange_certificate_chain_unittest.cc b/chromium/content/browser/web_package/signed_exchange_certificate_chain_unittest.cc
index 6389105c3a0..99149484e4c 100644
--- a/chromium/content/browser/web_package/signed_exchange_certificate_chain_unittest.cc
+++ b/chromium/content/browser/web_package/signed_exchange_certificate_chain_unittest.cc
@@ -27,13 +27,13 @@ cbor::CBORValue CBORByteString(base::StringPiece str) {
} // namespace
-TEST(SignedExchangeCertificateParseB1Test, Empty) {
+TEST(SignedExchangeCertificateParseB2Test, Empty) {
auto parsed = SignedExchangeCertificateChain::Parse(
- SignedExchangeVersion::kB1, base::span<const uint8_t>(), nullptr);
+ SignedExchangeVersion::kB2, base::span<const uint8_t>(), nullptr);
EXPECT_FALSE(parsed);
}
-TEST(SignedExchangeCertificateParseB1Test, EmptyChain) {
+TEST(SignedExchangeCertificateParseB2Test, EmptyChain) {
cbor::CBORValue::ArrayValue cbor_array;
cbor_array.push_back(cbor::CBORValue(u8"\U0001F4DC\u26D3"));
@@ -42,11 +42,11 @@ TEST(SignedExchangeCertificateParseB1Test, EmptyChain) {
ASSERT_TRUE(serialized.has_value());
auto parsed = SignedExchangeCertificateChain::Parse(
- SignedExchangeVersion::kB1, base::make_span(*serialized), nullptr);
+ SignedExchangeVersion::kB2, base::make_span(*serialized), nullptr);
EXPECT_FALSE(parsed);
}
-TEST(SignedExchangeCertificateParseB1Test, MissingCert) {
+TEST(SignedExchangeCertificateParseB2Test, MissingCert) {
cbor::CBORValue::MapValue cbor_map;
cbor_map[cbor::CBORValue("sct")] = CBORByteString("SCT");
cbor_map[cbor::CBORValue("ocsp")] = CBORByteString("OCSP");
@@ -60,11 +60,11 @@ TEST(SignedExchangeCertificateParseB1Test, MissingCert) {
ASSERT_TRUE(serialized.has_value());
auto parsed = SignedExchangeCertificateChain::Parse(
- SignedExchangeVersion::kB1, base::make_span(*serialized), nullptr);
+ SignedExchangeVersion::kB2, base::make_span(*serialized), nullptr);
EXPECT_FALSE(parsed);
}
-TEST(SignedExchangeCertificateParseB1Test, OneCert) {
+TEST(SignedExchangeCertificateParseB2Test, OneCert) {
net::CertificateList certs;
ASSERT_TRUE(
net::LoadCertificateFiles({"subjectAltName_sanity_check.pem"}, &certs));
@@ -86,7 +86,7 @@ TEST(SignedExchangeCertificateParseB1Test, OneCert) {
ASSERT_TRUE(serialized.has_value());
auto parsed = SignedExchangeCertificateChain::Parse(
- SignedExchangeVersion::kB1, base::make_span(*serialized), nullptr);
+ SignedExchangeVersion::kB2, base::make_span(*serialized), nullptr);
ASSERT_TRUE(parsed);
EXPECT_EQ(cert_der, net::x509_util::CryptoBufferAsStringPiece(
parsed->cert()->cert_buffer()));
@@ -95,7 +95,7 @@ TEST(SignedExchangeCertificateParseB1Test, OneCert) {
EXPECT_EQ(parsed->sct(), base::make_optional<std::string>("SCT"));
}
-TEST(SignedExchangeCertificateParseB1Test, MissingOCSPInFirstCert) {
+TEST(SignedExchangeCertificateParseB2Test, MissingOCSPInFirstCert) {
net::CertificateList certs;
ASSERT_TRUE(
net::LoadCertificateFiles({"subjectAltName_sanity_check.pem"}, &certs));
@@ -116,11 +116,11 @@ TEST(SignedExchangeCertificateParseB1Test, MissingOCSPInFirstCert) {
ASSERT_TRUE(serialized.has_value());
auto parsed = SignedExchangeCertificateChain::Parse(
- SignedExchangeVersion::kB1, base::make_span(*serialized), nullptr);
+ SignedExchangeVersion::kB2, base::make_span(*serialized), nullptr);
EXPECT_FALSE(parsed);
}
-TEST(SignedExchangeCertificateParseB1Test, TwoCerts) {
+TEST(SignedExchangeCertificateParseB2Test, TwoCerts) {
net::CertificateList certs;
ASSERT_TRUE(net::LoadCertificateFiles(
{"subjectAltName_sanity_check.pem", "root_ca_cert.pem"}, &certs));
@@ -148,7 +148,7 @@ TEST(SignedExchangeCertificateParseB1Test, TwoCerts) {
ASSERT_TRUE(serialized.has_value());
auto parsed = SignedExchangeCertificateChain::Parse(
- SignedExchangeVersion::kB1, base::make_span(*serialized), nullptr);
+ SignedExchangeVersion::kB2, base::make_span(*serialized), nullptr);
ASSERT_TRUE(parsed);
EXPECT_EQ(cert1_der, net::x509_util::CryptoBufferAsStringPiece(
parsed->cert()->cert_buffer()));
@@ -159,7 +159,7 @@ TEST(SignedExchangeCertificateParseB1Test, TwoCerts) {
EXPECT_EQ(parsed->sct(), base::make_optional<std::string>("SCT"));
}
-TEST(SignedExchangeCertificateParseB1Test, HavingOCSPInSecondCert) {
+TEST(SignedExchangeCertificateParseB2Test, HavingOCSPInSecondCert) {
net::CertificateList certs;
ASSERT_TRUE(net::LoadCertificateFiles(
{"subjectAltName_sanity_check.pem", "root_ca_cert.pem"}, &certs));
@@ -188,11 +188,11 @@ TEST(SignedExchangeCertificateParseB1Test, HavingOCSPInSecondCert) {
ASSERT_TRUE(serialized.has_value());
auto parsed = SignedExchangeCertificateChain::Parse(
- SignedExchangeVersion::kB1, base::make_span(*serialized), nullptr);
+ SignedExchangeVersion::kB2, base::make_span(*serialized), nullptr);
EXPECT_FALSE(parsed);
}
-TEST(SignedExchangeCertificateParseB1Test, ParseGoldenFile) {
+TEST(SignedExchangeCertificateParseB2Test, ParseGoldenFile) {
base::FilePath path;
base::PathService::Get(content::DIR_TEST_DATA, &path);
path =
@@ -201,7 +201,7 @@ TEST(SignedExchangeCertificateParseB1Test, ParseGoldenFile) {
ASSERT_TRUE(base::ReadFileToString(path, &contents));
auto parsed = SignedExchangeCertificateChain::Parse(
- SignedExchangeVersion::kB1, base::as_bytes(base::make_span(contents)),
+ SignedExchangeVersion::kB2, base::as_bytes(base::make_span(contents)),
nullptr);
ASSERT_TRUE(parsed);
}
diff --git a/chromium/content/browser/web_package/signed_exchange_consts.h b/chromium/content/browser/web_package/signed_exchange_consts.h
index 6e8bd5210ae..4f18d332992 100644
--- a/chromium/content/browser/web_package/signed_exchange_consts.h
+++ b/chromium/content/browser/web_package/signed_exchange_consts.h
@@ -8,9 +8,9 @@
namespace content {
constexpr char kAcceptHeaderSignedExchangeSuffix[] =
- ",application/signed-exchange;v=b1";
+ ",application/signed-exchange;v=b2";
-enum class SignedExchangeVersion { kB1 };
+enum class SignedExchangeVersion { kB2 };
// Field names defined in the application/signed-exchange content type:
// https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#application-signed-exchange
diff --git a/chromium/content/browser/web_package/signed_exchange_envelope.cc b/chromium/content/browser/web_package/signed_exchange_envelope.cc
index b42ccc07872..96f2750eadc 100644
--- a/chromium/content/browser/web_package/signed_exchange_envelope.cc
+++ b/chromium/content/browser/web_package/signed_exchange_envelope.cc
@@ -15,6 +15,7 @@
#include "components/cbor/cbor_reader.h"
#include "content/browser/web_package/signed_exchange_consts.h"
#include "content/browser/web_package/signed_exchange_utils.h"
+#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
#include "url/origin.h"
@@ -83,30 +84,6 @@ bool ParseRequestMap(const cbor::CBORValue& value,
const cbor::CBORValue::MapValue& request_map = value.GetMap();
- auto url_iter = request_map.find(
- cbor::CBORValue(kUrlKey, cbor::CBORValue::Type::BYTE_STRING));
- if (url_iter == request_map.end() || !url_iter->second.is_bytestring()) {
- signed_exchange_utils::ReportErrorAndTraceEvent(
- devtools_proxy, ":url is not found or not a bytestring.");
- return false;
- }
- out->set_request_url(GURL(url_iter->second.GetBytestringAsString()));
- if (!out->request_url().is_valid()) {
- signed_exchange_utils::ReportErrorAndTraceEvent(devtools_proxy,
- ":url is not a valid URL.");
- return false;
- }
- if (out->request_url().has_ref()) {
- signed_exchange_utils::ReportErrorAndTraceEvent(
- devtools_proxy, ":url can't have a fragment.");
- return false;
- }
- if (!out->request_url().SchemeIs("https")) {
- signed_exchange_utils::ReportErrorAndTraceEvent(
- devtools_proxy, ":url scheme must be 'https'.");
- return false;
- }
-
auto method_iter = request_map.find(
cbor::CBORValue(kMethodKey, cbor::CBORValue::Type::BYTE_STRING));
if (method_iter == request_map.end() ||
@@ -137,7 +114,15 @@ bool ParseRequestMap(const cbor::CBORValue& value,
return false;
}
base::StringPiece name_str = it.first.GetBytestringAsString();
- if (name_str == kUrlKey || name_str == kMethodKey)
+
+ if (name_str == kUrlKey) {
+ signed_exchange_utils::ReportErrorAndTraceEvent(
+ devtools_proxy,
+ ":url key in request map is obsolete in this version of the format.");
+ return false;
+ }
+
+ if (name_str == kMethodKey)
continue;
// TODO(kouhei): Add spec ref here once
@@ -195,6 +180,20 @@ bool ParseResponseMap(const cbor::CBORValue& value,
devtools_proxy, "Failed to parse status code to integer.");
return false;
}
+ // https://wicg.github.io/webpackage/loading.html#parsing-b1
+ // Step 26. If parsedExchange’s response's status is a redirect status or the
+ // signed exchange version of parsedExchange’s response is not
+ // undefined, return a failure. [spec text]
+ // TODO(crbug.com/803774): Reject if inner response is a signed exchange.
+ if (net::HttpResponseHeaders::IsRedirectResponseCode(response_code)) {
+ signed_exchange_utils::ReportErrorAndTraceEvent(
+ devtools_proxy,
+ base::StringPrintf(
+ "Exchange's response status must not be a redirect status. "
+ "status: %d",
+ response_code));
+ return false;
+ }
out->set_response_code(static_cast<net::HttpStatusCode>(response_code));
for (const auto& it : response_map) {
@@ -257,11 +256,15 @@ bool ParseResponseMap(const cbor::CBORValue& value,
// static
base::Optional<SignedExchangeEnvelope> SignedExchangeEnvelope::Parse(
+ const GURL& fallback_url,
base::StringPiece signature_header_field,
base::span<const uint8_t> cbor_header,
SignedExchangeDevToolsProxy* devtools_proxy) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
"SignedExchangeEnvelope::Parse");
+
+ const GURL& request_url = fallback_url;
+
cbor::CBORReader::DecoderError error;
base::Optional<cbor::CBORValue> value =
cbor::CBORReader::Read(cbor_header, &error);
@@ -293,6 +296,8 @@ base::Optional<SignedExchangeEnvelope> SignedExchangeEnvelope::Parse(
}
SignedExchangeEnvelope ret;
+ ret.set_cbor_header(cbor_header);
+ ret.set_request_url(request_url);
if (!ParseRequestMap(top_level_array[0], &ret, devtools_proxy)) {
signed_exchange_utils::ReportErrorAndTraceEvent(
@@ -321,7 +326,6 @@ base::Optional<SignedExchangeEnvelope> SignedExchangeEnvelope::Parse(
// If the signature’s “validity-url” parameter is not same-origin with
// exchange’s effective request URI (Section 5.5 of [RFC7230]), return
// “invalid” [spec text]
- const GURL request_url = ret.request_url();
const GURL validity_url = ret.signature().validity_url;
if (!url::IsSameOriginWith(request_url, validity_url)) {
signed_exchange_utils::ReportErrorAndTraceEvent(
@@ -371,4 +375,8 @@ SignedExchangeEnvelope::BuildHttpResponseHeaders() const {
net::HttpUtil::AssembleRawHeaders(header_str.c_str(), header_str.size()));
}
+void SignedExchangeEnvelope::set_cbor_header(base::span<const uint8_t> data) {
+ cbor_header_ = std::vector<uint8_t>(data.begin(), data.end());
+}
+
} // namespace content
diff --git a/chromium/content/browser/web_package/signed_exchange_envelope.h b/chromium/content/browser/web_package/signed_exchange_envelope.h
index 7d865308062..6903b8eb536 100644
--- a/chromium/content/browser/web_package/signed_exchange_envelope.h
+++ b/chromium/content/browser/web_package/signed_exchange_envelope.h
@@ -30,12 +30,13 @@ class CONTENT_EXPORT SignedExchangeEnvelope {
public:
using HeaderMap = std::map<std::string, std::string>;
- // Parse headers from the application/signed-exchange;v=b0 format.
+ // Parse headers from the application/signed-exchange;v=b2 format.
// https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#application-signed-exchange
//
// This also performs the step 1, 3 and 4 of "Cross-origin trust" validation.
// https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#cross-origin-trust
static base::Optional<SignedExchangeEnvelope> Parse(
+ const GURL& fallback_url,
base::StringPiece signature_header_field,
base::span<const uint8_t> cbor_header,
SignedExchangeDevToolsProxy* devtools_proxy);
@@ -50,6 +51,11 @@ class CONTENT_EXPORT SignedExchangeEnvelope {
bool AddResponseHeader(base::StringPiece name, base::StringPiece value);
scoped_refptr<net::HttpResponseHeaders> BuildHttpResponseHeaders() const;
+ const base::span<const uint8_t> cbor_header() const {
+ return base::make_span(cbor_header_);
+ }
+ void set_cbor_header(base::span<const uint8_t> data);
+
const GURL& request_url() const { return request_url_; };
void set_request_url(GURL url) { request_url_ = std::move(url); }
@@ -72,6 +78,8 @@ class CONTENT_EXPORT SignedExchangeEnvelope {
}
private:
+ std::vector<uint8_t> cbor_header_;
+
GURL request_url_;
std::string request_method_;
diff --git a/chromium/content/browser/web_package/signed_exchange_envelope_unittest.cc b/chromium/content/browser/web_package/signed_exchange_envelope_unittest.cc
index 021d7fef021..919019bdfdf 100644
--- a/chromium/content/browser/web_package/signed_exchange_envelope_unittest.cc
+++ b/chromium/content/browser/web_package/signed_exchange_envelope_unittest.cc
@@ -34,6 +34,7 @@ cbor::CBORValue CBORByteString(const char* str) {
}
base::Optional<SignedExchangeEnvelope> GenerateHeaderAndParse(
+ const GURL& fallback_url,
base::StringPiece signature,
const std::map<const char*, const char*>& request_map,
const std::map<const char*, const char*>& response_map) {
@@ -50,7 +51,8 @@ base::Optional<SignedExchangeEnvelope> GenerateHeaderAndParse(
auto serialized = cbor::CBORWriter::Write(cbor::CBORValue(std::move(array)));
return SignedExchangeEnvelope::Parse(
- signature, base::make_span(serialized->data(), serialized->size()),
+ fallback_url, signature,
+ base::make_span(serialized->data(), serialized->size()),
nullptr /* devtools_proxy */);
}
@@ -66,25 +68,38 @@ TEST(SignedExchangeEnvelopeTest, ParseGoldenFile) {
ASSERT_TRUE(base::ReadFileToString(test_sxg_path, &contents));
auto* contents_bytes = reinterpret_cast<const uint8_t*>(contents.data());
- ASSERT_GT(contents.size(), SignedExchangePrologue::kEncodedPrologueInBytes);
- base::Optional<SignedExchangePrologue> prologue =
- SignedExchangePrologue::Parse(
- base::make_span(contents_bytes,
- SignedExchangePrologue::kEncodedPrologueInBytes),
+ ASSERT_GT(contents.size(),
+ signed_exchange_prologue::BeforeFallbackUrl::kEncodedSizeInBytes);
+ signed_exchange_prologue::BeforeFallbackUrl prologue_a =
+ signed_exchange_prologue::BeforeFallbackUrl::Parse(
+ base::make_span(
+ contents_bytes,
+ signed_exchange_prologue::BeforeFallbackUrl::kEncodedSizeInBytes),
nullptr /* devtools_proxy */);
- ASSERT_TRUE(prologue.has_value());
- ASSERT_GT(contents.size(), SignedExchangePrologue::kEncodedPrologueInBytes +
- prologue->ComputeFollowingSectionsLength());
-
+ ASSERT_GT(contents.size(),
+ signed_exchange_prologue::BeforeFallbackUrl::kEncodedSizeInBytes +
+ prologue_a.ComputeFallbackUrlAndAfterLength());
+ signed_exchange_prologue::FallbackUrlAndAfter prologue_b =
+ signed_exchange_prologue::FallbackUrlAndAfter::Parse(
+ base::make_span(contents_bytes +
+ signed_exchange_prologue::BeforeFallbackUrl::
+ kEncodedSizeInBytes,
+ prologue_a.ComputeFallbackUrlAndAfterLength()),
+ prologue_a, nullptr /* devtools_proxy */);
+
+ size_t signature_header_field_offset =
+ signed_exchange_prologue::BeforeFallbackUrl::kEncodedSizeInBytes +
+ prologue_a.ComputeFallbackUrlAndAfterLength();
base::StringPiece signature_header_field(
- contents.data() + SignedExchangePrologue::kEncodedPrologueInBytes,
- prologue->signature_header_field_length());
+ contents.data() + signature_header_field_offset,
+ prologue_b.signature_header_field_length());
const auto cbor_bytes = base::make_span<const uint8_t>(
- contents_bytes + SignedExchangePrologue::kEncodedPrologueInBytes +
- prologue->signature_header_field_length(),
- prologue->cbor_header_length());
+ contents_bytes + signature_header_field_offset +
+ prologue_b.signature_header_field_length(),
+ prologue_b.cbor_header_length());
const base::Optional<SignedExchangeEnvelope> envelope =
- SignedExchangeEnvelope::Parse(signature_header_field, cbor_bytes,
+ SignedExchangeEnvelope::Parse(prologue_b.fallback_url(),
+ signature_header_field, cbor_bytes,
nullptr /* devtools_proxy */);
ASSERT_TRUE(envelope.has_value());
EXPECT_EQ(envelope->request_url(), GURL("https://test.example.org/test/"));
@@ -92,14 +107,14 @@ TEST(SignedExchangeEnvelopeTest, ParseGoldenFile) {
EXPECT_EQ(envelope->response_code(), static_cast<net::HttpStatusCode>(200u));
EXPECT_EQ(envelope->response_headers().size(), 3u);
EXPECT_EQ(envelope->response_headers().find("content-encoding")->second,
- "mi-sha256-draft2");
+ "mi-sha256-03");
}
TEST(SignedExchangeEnvelopeTest, ValidHeader) {
auto header = GenerateHeaderAndParse(
- kSignatureString,
+ GURL("https://test.example.org/test/"), kSignatureString,
{
- {kUrlKey, "https://test.example.org/test/"}, {kMethodKey, "GET"},
+ {kMethodKey, "GET"},
},
{{kStatusKey, "200"}, {"content-type", "text/html"}});
ASSERT_TRUE(header.has_value());
@@ -110,58 +125,61 @@ TEST(SignedExchangeEnvelopeTest, ValidHeader) {
}
TEST(SignedExchangeEnvelopeTest, UnsafeMethod) {
- auto header = GenerateHeaderAndParse(
- kSignatureString,
- {
- {kUrlKey, "https://test.example.org/test/"}, {kMethodKey, "POST"},
- },
- {
- {kStatusKey, "200"},
- });
+ auto header = GenerateHeaderAndParse(GURL("https://test.example.org/test/"),
+ kSignatureString,
+ {
+ {kMethodKey, "POST"},
+ },
+ {
+ {kStatusKey, "200"},
+ });
ASSERT_FALSE(header.has_value());
}
-TEST(SignedExchangeEnvelopeTest, InvalidURL) {
- auto header = GenerateHeaderAndParse(
- kSignatureString,
- {
- {kUrlKey, "https:://test.example.org/test/"}, {kMethodKey, "GET"},
- },
- {
- {kStatusKey, "200"},
- });
+TEST(SignedExchangeEnvelopeTest, RelativeURL) {
+ auto header = GenerateHeaderAndParse(GURL("test/"), kSignatureString,
+ {
+ {kMethodKey, "GET"},
+ },
+ {
+ {kStatusKey, "200"},
+ });
ASSERT_FALSE(header.has_value());
}
-TEST(SignedExchangeEnvelopeTest, URLWithFragment) {
- auto header = GenerateHeaderAndParse(
- kSignatureString,
- {
- {kUrlKey, "https://test.example.org/test/#foo"}, {kMethodKey, "GET"},
- },
- {
- {kStatusKey, "200"},
- });
+TEST(SignedExchangeEnvelopeTest, HttpURLShouldFail) {
+ auto header = GenerateHeaderAndParse(GURL("http://test.example.org/test/"),
+ kSignatureString,
+ {
+ {kMethodKey, "GET"},
+ },
+ {
+ {kStatusKey, "200"},
+ });
ASSERT_FALSE(header.has_value());
}
-TEST(SignedExchangeEnvelopeTest, RelativeURL) {
- auto header =
- GenerateHeaderAndParse(kSignatureString,
- {
- {kUrlKey, "test/"}, {kMethodKey, "GET"},
- },
- {
- {kStatusKey, "200"},
- });
+TEST(SignedExchangeEnvelopeTest, RedirectStatusShouldFail) {
+ auto header = GenerateHeaderAndParse(GURL("https://test.example.org/test/"),
+ kSignatureString, {{kMethodKey, "GET"}},
+ {{kStatusKey, "302"}});
ASSERT_FALSE(header.has_value());
}
-TEST(SignedExchangeEnvelopeTest, HttpURLShouldFail) {
+TEST(SignedExchangeEnvelopeTest, Status300ShouldSucceed) {
+ auto header = GenerateHeaderAndParse(
+ GURL("https://test.example.org/test/"), kSignatureString,
+ {{kMethodKey, "GET"}},
+ {{kStatusKey, "300"}}); // 300 is not a redirect status.
+ ASSERT_TRUE(header.has_value());
+ EXPECT_EQ(header->response_code(), static_cast<net::HttpStatusCode>(300u));
+}
+
+TEST(SignedExchangeEnvelopeTest, StatefulRequestHeader) {
auto header = GenerateHeaderAndParse(
- kSignatureString,
+ GURL("https://test.example.org/test/"), kSignatureString,
{
- {kUrlKey, "http://test.example.org/test/"}, {kMethodKey, "GET"},
+ {kMethodKey, "GET"}, {"authorization", "Basic Zm9vOmJhcg=="},
},
{
{kStatusKey, "200"},
@@ -169,25 +187,11 @@ TEST(SignedExchangeEnvelopeTest, HttpURLShouldFail) {
ASSERT_FALSE(header.has_value());
}
-TEST(SignedExchangeEnvelopeTest, StatefulRequestHeader) {
- auto header =
- GenerateHeaderAndParse(kSignatureString,
- {
- {kUrlKey, "https://test.example.org/test/"},
- {kMethodKey, "GET"},
- {"authorization", "Basic Zm9vOmJhcg=="},
- },
- {
- {kStatusKey, "200"},
- });
- ASSERT_FALSE(header.has_value());
-}
-
TEST(SignedExchangeEnvelopeTest, StatefulResponseHeader) {
auto header = GenerateHeaderAndParse(
- kSignatureString,
+ GURL("https://test.example.org/test/"), kSignatureString,
{
- {kUrlKey, "https://test.example.org/test/"}, {kMethodKey, "GET"},
+ {kMethodKey, "GET"},
},
{
{kStatusKey, "200"}, {"set-cookie", "foo=bar"},
@@ -196,22 +200,20 @@ TEST(SignedExchangeEnvelopeTest, StatefulResponseHeader) {
}
TEST(SignedExchangeEnvelopeTest, UppercaseRequestMap) {
- auto header =
- GenerateHeaderAndParse(kSignatureString,
- {{kUrlKey, "https://test.example.org/test/"},
- {kMethodKey, "GET"},
- {"Accept-Language", "en-us"}},
- {
- {kStatusKey, "200"},
- });
+ auto header = GenerateHeaderAndParse(
+ GURL("https://test.example.org/test/"), kSignatureString,
+ {{kMethodKey, "GET"}, {"Accept-Language", "en-us"}},
+ {
+ {kStatusKey, "200"},
+ });
ASSERT_FALSE(header.has_value());
}
TEST(SignedExchangeEnvelopeTest, UppercaseResponseMap) {
auto header = GenerateHeaderAndParse(
- kSignatureString,
+ GURL("https://test.example.org/test/"), kSignatureString,
{
- {kUrlKey, "https://test.example.org/test/"}, {kMethodKey, "GET"},
+ {kMethodKey, "GET"},
},
{{kStatusKey, "200"}, {"Content-Length", "123"}});
ASSERT_FALSE(header.has_value());
@@ -219,9 +221,9 @@ TEST(SignedExchangeEnvelopeTest, UppercaseResponseMap) {
TEST(SignedExchangeEnvelopeTest, InvalidValidityURLHeader) {
auto header = GenerateHeaderAndParse(
- kSignatureString,
+ GURL("https://test2.example.org/test/"), kSignatureString,
{
- {kUrlKey, "https://test2.example.org/test/"}, {kMethodKey, "GET"},
+ {kMethodKey, "GET"},
},
{{kStatusKey, "200"}, {"content-type", "text/html"}});
ASSERT_FALSE(header.has_value());
diff --git a/chromium/content/browser/web_package/signed_exchange_handler.cc b/chromium/content/browser/web_package/signed_exchange_handler.cc
index b068987cc1f..a2c5fb82f99 100644
--- a/chromium/content/browser/web_package/signed_exchange_handler.cc
+++ b/chromium/content/browser/web_package/signed_exchange_handler.cc
@@ -7,7 +7,10 @@
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
+#include "content/browser/frame_host/frame_tree_node.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/loader/merkle_integrity_source_stream.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/web_package/signed_exchange_cert_fetcher_factory.h"
#include "content/browser/web_package/signed_exchange_certificate_chain.h"
#include "content/browser/web_package/signed_exchange_devtools_proxy.h"
@@ -17,39 +20,34 @@
#include "content/browser/web_package/signed_exchange_utils.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_features.h"
#include "content/public/common/url_loader_throttle.h"
+#include "mojo/public/cpp/bindings/callback_helpers.h"
#include "mojo/public/cpp/system/string_data_pipe_producer.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/cert/asn1_util.h"
#include "net/cert/cert_status_flags.h"
-#include "net/cert/cert_verifier.h"
-#include "net/cert/ct_policy_enforcer.h"
-#include "net/cert/ct_verifier.h"
#include "net/cert/x509_certificate.h"
#include "net/cert/x509_util.h"
#include "net/filter/source_stream.h"
-#include "net/http/transport_security_state.h"
-#include "net/ssl/ssl_config.h"
-#include "net/ssl/ssl_config_service.h"
#include "net/ssl/ssl_info.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/resource_response.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/url_loader_completion_status.h"
+#include "services/network/public/mojom/network_context.mojom.h"
namespace content {
namespace {
-constexpr char kMiHeader[] = "MI-Draft2";
+constexpr char kDigestHeader[] = "Digest";
-net::CertVerifier* g_cert_verifier_for_testing = nullptr;
+network::mojom::NetworkContext* g_network_context_for_testing = nullptr;
base::Optional<base::Time> g_verification_time_for_testing;
@@ -59,12 +57,58 @@ base::Time GetVerificationTime() {
return base::Time::Now();
}
+bool IsSupportedSignedExchangeVersion(
+ const base::Optional<SignedExchangeVersion>& version) {
+ return version == SignedExchangeVersion::kB2;
+}
+
+using VerifyCallback = base::OnceCallback<void(int32_t,
+ const net::CertVerifyResult&,
+ const net::ct::CTVerifyResult&)>;
+
+void OnVerifyCertUI(VerifyCallback callback,
+ int32_t error_code,
+ const net::CertVerifyResult& cv_result,
+ const net::ct::CTVerifyResult& ct_result) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(std::move(callback), error_code, cv_result, ct_result));
+}
+
+void VerifyCert(const scoped_refptr<net::X509Certificate>& certificate,
+ const GURL& url,
+ const std::string& ocsp_result,
+ const std::string& sct_list,
+ base::RepeatingCallback<int(void)> frame_tree_node_id_getter,
+ VerifyCallback callback) {
+ VerifyCallback wrapped_callback = mojo::WrapCallbackWithDefaultInvokeIfNotRun(
+ base::BindOnce(OnVerifyCertUI, std::move(callback)), net::ERR_FAILED,
+ net::CertVerifyResult(), net::ct::CTVerifyResult());
+
+ network::mojom::NetworkContext* network_context =
+ g_network_context_for_testing;
+ if (!network_context) {
+ auto* frame =
+ FrameTreeNode::GloballyFindByID(frame_tree_node_id_getter.Run());
+ if (!frame)
+ return;
+
+ network_context = frame->current_frame_host()
+ ->GetProcess()
+ ->GetStoragePartition()
+ ->GetNetworkContext();
+ }
+
+ network_context->VerifyCertForSignedExchange(
+ certificate, url, ocsp_result, sct_list, std::move(wrapped_callback));
+}
+
} // namespace
// static
-void SignedExchangeHandler::SetCertVerifierForTesting(
- net::CertVerifier* cert_verifier) {
- g_cert_verifier_for_testing = cert_verifier;
+void SignedExchangeHandler::SetNetworkContextForTesting(
+ network::mojom::NetworkContext* network_context) {
+ g_network_context_for_testing = network_context;
}
// static
@@ -79,17 +123,14 @@ SignedExchangeHandler::SignedExchangeHandler(
ExchangeHeadersCallback headers_callback,
std::unique_ptr<SignedExchangeCertFetcherFactory> cert_fetcher_factory,
int load_flags,
- scoped_refptr<net::URLRequestContextGetter> request_context_getter,
- std::unique_ptr<SignedExchangeDevToolsProxy> devtools_proxy)
+ std::unique_ptr<SignedExchangeDevToolsProxy> devtools_proxy,
+ base::RepeatingCallback<int(void)> frame_tree_node_id_getter)
: headers_callback_(std::move(headers_callback)),
source_(std::move(body)),
cert_fetcher_factory_(std::move(cert_fetcher_factory)),
load_flags_(load_flags),
- request_context_getter_(std::move(request_context_getter)),
- net_log_(net::NetLogWithSource::Make(
- request_context_getter_->GetURLRequestContext()->net_log(),
- net::NetLogSourceType::CERT_VERIFIER_JOB)),
devtools_proxy_(std::move(devtools_proxy)),
+ frame_tree_node_id_getter_(frame_tree_node_id_getter),
weak_factory_(this) {
DCHECK(signed_exchange_utils::IsSignedExchangeHandlingEnabled());
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
@@ -97,23 +138,20 @@ SignedExchangeHandler::SignedExchangeHandler(
if (!SignedExchangeSignatureHeaderField::GetVersionParamFromContentType(
content_type, &version_) ||
- version_ != SignedExchangeVersion::kB1) {
- base::SequencedTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&SignedExchangeHandler::RunErrorCallback,
- weak_factory_.GetWeakPtr(),
- net::ERR_INVALID_SIGNED_EXCHANGE));
+ !IsSupportedSignedExchangeVersion(version_)) {
signed_exchange_utils::ReportErrorAndTraceEvent(
devtools_proxy_.get(),
base::StringPrintf("Unsupported version of the content type. Currentry "
"content type must be "
- "\"application/signed-exchange;v=b1\". But the "
+ "\"application/signed-exchange;v=b2\". But the "
"response content type was \"%s\"",
content_type.c_str()));
- return;
+ // Proceed to extract and redirect to the fallback URL.
}
// Triggering the read (asynchronously) for the prologue bytes.
- SetupBuffers(SignedExchangePrologue::kEncodedPrologueInBytes);
+ SetupBuffers(
+ signed_exchange_prologue::BeforeFallbackUrl::kEncodedSizeInBytes);
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&SignedExchangeHandler::DoHeaderLoop,
weak_factory_.GetWeakPtr()));
@@ -124,6 +162,10 @@ SignedExchangeHandler::~SignedExchangeHandler() = default;
SignedExchangeHandler::SignedExchangeHandler()
: load_flags_(net::LOAD_NORMAL), weak_factory_(this) {}
+const GURL& SignedExchangeHandler::GetFallbackUrl() const {
+ return prologue_fallback_url_and_after_.fallback_url();
+}
+
void SignedExchangeHandler::SetupBuffers(size_t size) {
header_buf_ = base::MakeRefCounted<net::IOBuffer>(size);
header_read_buf_ =
@@ -131,7 +173,9 @@ void SignedExchangeHandler::SetupBuffers(size_t size) {
}
void SignedExchangeHandler::DoHeaderLoop() {
- DCHECK(state_ == State::kReadingPrologue || state_ == State::kReadingHeaders);
+ DCHECK(state_ == State::kReadingPrologueBeforeFallbackUrl ||
+ state_ == State::kReadingPrologueFallbackUrlAndAfter ||
+ state_ == State::kReadingHeaders);
int rv = source_->Read(
header_read_buf_.get(), header_read_buf_->BytesRemaining(),
base::BindRepeating(&SignedExchangeHandler::DidReadHeader,
@@ -141,7 +185,9 @@ void SignedExchangeHandler::DoHeaderLoop() {
}
void SignedExchangeHandler::DidReadHeader(bool completed_syncly, int result) {
- DCHECK(state_ == State::kReadingPrologue || state_ == State::kReadingHeaders);
+ DCHECK(state_ == State::kReadingPrologueBeforeFallbackUrl ||
+ state_ == State::kReadingPrologueFallbackUrlAndAfter ||
+ state_ == State::kReadingHeaders);
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
"SignedExchangeHandler::DidReadHeader");
@@ -164,8 +210,14 @@ void SignedExchangeHandler::DidReadHeader(bool completed_syncly, int result) {
header_read_buf_->DidConsume(result);
if (header_read_buf_->BytesRemaining() == 0) {
switch (state_) {
- case State::kReadingPrologue:
- if (!ParsePrologue()) {
+ case State::kReadingPrologueBeforeFallbackUrl:
+ if (!ParsePrologueBeforeFallbackUrl()) {
+ RunErrorCallback(net::ERR_INVALID_SIGNED_EXCHANGE);
+ return;
+ }
+ break;
+ case State::kReadingPrologueFallbackUrlAndAfter:
+ if (!ParsePrologueFallbackUrlAndAfter()) {
RunErrorCallback(net::ERR_INVALID_SIGNED_EXCHANGE);
return;
}
@@ -186,7 +238,9 @@ void SignedExchangeHandler::DidReadHeader(bool completed_syncly, int result) {
return;
// Trigger the next read.
- DCHECK(state_ == State::kReadingPrologue || state_ == State::kReadingHeaders);
+ DCHECK(state_ == State::kReadingPrologueBeforeFallbackUrl ||
+ state_ == State::kReadingPrologueFallbackUrlAndAfter ||
+ state_ == State::kReadingHeaders);
if (completed_syncly) {
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&SignedExchangeHandler::DoHeaderLoop,
@@ -196,18 +250,49 @@ void SignedExchangeHandler::DidReadHeader(bool completed_syncly, int result) {
}
}
-bool SignedExchangeHandler::ParsePrologue() {
- DCHECK_EQ(state_, State::kReadingPrologue);
+bool SignedExchangeHandler::ParsePrologueBeforeFallbackUrl() {
+ DCHECK_EQ(state_, State::kReadingPrologueBeforeFallbackUrl);
+
+ prologue_before_fallback_url_ =
+ signed_exchange_prologue::BeforeFallbackUrl::Parse(
+ base::make_span(
+ reinterpret_cast<uint8_t*>(header_buf_->data()),
+ signed_exchange_prologue::BeforeFallbackUrl::kEncodedSizeInBytes),
+ devtools_proxy_.get());
+
+ // Note: We will proceed even if |!prologue_before_fallback_url_.is_valid()|
+ // to attempt reading `fallbackUrl`.
+
+ // Set up a new buffer for reading
+ // |signed_exchange_prologue::FallbackUrlAndAfter|.
+ SetupBuffers(
+ prologue_before_fallback_url_.ComputeFallbackUrlAndAfterLength());
+ state_ = State::kReadingPrologueFallbackUrlAndAfter;
+ return true;
+}
+
+bool SignedExchangeHandler::ParsePrologueFallbackUrlAndAfter() {
+ DCHECK_EQ(state_, State::kReadingPrologueFallbackUrlAndAfter);
+
+ prologue_fallback_url_and_after_ =
+ signed_exchange_prologue::FallbackUrlAndAfter::Parse(
+ base::make_span(
+ reinterpret_cast<uint8_t*>(header_buf_->data()),
+ prologue_before_fallback_url_.ComputeFallbackUrlAndAfterLength()),
+ prologue_before_fallback_url_, devtools_proxy_.get());
+ if (!prologue_fallback_url_and_after_.is_valid()) {
+ return false;
+ }
- prologue_ = SignedExchangePrologue::Parse(
- base::make_span(reinterpret_cast<uint8_t*>(header_buf_->data()),
- SignedExchangePrologue::kEncodedPrologueInBytes),
- devtools_proxy_.get());
- if (!prologue_)
+ // If the signed exchange version from content-type is unsupported, abort
+ // parsing and redirect to the fallback URL.
+ if (!IsSupportedSignedExchangeVersion(version_))
return false;
- // Set up a new buffer for Signature + CBOR-encoded header reading.
- SetupBuffers(prologue_->ComputeFollowingSectionsLength());
+ // Set up a new buffer for reading the Signature header field and CBOR-encoded
+ // headers.
+ SetupBuffers(
+ prologue_fallback_url_and_after_.ComputeFollowingSectionsLength());
state_ = State::kReadingHeaders;
return true;
}
@@ -218,13 +303,15 @@ bool SignedExchangeHandler::ParseHeadersAndFetchCertificate() {
DCHECK_EQ(state_, State::kReadingHeaders);
base::StringPiece data(header_buf_->data(), header_read_buf_->size());
- base::StringPiece signature_header_field =
- data.substr(0, prologue_->signature_header_field_length());
- base::span<const uint8_t> cbor_header = base::as_bytes(
- base::make_span(data.substr(prologue_->signature_header_field_length(),
- prologue_->cbor_header_length())));
- envelope_ = SignedExchangeEnvelope::Parse(signature_header_field, cbor_header,
- devtools_proxy_.get());
+ base::StringPiece signature_header_field = data.substr(
+ 0, prologue_fallback_url_and_after_.signature_header_field_length());
+ base::span<const uint8_t> cbor_header =
+ base::as_bytes(base::make_span(data.substr(
+ prologue_fallback_url_and_after_.signature_header_field_length(),
+ prologue_fallback_url_and_after_.cbor_header_length())));
+ envelope_ =
+ SignedExchangeEnvelope::Parse(GetFallbackUrl(), signature_header_field,
+ cbor_header, devtools_proxy_.get());
header_read_buf_ = nullptr;
header_buf_ = nullptr;
if (!envelope_) {
@@ -264,8 +351,8 @@ void SignedExchangeHandler::RunErrorCallback(net::Error error) {
nullptr);
}
std::move(headers_callback_)
- .Run(error, GURL(), std::string(), network::ResourceResponseHead(),
- nullptr);
+ .Run(error, GetFallbackUrl(), std::string(),
+ network::ResourceResponseHead(), nullptr);
state_ = State::kHeadersCallbackCalled;
}
@@ -301,37 +388,25 @@ void SignedExchangeHandler::OnCertReceived(
return;
}
- // TODO(https://crbug.com/849935): The code below reaching into
- // URLRequestContext will not work with Network service.
- DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
- net::URLRequestContext* request_context =
- request_context_getter_->GetURLRequestContext();
- if (!request_context) {
- signed_exchange_utils::ReportErrorAndTraceEvent(
- devtools_proxy_.get(), "No request context available.");
- RunErrorCallback(net::ERR_CONTEXT_SHUT_DOWN);
- return;
- }
+ auto certificate = unverified_cert_chain_->cert();
+ auto url = envelope_->request_url();
+
+ // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#cross-origin-trust
+ // Step 6.4 Validate that valid SCTs from trusted logs are available from any
+ // of:
+ // - The SignedCertificateTimestampList in main-certificate’s sct property
+ // (Section 3.3),
+ const std::string& sct_list_from_cert_cbor = unverified_cert_chain_->sct();
+ // - An OCSP extension in the OCSP response in main-certificate’s ocsp
+ // property, or
+ const std::string& stapled_ocsp_response = unverified_cert_chain_->ocsp();
- net::SSLConfig config;
- request_context->ssl_config_service()->GetSSLConfig(&config);
-
- net::CertVerifier* cert_verifier = g_cert_verifier_for_testing
- ? g_cert_verifier_for_testing
- : request_context->cert_verifier();
- int result = cert_verifier->Verify(
- net::CertVerifier::RequestParams(
- unverified_cert_chain_->cert(), envelope_->request_url().host(),
- config.GetCertVerifyFlags(), unverified_cert_chain_->ocsp(),
- net::CertificateList()),
- net::SSLConfigService::GetCRLSet().get(), &cert_verify_result_,
- base::BindRepeating(&SignedExchangeHandler::OnCertVerifyComplete,
- base::Unretained(this)),
- &cert_verifier_request_, net_log_);
- // TODO(https://crbug.com/803774): Avoid these recursive patterns by using
- // explicit state machines (eg: DoLoop() in //net).
- if (result != net::ERR_IO_PENDING)
- OnCertVerifyComplete(result);
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::BindOnce(&VerifyCert, certificate, url, stapled_ocsp_response,
+ sct_list_from_cert_cbor, frame_tree_node_id_getter_,
+ base::BindOnce(&SignedExchangeHandler::OnVerifyCert,
+ weak_factory_.GetWeakPtr())));
}
bool SignedExchangeHandler::CheckCertExtension(
@@ -364,109 +439,34 @@ bool SignedExchangeHandler::CheckOCSPStatus(
return true;
}
-// TODO(https://crbug.com/815025, https://crbug.com/849935): This is temporary
-// code until we have Network Service friendly CT verification.
-int SignedExchangeHandler::VerifyCT(net::ct::CTVerifyResult* ct_verify_result) {
- // This function will not work with Network Service.
- DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
-
- net::URLRequestContext* request_context =
- request_context_getter_->GetURLRequestContext();
- if (!request_context)
- return net::ERR_CONTEXT_SHUT_DOWN;
-
- // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#cross-origin-trust
- // Step 6.4 Validate that valid SCTs from trusted logs are available from any
- // of:
- // - The SignedCertificateTimestampList in main-certificate’s sct property
- // (Section 3.3),
- const std::string& sct_list_from_cert_cbor = unverified_cert_chain_->sct();
- // - An OCSP extension in the OCSP response in main-certificate’s ocsp
- // property, or
- const std::string& stapled_ocsp_response = unverified_cert_chain_->ocsp();
- // - An X.509 extension in the certificate in main-certificate’s cert
- // property,
- net::X509Certificate* verified_cert = cert_verify_result_.verified_cert.get();
- // as described by Section 3.3 of [RFC6962]. [spec text]
- request_context->cert_transparency_verifier()->Verify(
- envelope_->request_url().host(), verified_cert, stapled_ocsp_response,
- sct_list_from_cert_cbor, &ct_verify_result->scts, net_log_);
-
- net::ct::SCTList verified_scts = net::ct::SCTsMatchingStatus(
- ct_verify_result->scts, net::ct::SCT_STATUS_OK);
-
- ct_verify_result->policy_compliance =
- request_context->ct_policy_enforcer()->CheckCompliance(
- verified_cert, verified_scts, net_log_);
-
- // TODO(https://crbug.com/803774): We should determine whether EV & SXG
- // should be a thing (due to the online/offline signing difference)
- if (cert_verify_result_.cert_status & net::CERT_STATUS_IS_EV &&
- ct_verify_result->policy_compliance !=
- net::ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS &&
- ct_verify_result->policy_compliance !=
- net::ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY) {
- cert_verify_result_.cert_status |= net::CERT_STATUS_CT_COMPLIANCE_FAILED;
- cert_verify_result_.cert_status &= ~net::CERT_STATUS_IS_EV;
- }
-
- net::TransportSecurityState::CTRequirementsStatus ct_requirement_status =
- request_context->transport_security_state()->CheckCTRequirements(
- net::HostPortPair::FromURL(envelope_->request_url()),
- cert_verify_result_.is_issued_by_known_root,
- cert_verify_result_.public_key_hashes, verified_cert,
- unverified_cert_chain_->cert().get(), ct_verify_result->scts,
- net::TransportSecurityState::ENABLE_EXPECT_CT_REPORTS,
- ct_verify_result->policy_compliance);
-
- switch (ct_requirement_status) {
- case net::TransportSecurityState::CT_REQUIREMENTS_NOT_MET:
- return net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED;
- case net::TransportSecurityState::CT_REQUIREMENTS_MET:
- ct_verify_result->policy_compliance_required = true;
- break;
- case net::TransportSecurityState::CT_NOT_REQUIRED:
- // CT is not required if the certificate does not chain to a publicly
- // trusted root certificate.
- if (!cert_verify_result_.is_issued_by_known_root) {
- ct_verify_result->policy_compliance_required = false;
- break;
- }
- // For old certificates (issued before 2018-05-01), CheckCTRequirements()
- // may return CT_NOT_REQUIRED, so we check the compliance status here.
- // TODO(https://crbug.com/851778): Remove this condition once we require
- // signing certificates to have CanSignHttpExchanges extension, because
- // such certificates should be naturally after 2018-05-01.
- if (ct_verify_result->policy_compliance ==
- net::ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS ||
- ct_verify_result->policy_compliance ==
- net::ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY) {
- ct_verify_result->policy_compliance_required = true;
- break;
- }
- // Require CT compliance, by overriding CT_NOT_REQUIRED and treat it as
- // ERR_CERTIFICATE_TRANSPARENCY_REQUIRED.
- return net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED;
- }
- return net::OK;
-}
-
-void SignedExchangeHandler::OnCertVerifyComplete(int result) {
+void SignedExchangeHandler::OnVerifyCert(
+ int32_t error_code,
+ const net::CertVerifyResult& cv_result,
+ const net::ct::CTVerifyResult& ct_result) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
"SignedExchangeHandler::OnCertVerifyComplete");
- if (result != net::OK) {
+ if (error_code != net::OK) {
+ std::string error_message;
+ if (error_code == net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED) {
+ error_message = base::StringPrintf(
+ "CT verification failed. result: %s, policy compliance: %d",
+ net::ErrorToShortString(error_code).c_str(),
+ ct_result.policy_compliance);
+ } else {
+ error_message =
+ base::StringPrintf("Certificate verification error: %s",
+ net::ErrorToShortString(error_code).c_str());
+ }
signed_exchange_utils::ReportErrorAndTraceEvent(
- devtools_proxy_.get(),
- base::StringPrintf("Certificate verification error: %s",
- net::ErrorToShortString(result).c_str()),
+ devtools_proxy_.get(), error_message,
std::make_pair(0 /* signature_index */,
SignedExchangeError::Field::kSignatureCertUrl));
RunErrorCallback(net::ERR_INVALID_SIGNED_EXCHANGE);
return;
}
- if (!CheckCertExtension(cert_verify_result_.verified_cert.get())) {
+ if (!CheckCertExtension(cv_result.verified_cert.get())) {
signed_exchange_utils::ReportErrorAndTraceEvent(
devtools_proxy_.get(),
"Certificate must have CanSignHttpExchangesDraft extension. To ignore "
@@ -478,28 +478,13 @@ void SignedExchangeHandler::OnCertVerifyComplete(int result) {
return;
}
- if (!CheckOCSPStatus(cert_verify_result_.ocsp_result)) {
+ if (!CheckOCSPStatus(cv_result.ocsp_result)) {
signed_exchange_utils::ReportErrorAndTraceEvent(
devtools_proxy_.get(),
base::StringPrintf(
"OCSP check failed. response status: %d, revocation status: %d",
- cert_verify_result_.ocsp_result.response_status,
- cert_verify_result_.ocsp_result.revocation_status),
- std::make_pair(0 /* signature_index */,
- SignedExchangeError::Field::kSignatureCertUrl));
- RunErrorCallback(net::ERR_INVALID_SIGNED_EXCHANGE);
- return;
- }
-
- net::ct::CTVerifyResult ct_verify_result;
- int ct_result = VerifyCT(&ct_verify_result);
- if (ct_result != net::OK) {
- signed_exchange_utils::ReportErrorAndTraceEvent(
- devtools_proxy_.get(),
- base::StringPrintf(
- "CT verification failed. result: %s, policy compliance: %d",
- net::ErrorToShortString(ct_result).c_str(),
- ct_verify_result.policy_compliance),
+ cv_result.ocsp_result.response_status,
+ cv_result.ocsp_result.revocation_status),
std::make_pair(0 /* signature_index */,
SignedExchangeError::Field::kSignatureCertUrl));
RunErrorCallback(net::ERR_INVALID_SIGNED_EXCHANGE);
@@ -520,29 +505,28 @@ void SignedExchangeHandler::OnCertVerifyComplete(int result) {
response_head.load_timing.send_end = now;
response_head.load_timing.receive_headers_end = now;
- std::string mi_header_value;
- if (!response_head.headers->EnumerateHeader(nullptr, kMiHeader,
- &mi_header_value)) {
+ std::string digest_header_value;
+ if (!response_head.headers->EnumerateHeader(nullptr, kDigestHeader,
+ &digest_header_value)) {
signed_exchange_utils::ReportErrorAndTraceEvent(
- devtools_proxy_.get(), "Signed exchange has no MI-Draft2: header");
+ devtools_proxy_.get(), "Signed exchange has no Digest: header");
RunErrorCallback(net::ERR_INVALID_SIGNED_EXCHANGE);
return;
}
auto mi_stream = std::make_unique<MerkleIntegritySourceStream>(
- mi_header_value, std::move(source_));
+ digest_header_value, std::move(source_));
net::SSLInfo ssl_info;
- ssl_info.cert = cert_verify_result_.verified_cert;
+ ssl_info.cert = cv_result.verified_cert;
ssl_info.unverified_cert = unverified_cert_chain_->cert();
- ssl_info.cert_status = cert_verify_result_.cert_status;
- ssl_info.is_issued_by_known_root =
- cert_verify_result_.is_issued_by_known_root;
- ssl_info.public_key_hashes = cert_verify_result_.public_key_hashes;
- ssl_info.ocsp_result = cert_verify_result_.ocsp_result;
+ ssl_info.cert_status = cv_result.cert_status;
+ ssl_info.is_issued_by_known_root = cv_result.is_issued_by_known_root;
+ ssl_info.public_key_hashes = cv_result.public_key_hashes;
+ ssl_info.ocsp_result = cv_result.ocsp_result;
ssl_info.is_fatal_cert_error =
net::IsCertStatusError(ssl_info.cert_status) &&
!net::IsCertStatusMinorError(ssl_info.cert_status);
- ssl_info.UpdateCertificateTransparencyInfo(ct_verify_result);
+ ssl_info.UpdateCertificateTransparencyInfo(ct_result);
if (devtools_proxy_) {
devtools_proxy_->OnSignedExchangeReceived(
diff --git a/chromium/content/browser/web_package/signed_exchange_handler.h b/chromium/content/browser/web_package/signed_exchange_handler.h
index b2ded77ac04..122ac720be3 100644
--- a/chromium/content/browser/web_package/signed_exchange_handler.h
+++ b/chromium/content/browser/web_package/signed_exchange_handler.h
@@ -24,16 +24,17 @@
#include "url/origin.h"
namespace net {
-class CertVerifier;
class CertVerifyResult;
class DrainableIOBuffer;
class SourceStream;
-class URLRequestContextGetter;
struct OCSPVerifyResult;
} // namespace net
namespace network {
struct ResourceResponseHead;
+namespace mojom {
+class NetworkContext;
+}
} // namespace network
namespace content {
@@ -43,12 +44,16 @@ class SignedExchangeCertFetcherFactory;
class SignedExchangeCertificateChain;
class SignedExchangeDevToolsProxy;
-// IMPORTANT: Currenly SignedExchangeHandler partially implements the verifying
-// logic.
-// TODO(https://crbug.com/803774): Implement verifying logic.
+// SignedExchangeHandler reads "application/signed-exchange" format from a
+// net::SourceStream, parse and verify the signed exchange, and report
+// the result asynchronously via SignedExchangeHandler::ExchangeHeadersCallback.
+//
+// Note that verifying a signed exchange requires an associated certificate
+// chain. SignedExchangeHandler creates a SignedExchangeCertFetcher to
+// fetch the certificate chain over network, and verify it with the
+// net::CertVerifier.
class CONTENT_EXPORT SignedExchangeHandler {
public:
- // TODO(https://crbug.com/803774): Add verification status here.
using ExchangeHeadersCallback = base::OnceCallback<void(
net::Error error,
const GURL& request_url,
@@ -56,9 +61,8 @@ class CONTENT_EXPORT SignedExchangeHandler {
const network::ResourceResponseHead&,
std::unique_ptr<net::SourceStream> payload_stream)>;
- // TODO(https://crbug.com/817187): Find a more sophisticated way to use a
- // MockCertVerifier in browser tests instead of using the static method.
- static void SetCertVerifierForTesting(net::CertVerifier* cert_verifier);
+ static void SetNetworkContextForTesting(
+ network::mojom::NetworkContext* network_context);
static void SetVerificationTimeForTesting(
base::Optional<base::Time> verification_time_for_testing);
@@ -73,8 +77,8 @@ class CONTENT_EXPORT SignedExchangeHandler {
ExchangeHeadersCallback headers_callback,
std::unique_ptr<SignedExchangeCertFetcherFactory> cert_fetcher_factory,
int load_flags,
- scoped_refptr<net::URLRequestContextGetter> request_context_getter,
- std::unique_ptr<SignedExchangeDevToolsProxy> devtools_proxy);
+ std::unique_ptr<SignedExchangeDevToolsProxy> devtools_proxy,
+ base::RepeatingCallback<int(void)> frame_tree_node_id_getter);
~SignedExchangeHandler();
protected:
@@ -82,57 +86,57 @@ class CONTENT_EXPORT SignedExchangeHandler {
private:
enum class State {
- kReadingPrologue,
+ kReadingPrologueBeforeFallbackUrl,
+ kReadingPrologueFallbackUrlAndAfter,
kReadingHeaders,
kFetchingCertificate,
kHeadersCallbackCalled,
};
+ const GURL& GetFallbackUrl() const;
+
void SetupBuffers(size_t size);
void DoHeaderLoop();
void DidReadHeader(bool completed_syncly, int result);
- bool ParsePrologue();
+ bool ParsePrologueBeforeFallbackUrl();
+ bool ParsePrologueFallbackUrlAndAfter();
bool ParseHeadersAndFetchCertificate();
void RunErrorCallback(net::Error);
void OnCertReceived(
std::unique_ptr<SignedExchangeCertificateChain> cert_chain);
- void OnCertVerifyComplete(int result);
bool CheckCertExtension(const net::X509Certificate* verified_cert);
bool CheckOCSPStatus(const net::OCSPVerifyResult& ocsp_result);
- int VerifyCT(net::ct::CTVerifyResult* ct_verify_result);
+
+ void OnVerifyCert(int32_t error_code,
+ const net::CertVerifyResult& cv_result,
+ const net::ct::CTVerifyResult& ct_result);
ExchangeHeadersCallback headers_callback_;
base::Optional<SignedExchangeVersion> version_;
std::unique_ptr<net::SourceStream> source_;
- State state_ = State::kReadingPrologue;
+ State state_ = State::kReadingPrologueBeforeFallbackUrl;
// Buffer used for prologue and envelope reading.
scoped_refptr<net::IOBuffer> header_buf_;
// Wrapper around |header_buf_| to progressively read fixed-size data.
scoped_refptr<net::DrainableIOBuffer> header_read_buf_;
- base::Optional<SignedExchangePrologue> prologue_;
+
+ signed_exchange_prologue::BeforeFallbackUrl prologue_before_fallback_url_;
+ signed_exchange_prologue::FallbackUrlAndAfter
+ prologue_fallback_url_and_after_;
base::Optional<SignedExchangeEnvelope> envelope_;
std::unique_ptr<SignedExchangeCertFetcherFactory> cert_fetcher_factory_;
std::unique_ptr<SignedExchangeCertFetcher> cert_fetcher_;
const int load_flags_;
- scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
-
std::unique_ptr<SignedExchangeCertificateChain> unverified_cert_chain_;
- // CertVerifyResult must be freed after the Request has been destructed.
- // So |cert_verify_result_| must be written before |cert_verifier_request_|.
- net::CertVerifyResult cert_verify_result_;
- std::unique_ptr<net::CertVerifier::Request> cert_verifier_request_;
-
- // TODO(https://crbug.com/767450): figure out what we should do for NetLog
- // with Network Service.
- net::NetLogWithSource net_log_;
-
std::unique_ptr<SignedExchangeDevToolsProxy> devtools_proxy_;
+ base::RepeatingCallback<int(void)> frame_tree_node_id_getter_;
+
base::WeakPtrFactory<SignedExchangeHandler> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(SignedExchangeHandler);
diff --git a/chromium/content/browser/web_package/signed_exchange_handler_unittest.cc b/chromium/content/browser/web_package/signed_exchange_handler_unittest.cc
index 54a648fc03b..43578473a64 100644
--- a/chromium/content/browser/web_package/signed_exchange_handler_unittest.cc
+++ b/chromium/content/browser/web_package/signed_exchange_handler_unittest.cc
@@ -12,11 +12,11 @@
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/test/scoped_feature_list.h"
-#include "base/test/scoped_task_environment.h"
#include "content/browser/web_package/signed_exchange_cert_fetcher_factory.h"
#include "content/browser/web_package/signed_exchange_devtools_proxy.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_paths.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
#include "net/base/test_completion_callback.h"
@@ -28,6 +28,7 @@
#include "net/test/cert_test_util.h"
#include "net/test/test_data_directory.h"
#include "net/url_request/url_request_test_util.h"
+#include "services/network/network_context.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -45,10 +46,17 @@ namespace {
const uint64_t kSignatureHeaderDate = 1520834000;
const int kOutputBufferSize = 4096;
+constexpr char kTestSxgInnerURL[] = "https://test.example.org/test/";
+
// "wildcard_example.org.public.pem.cbor" has these dummy data in "ocsp" and
// "sct" fields.
constexpr base::StringPiece kDummyOCSPDer = "OCSP";
-constexpr base::StringPiece kDummySCTList = "SCT";
+constexpr char kDummySCTBytes[] = {
+ 0x00, 0x05, // Length of the sct list
+ 0x00, 0x03, 'S', 'C', 'T' // List entry: length and body
+};
+constexpr base::StringPiece kDummySCTList(kDummySCTBytes,
+ sizeof(kDummySCTBytes));
std::string GetTestFileContents(base::StringPiece name) {
base::FilePath path;
@@ -105,20 +113,19 @@ class GMockCertVerifier : public net::CertVerifier {
public:
// net::CompletionOnceCallback is move-only, which GMock does not support.
int Verify(const net::CertVerifier::RequestParams& params,
- net::CRLSet* crl_set,
net::CertVerifyResult* verify_result,
net::CompletionOnceCallback callback,
std::unique_ptr<net::CertVerifier::Request>* out_req,
const net::NetLogWithSource& net_log) override {
- return VerifyImpl(params, crl_set, verify_result, out_req, net_log);
+ return VerifyImpl(params, verify_result, out_req, net_log);
}
- MOCK_METHOD5(VerifyImpl,
+ MOCK_METHOD4(VerifyImpl,
int(const net::CertVerifier::RequestParams& params,
- net::CRLSet* crl_set,
net::CertVerifyResult* verify_result,
std::unique_ptr<net::CertVerifier::Request>* out_req,
const net::NetLogWithSource& net_log));
+ MOCK_METHOD1(SetConfig, void(const net::CertVerifier::Config& config));
};
class MockCTVerifier : public net::CTVerifier {
@@ -158,7 +165,7 @@ class SignedExchangeHandlerTest
url::Origin::Create(GURL("https://sxg.example.com/test.sxg"))) {}
virtual std::string ContentType() {
- return "application/signed-exchange;v=b1";
+ return "application/signed-exchange;v=b2";
}
void SetUp() override {
@@ -183,14 +190,15 @@ class SignedExchangeHandlerTest
}
void TearDown() override {
- SignedExchangeHandler::SetCertVerifierForTesting(nullptr);
+ SignedExchangeHandler::SetNetworkContextForTesting(nullptr);
+ network::NetworkContext::SetCertVerifierForTesting(nullptr);
SignedExchangeHandler::SetVerificationTimeForTesting(
base::Optional<base::Time>());
}
void SetCertVerifier(std::unique_ptr<net::CertVerifier> cert_verifier) {
cert_verifier_ = std::move(cert_verifier);
- SignedExchangeHandler::SetCertVerifierForTesting(cert_verifier_.get());
+ network::NetworkContext::SetCertVerifierForTesting(cert_verifier_.get());
}
// Reads from |stream| until an error occurs or the EOF is reached.
@@ -228,6 +236,7 @@ class SignedExchangeHandlerTest
bool read_header() const { return read_header_; }
net::Error error() const { return error_; }
+ const GURL& inner_url() const { return inner_url_; }
const network::ResourceResponseHead& resource_response() const {
return resource_response_;
}
@@ -245,53 +254,61 @@ class SignedExchangeHandlerTest
void CreateSignedExchangeHandler(
std::unique_ptr<net::TestURLRequestContext> context) {
- request_context_getter_ = new net::TestURLRequestContextGetter(
- scoped_task_environment_.GetMainThreadTaskRunner(), std::move(context));
+ url_request_context_ = std::move(context);
+ network_context_ = std::make_unique<network::NetworkContext>(
+ nullptr, mojo::MakeRequest(&network_context_ptr_),
+ url_request_context_.get());
+ SignedExchangeHandler::SetNetworkContextForTesting(network_context_.get());
handler_ = std::make_unique<SignedExchangeHandler>(
ContentType(), std::move(source_stream_),
base::BindOnce(&SignedExchangeHandlerTest::OnHeaderFound,
base::Unretained(this)),
std::move(cert_fetcher_factory_), net::LOAD_NORMAL,
- request_context_getter_, nullptr /* devtools_proxy */);
+ nullptr /* devtools_proxy */, base::RepeatingCallback<int(void)>());
}
void WaitForHeader() {
while (!read_header()) {
while (source_->awaiting_completion())
source_->CompleteNextRead();
- scoped_task_environment_.RunUntilIdle();
+ browser_thread_bundle_.RunUntilIdle();
}
}
protected:
MockSignedExchangeCertFetcherFactory* mock_cert_fetcher_factory_;
std::unique_ptr<net::CertVerifier> cert_verifier_;
+ std::unique_ptr<MockCTVerifier> mock_ct_verifier_;
std::unique_ptr<MockCTPolicyEnforcer> mock_ct_policy_enforcer_;
net::MockSourceStream* source_;
std::unique_ptr<SignedExchangeHandler> handler_;
private:
void OnHeaderFound(net::Error error,
- const GURL&,
+ const GURL& url,
const std::string&,
const network::ResourceResponseHead& resource_response,
std::unique_ptr<net::SourceStream> payload_stream) {
read_header_ = true;
error_ = error;
+ inner_url_ = url;
resource_response_ = resource_response;
payload_stream_ = std::move(payload_stream);
}
base::test::ScopedFeatureList feature_list_;
- base::test::ScopedTaskEnvironment scoped_task_environment_;
- scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
+ content::TestBrowserThreadBundle browser_thread_bundle_;
+ std::unique_ptr<net::TestURLRequestContext> url_request_context_;
+ std::unique_ptr<network::NetworkContext> network_context_;
+ network::mojom::NetworkContextPtr network_context_ptr_;
const url::Origin request_initiator_;
std::unique_ptr<net::MockSourceStream> source_stream_;
std::unique_ptr<MockSignedExchangeCertFetcherFactory> cert_fetcher_factory_;
bool read_header_ = false;
net::Error error_;
+ GURL inner_url_;
network::ResourceResponseHead resource_response_;
std::unique_ptr<net::SourceStream> payload_stream_;
};
@@ -304,6 +321,7 @@ TEST_P(SignedExchangeHandlerTest, Empty) {
ASSERT_TRUE(read_header());
EXPECT_EQ(net::ERR_INVALID_SIGNED_EXCHANGE, error());
+ EXPECT_TRUE(inner_url().is_empty());
}
TEST_P(SignedExchangeHandlerTest, Simple) {
@@ -334,6 +352,7 @@ TEST_P(SignedExchangeHandlerTest, Simple) {
ASSERT_TRUE(read_header());
EXPECT_EQ(net::OK, error());
+ EXPECT_EQ(kTestSxgInnerURL, inner_url());
EXPECT_EQ(200, resource_response().headers->response_code());
EXPECT_EQ("text/html", resource_response().mime_type);
EXPECT_EQ("utf-8", resource_response().charset);
@@ -394,7 +413,7 @@ TEST_P(SignedExchangeHandlerTest, MimeType) {
}
TEST_P(SignedExchangeHandlerTest, HeaderParseError) {
- const uint8_t data[] = {'s', 'x', 'g', '1', '-', 'b', '1', '\0',
+ const uint8_t data[] = {'s', 'x', 'g', '1', '-', 'b', '2', '\0',
0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00};
source_->AddReadResult(reinterpret_cast<const char*>(data), sizeof(data),
net::OK, GetParam());
@@ -403,6 +422,7 @@ TEST_P(SignedExchangeHandlerTest, HeaderParseError) {
ASSERT_TRUE(read_header());
EXPECT_EQ(net::ERR_INVALID_SIGNED_EXCHANGE, error());
+ EXPECT_TRUE(inner_url().is_empty());
}
TEST_P(SignedExchangeHandlerTest, TruncatedInHeader) {
@@ -416,6 +436,7 @@ TEST_P(SignedExchangeHandlerTest, TruncatedInHeader) {
ASSERT_TRUE(read_header());
EXPECT_EQ(net::ERR_INVALID_SIGNED_EXCHANGE, error());
+ EXPECT_TRUE(inner_url().is_empty());
}
TEST_P(SignedExchangeHandlerTest, CertWithoutExtensionShouldBeRejected) {
@@ -446,6 +467,7 @@ TEST_P(SignedExchangeHandlerTest, CertWithoutExtensionShouldBeRejected) {
ASSERT_TRUE(read_header());
EXPECT_EQ(net::ERR_INVALID_SIGNED_EXCHANGE, error());
+ EXPECT_EQ(kTestSxgInnerURL, inner_url());
// Drain the MockSourceStream, otherwise its destructer causes DCHECK failure.
ReadStream(source_, nullptr);
}
@@ -513,6 +535,7 @@ TEST_P(SignedExchangeHandlerTest, CertSha256Mismatch) {
ASSERT_TRUE(read_header());
EXPECT_EQ(net::ERR_INVALID_SIGNED_EXCHANGE, error());
+ EXPECT_EQ(kTestSxgInnerURL, inner_url());
// Drain the MockSourceStream, otherwise its destructer causes DCHECK failure.
ReadStream(source_, nullptr);
}
@@ -547,6 +570,7 @@ TEST_P(SignedExchangeHandlerTest, VerifyCertFailure) {
ASSERT_TRUE(read_header());
EXPECT_EQ(net::ERR_INVALID_SIGNED_EXCHANGE, error());
+ EXPECT_EQ("https://test.example.com/test/", inner_url());
// Drain the MockSourceStream, otherwise its destructer causes DCHECK failure.
ReadStream(source_, nullptr);
}
@@ -578,6 +602,7 @@ TEST_P(SignedExchangeHandlerTest, OCSPNotChecked) {
ASSERT_TRUE(read_header());
EXPECT_EQ(net::ERR_INVALID_SIGNED_EXCHANGE, error());
+ EXPECT_EQ(kTestSxgInnerURL, inner_url());
// Drain the MockSourceStream, otherwise its destructer causes DCHECK failure.
ReadStream(source_, nullptr);
}
@@ -609,6 +634,7 @@ TEST_P(SignedExchangeHandlerTest, OCSPNotProvided) {
ASSERT_TRUE(read_header());
EXPECT_EQ(net::ERR_INVALID_SIGNED_EXCHANGE, error());
+ EXPECT_EQ(kTestSxgInnerURL, inner_url());
// Drain the MockSourceStream, otherwise its destructer causes DCHECK failure.
ReadStream(source_, nullptr);
}
@@ -641,6 +667,7 @@ TEST_P(SignedExchangeHandlerTest, OCSPInvalid) {
ASSERT_TRUE(read_header());
EXPECT_EQ(net::ERR_INVALID_SIGNED_EXCHANGE, error());
+ EXPECT_EQ(kTestSxgInnerURL, inner_url());
// Drain the MockSourceStream, otherwise its destructer causes DCHECK failure.
ReadStream(source_, nullptr);
}
@@ -674,6 +701,7 @@ TEST_P(SignedExchangeHandlerTest, OCSPRevoked) {
ASSERT_TRUE(read_header());
EXPECT_EQ(net::ERR_INVALID_SIGNED_EXCHANGE, error());
+ EXPECT_EQ(kTestSxgInnerURL, inner_url());
// Drain the MockSourceStream, otherwise its destructer causes DCHECK failure.
ReadStream(source_, nullptr);
}
@@ -704,10 +732,9 @@ TEST_P(SignedExchangeHandlerTest, CertVerifierParams) {
CertEqualsIncludingChain(original_cert)),
Property(&net::CertVerifier::RequestParams::hostname,
"test.example.org")),
- _ /* crl_set */, _ /* verify_result */, _ /* out_req */,
- _ /* net_log */
+ _ /* verify_result */, _ /* out_req */, _ /* net_log */
))
- .WillOnce(DoAll(SetArgPointee<2>(fake_result), Return(net::OK)));
+ .WillOnce(DoAll(SetArgPointee<1>(fake_result), Return(net::OK)));
SetCertVerifier(std::move(gmock_cert_verifier));
std::string contents = GetTestFileContents("test.example.org_test.sxg");
@@ -760,6 +787,7 @@ TEST_P(SignedExchangeHandlerTest, NotEnoughSCTsFromPubliclyTrustedCert) {
ASSERT_TRUE(read_header());
EXPECT_EQ(net::ERR_INVALID_SIGNED_EXCHANGE, error());
+ EXPECT_EQ(kTestSxgInnerURL, inner_url());
// Drain the MockSourceStream, otherwise its destructer causes DCHECK failure.
ReadStream(source_, nullptr);
}
@@ -884,9 +912,8 @@ TEST_P(SignedExchangeHandlerTest, CTVerifierParams) {
.WillOnce(
Return(net::ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS));
- std::unique_ptr<MockCTVerifier> ct_verifier =
- std::make_unique<MockCTVerifier>();
- EXPECT_CALL(*ct_verifier,
+ mock_ct_verifier_ = std::make_unique<MockCTVerifier>();
+ EXPECT_CALL(*mock_ct_verifier_,
Verify(base::StringPiece("test.example.org"),
CertEqualsIncludingChain(original_cert), kDummyOCSPDer,
kDummySCTList, _ /* output_scts */, _ /* net_log */))
@@ -896,7 +923,8 @@ TEST_P(SignedExchangeHandlerTest, CTVerifierParams) {
true /* delay_initialization */);
test_url_request_context->set_ct_policy_enforcer(
mock_ct_policy_enforcer_.get());
- test_url_request_context->set_cert_transparency_verifier(ct_verifier.get());
+ test_url_request_context->set_cert_transparency_verifier(
+ mock_ct_verifier_.get());
test_url_request_context->Init();
// Make the MockCertVerifier treat the certificate
diff --git a/chromium/content/browser/web_package/signed_exchange_loader.cc b/chromium/content/browser/web_package/signed_exchange_loader.cc
index 9ede996006a..d03dd7f2947 100644
--- a/chromium/content/browser/web_package/signed_exchange_loader.cc
+++ b/chromium/content/browser/web_package/signed_exchange_loader.cc
@@ -20,7 +20,6 @@
#include "net/base/net_errors.h"
#include "net/cert/cert_status_flags.h"
#include "net/http/http_util.h"
-#include "net/url_request/url_request_context_getter.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/url_loader_completion_status.h"
@@ -30,11 +29,22 @@ namespace content {
namespace {
-net::RedirectInfo CreateRedirectInfo(const GURL& new_url) {
+net::RedirectInfo CreateRedirectInfo(const GURL& new_url,
+ const GURL& outer_request_url) {
net::RedirectInfo redirect_info;
- redirect_info.new_url = new_url;
+ if (outer_request_url.has_ref()) {
+ // Propagate ref fragment from the outer request URL.
+ url::Replacements<char> replacements;
+ base::StringPiece ref = outer_request_url.ref_piece();
+ replacements.SetRef(ref.data(), url::Component(0, ref.length()));
+ redirect_info.new_url = new_url.ReplaceComponents(replacements);
+ } else {
+ redirect_info.new_url = new_url;
+ }
redirect_info.new_method = "GET";
- redirect_info.status_code = 302;
+ // https://wicg.github.io/webpackage/loading.html#mp-http-fetch
+ // Step 3. Set actualResponse's status to 303. [spec text]
+ redirect_info.status_code = 303;
redirect_info.new_site_for_cookies = redirect_info.new_url;
return redirect_info;
}
@@ -57,7 +67,7 @@ class SignedExchangeLoader::ResponseTimingInfo {
network::ResourceResponseHead CreateRedirectResponseHead() const {
network::ResourceResponseHead response_head;
response_head.encoded_data_length = 0;
- std::string buf(base::StringPrintf("HTTP/1.1 %d %s\r\n", 302, "Found"));
+ std::string buf(base::StringPrintf("HTTP/1.1 %d %s\r\n", 303, "See Other"));
response_head.headers = new net::HttpResponseHeaders(
net::HttpUtil::AssembleRawHeaders(buf.c_str(), buf.size()));
response_head.encoded_data_length = 0;
@@ -87,12 +97,14 @@ SignedExchangeLoader::SignedExchangeLoader(
url::Origin request_initiator,
uint32_t url_loader_options,
int load_flags,
+ bool should_redirect_on_failure,
const base::Optional<base::UnguessableToken>& throttling_profile_id,
std::unique_ptr<SignedExchangeDevToolsProxy> devtools_proxy,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
URLLoaderThrottlesGetter url_loader_throttles_getter,
- scoped_refptr<net::URLRequestContextGetter> request_context_getter)
- : outer_response_timing_info_(
+ base::RepeatingCallback<int(void)> frame_tree_node_id_getter)
+ : outer_request_url_(outer_request_url),
+ outer_response_timing_info_(
std::make_unique<ResponseTimingInfo>(outer_response)),
outer_response_(outer_response),
forwarding_client_(std::move(forwarding_client)),
@@ -100,13 +112,15 @@ SignedExchangeLoader::SignedExchangeLoader(
request_initiator_(request_initiator),
url_loader_options_(url_loader_options),
load_flags_(load_flags),
+ should_redirect_on_failure_(should_redirect_on_failure),
throttling_profile_id_(throttling_profile_id),
devtools_proxy_(std::move(devtools_proxy)),
url_loader_factory_(std::move(url_loader_factory)),
url_loader_throttles_getter_(std::move(url_loader_throttles_getter)),
- request_context_getter_(std::move(request_context_getter)),
+ frame_tree_node_id_getter_(frame_tree_node_id_getter),
weak_factory_(this) {
DCHECK(signed_exchange_utils::IsSignedExchangeHandlingEnabled());
+ DCHECK(outer_request_url_.is_valid());
// https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#privacy-considerations
// This can be difficult to determine when the exchange is being loaded from
@@ -129,25 +143,6 @@ SignedExchangeLoader::SignedExchangeLoader(
return;
}
- // TODO(https://crbug.com/849935): Remove this once we have Network Service
- // friendly cert, OCSP, and CT verification.
- if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
- devtools_proxy_->ReportError(
- "Currently, signed exchange does not work when "
- "chrome://flags/#network-service is enabled. "
- "See http://crbug.com/849935 for details.",
- base::nullopt /* error_field */);
- // Calls OnSignedExchangeReceived() to show the outer response in DevTool's
- // Network panel and the error message in the Preview panel.
- devtools_proxy_->OnSignedExchangeReceived(base::nullopt /* header */,
- nullptr /* certificate */,
- nullptr /* ssl_info */);
- // This will asynchronously delete |this|.
- forwarding_client_->OnComplete(
- network::URLLoaderCompletionStatus(net::ERR_INVALID_SIGNED_EXCHANGE));
- return;
- }
-
// Can't use HttpResponseHeaders::GetMimeType() because SignedExchangeHandler
// checks "v=" parameter.
outer_response.headers->EnumerateHeader(nullptr, "content-type",
@@ -228,8 +223,8 @@ void SignedExchangeLoader::OnStartLoadingResponseBody(
content_type_, std::make_unique<DataPipeToSourceStream>(std::move(body)),
base::BindOnce(&SignedExchangeLoader::OnHTTPExchangeFound,
weak_factory_.GetWeakPtr()),
- std::move(cert_fetcher_factory), load_flags_,
- std::move(request_context_getter_), std::move(devtools_proxy_));
+ std::move(cert_fetcher_factory), load_flags_, std::move(devtools_proxy_),
+ frame_tree_node_id_getter_);
}
void SignedExchangeLoader::OnComplete(
@@ -243,9 +238,6 @@ void SignedExchangeLoader::FollowRedirect(
}
void SignedExchangeLoader::ProceedWithResponse() {
- // TODO(https://crbug.com/791049): Remove this when NetworkService is
- // enabled by default.
- DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
DCHECK(body_data_pipe_adapter_);
DCHECK(pending_body_consumer_.is_valid());
@@ -280,15 +272,28 @@ void SignedExchangeLoader::OnHTTPExchangeFound(
const network::ResourceResponseHead& resource_response,
std::unique_ptr<net::SourceStream> payload_stream) {
if (error) {
- // This will eventually delete |this|.
- forwarding_client_->OnComplete(network::URLLoaderCompletionStatus(error));
+ if (error != net::ERR_INVALID_SIGNED_EXCHANGE ||
+ !should_redirect_on_failure_ || !request_url.is_valid()) {
+ // Let the request fail.
+ // This will eventually delete |this|.
+ forwarding_client_->OnComplete(network::URLLoaderCompletionStatus(error));
+ return;
+ }
+ // Make a fallback redirect to |request_url|.
+ DCHECK(!has_redirected_to_fallback_url_);
+ has_redirected_to_fallback_url_ = true;
+ DCHECK(outer_response_timing_info_);
+ forwarding_client_->OnReceiveRedirect(
+ CreateRedirectInfo(request_url, outer_request_url_),
+ std::move(outer_response_timing_info_)->CreateRedirectResponseHead());
+ forwarding_client_.reset();
return;
}
// TODO(https://crbug.com/803774): Handle no-GET request_method as a error.
DCHECK(outer_response_timing_info_);
forwarding_client_->OnReceiveRedirect(
- CreateRedirectInfo(request_url),
+ CreateRedirectInfo(request_url, outer_request_url_),
std::move(outer_response_timing_info_)->CreateRedirectResponseHead());
forwarding_client_.reset();
diff --git a/chromium/content/browser/web_package/signed_exchange_loader.h b/chromium/content/browser/web_package/signed_exchange_loader.h
index 2ab0d3a1d66..47cdeccf490 100644
--- a/chromium/content/browser/web_package/signed_exchange_loader.h
+++ b/chromium/content/browser/web_package/signed_exchange_loader.h
@@ -19,7 +19,6 @@
namespace net {
class SourceStream;
-class URLRequestContextGetter;
} // namespace net
namespace network {
@@ -45,6 +44,8 @@ class SignedExchangeLoader final : public network::mojom::URLLoaderClient,
using URLLoaderThrottlesGetter = base::RepeatingCallback<
std::vector<std::unique_ptr<content::URLLoaderThrottle>>()>;
+ // If |should_redirect_on_failure| is true, verification failure causes a
+ // redirect to the fallback URL.
SignedExchangeLoader(
const GURL& outer_request_url,
const network::ResourceResponseHead& outer_response,
@@ -53,13 +54,18 @@ class SignedExchangeLoader final : public network::mojom::URLLoaderClient,
url::Origin request_initiator,
uint32_t url_loader_options,
int load_flags,
+ bool should_redirect_on_failure,
const base::Optional<base::UnguessableToken>& throttling_profile_id,
std::unique_ptr<SignedExchangeDevToolsProxy> devtools_proxy,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
URLLoaderThrottlesGetter url_loader_throttles_getter,
- scoped_refptr<net::URLRequestContextGetter> request_context_getter);
+ base::RepeatingCallback<int(void)> frame_tree_node_id_getter);
~SignedExchangeLoader() override;
+ bool HasRedirectedToFallbackURL() const {
+ return has_redirected_to_fallback_url_;
+ }
+
// network::mojom::URLLoaderClient implementation
// Only OnStartLoadingResponseBody() and OnComplete() are called.
void OnReceiveResponse(
@@ -107,6 +113,8 @@ class SignedExchangeLoader final : public network::mojom::URLLoaderClient,
void FinishReadingBody(int result);
+ const GURL outer_request_url_;
+
// This timing info is used to create a dummy redirect response.
std::unique_ptr<const ResponseTimingInfo> outer_response_timing_info_;
@@ -137,11 +145,13 @@ class SignedExchangeLoader final : public network::mojom::URLLoaderClient,
url::Origin request_initiator_;
const uint32_t url_loader_options_;
const int load_flags_;
+ const bool should_redirect_on_failure_;
+ bool has_redirected_to_fallback_url_ = false;
const base::Optional<base::UnguessableToken> throttling_profile_id_;
std::unique_ptr<SignedExchangeDevToolsProxy> devtools_proxy_;
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
URLLoaderThrottlesGetter url_loader_throttles_getter_;
- scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
+ base::RepeatingCallback<int(void)> frame_tree_node_id_getter_;
base::Optional<net::SSLInfo> ssl_info_;
diff --git a/chromium/content/browser/web_package/signed_exchange_prefetch_handler.cc b/chromium/content/browser/web_package/signed_exchange_prefetch_handler.cc
index c28252bf4df..abf10c2ed0a 100644
--- a/chromium/content/browser/web_package/signed_exchange_prefetch_handler.cc
+++ b/chromium/content/browser/web_package/signed_exchange_prefetch_handler.cc
@@ -51,12 +51,13 @@ SignedExchangePrefetchHandler::SignedExchangePrefetchHandler(
signed_exchange_loader_ = std::make_unique<SignedExchangeLoader>(
outer_request_url, response, std::move(client), std::move(endpoints),
std::move(request_initiator), network::mojom::kURLLoadOptionNone,
- load_flags, throttling_profile_id,
+ load_flags, false /* should_redirect_to_fallback */,
+ throttling_profile_id,
std::make_unique<SignedExchangeDevToolsProxy>(
- outer_request_url, response, std::move(frame_tree_node_id_getter),
+ outer_request_url, response, frame_tree_node_id_getter,
base::nullopt /* devtools_navigation_token */, report_raw_headers),
std::move(url_loader_factory), loader_throttles_getter,
- request_context_getter);
+ frame_tree_node_id_getter);
}
SignedExchangePrefetchHandler::~SignedExchangePrefetchHandler() = default;
diff --git a/chromium/content/browser/web_package/signed_exchange_prologue.cc b/chromium/content/browser/web_package/signed_exchange_prologue.cc
index 8f45dc93d90..c298b0b6261 100644
--- a/chromium/content/browser/web_package/signed_exchange_prologue.cc
+++ b/chromium/content/browser/web_package/signed_exchange_prologue.cc
@@ -4,6 +4,7 @@
#include "content/browser/web_package/signed_exchange_prologue.h"
+#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "base/trace_event/trace_event.h"
#include "content/browser/web_package/signed_exchange_utils.h"
@@ -12,72 +13,170 @@ namespace content {
namespace {
-constexpr char kSignedExchangeMagic[] = "sxg1-b1";
+constexpr char kSignedExchangeMagic[] = "sxg1-b2";
+
+// size of `fallbackUrlLength` field in number of bytes.
+constexpr size_t kFallbackUrlLengthFieldSizeInBytes = 2;
+// size of `sigLength` field in number of bytes.
+constexpr size_t kSigLengthFieldLengthInBytes = 3;
+// size of `headerLength` field in number of bytes.
+constexpr size_t kHeaderLengthFieldLengthInBytes = 3;
+
constexpr size_t kMaximumSignatureHeaderFieldLength = 16 * 1024;
constexpr size_t kMaximumCBORHeaderLength = 512 * 1024;
} // namespace
-constexpr size_t SignedExchangePrologue::kEncodedLengthInBytes;
-size_t SignedExchangePrologue::kEncodedPrologueInBytes =
- sizeof(kSignedExchangeMagic) +
- SignedExchangePrologue::kEncodedLengthInBytes * 2;
+namespace signed_exchange_prologue {
-// static
-size_t SignedExchangePrologue::ParseEncodedLength(
- base::span<const uint8_t> input) {
- DCHECK_EQ(input.size(), SignedExchangePrologue::kEncodedLengthInBytes);
+constexpr size_t BeforeFallbackUrl::kEncodedSizeInBytes =
+ sizeof(kSignedExchangeMagic) + kFallbackUrlLengthFieldSizeInBytes;
+
+size_t Parse2BytesEncodedLength(base::span<const uint8_t> input) {
+ DCHECK_EQ(input.size(), 2u);
+ return static_cast<size_t>(input[0]) << 8 | static_cast<size_t>(input[1]);
+}
+
+size_t Parse3BytesEncodedLength(base::span<const uint8_t> input) {
+ DCHECK_EQ(input.size(), 3u);
return static_cast<size_t>(input[0]) << 16 |
static_cast<size_t>(input[1]) << 8 | static_cast<size_t>(input[2]);
}
// static
-base::Optional<SignedExchangePrologue> SignedExchangePrologue::Parse(
+BeforeFallbackUrl BeforeFallbackUrl::Parse(
base::span<const uint8_t> input,
SignedExchangeDevToolsProxy* devtools_proxy) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
- "SignedExchangePrologue::Parse");
+ "signed_exchange_prologue::BeforeFallbackUrl::Parse");
- CHECK_EQ(input.size(), kEncodedPrologueInBytes);
+ CHECK_EQ(input.size(), kEncodedSizeInBytes);
const auto magic_string = input.subspan(0, sizeof(kSignedExchangeMagic));
- const auto encoded_signature_header_field_length =
- input.subspan(sizeof(kSignedExchangeMagic), kEncodedLengthInBytes);
- const auto encoded_cbor_header_length =
- input.subspan(sizeof(kSignedExchangeMagic) + kEncodedLengthInBytes,
- kEncodedLengthInBytes);
+ const auto encoded_fallback_url_length_field = input.subspan(
+ sizeof(kSignedExchangeMagic), kFallbackUrlLengthFieldSizeInBytes);
+ bool is_valid = true;
if (memcmp(magic_string.data(), kSignedExchangeMagic,
sizeof(kSignedExchangeMagic)) != 0) {
signed_exchange_utils::ReportErrorAndTraceEvent(devtools_proxy,
"Wrong magic string");
- return base::nullopt;
+ is_valid = false;
+ }
+
+ size_t fallback_url_length =
+ Parse2BytesEncodedLength(encoded_fallback_url_length_field);
+ return BeforeFallbackUrl(is_valid, fallback_url_length);
+}
+
+size_t BeforeFallbackUrl::ComputeFallbackUrlAndAfterLength() const {
+ return fallback_url_length_ + kSigLengthFieldLengthInBytes +
+ kHeaderLengthFieldLengthInBytes;
+}
+
+// static
+FallbackUrlAndAfter FallbackUrlAndAfter::ParseFailedButFallbackUrlAvailable(
+ GURL fallback_url) {
+ return FallbackUrlAndAfter(/*is_valid=*/false, std::move(fallback_url),
+ /*signature_header_field_length=*/0,
+ /*cbor_header_length=*/0);
+}
+
+// static
+FallbackUrlAndAfter FallbackUrlAndAfter::Parse(
+ base::span<const uint8_t> input,
+ const BeforeFallbackUrl& before_fallback_url,
+ SignedExchangeDevToolsProxy* devtools_proxy) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
+ "signed_exchange_prologue::FallbackUrlAndAfter::Parse");
+
+ if (input.size() < before_fallback_url.fallback_url_length()) {
+ signed_exchange_utils::ReportErrorAndTraceEvent(
+ devtools_proxy,
+ "End of stream reached before reading the entire `fallbackUrl`.");
+ return FallbackUrlAndAfter();
+ }
+
+ base::StringPiece fallback_url_str(
+ reinterpret_cast<const char*>(input.data()),
+ before_fallback_url.fallback_url_length());
+ GURL fallback_url(fallback_url_str);
+
+ if (!fallback_url.is_valid()) {
+ signed_exchange_utils::ReportErrorAndTraceEvent(
+ devtools_proxy, "Failed to parse `fallbackUrl`.");
+ return FallbackUrlAndAfter();
}
+ if (!fallback_url.SchemeIs(url::kHttpsScheme)) {
+ signed_exchange_utils::ReportErrorAndTraceEvent(
+ devtools_proxy, "`fallbackUrl` in non-https scheme.");
+ return FallbackUrlAndAfter();
+ }
+ if (fallback_url.has_ref()) {
+ signed_exchange_utils::ReportErrorAndTraceEvent(
+ devtools_proxy, ":url can't have a fragment.");
+ return FallbackUrlAndAfter();
+ }
+
+ // Note: For the code path after this comment, if parsing failed but
+ // the `fallbackUrl` parse had succeed, the return value can still be
+ // used for fallback redirect.
+
+ if (!before_fallback_url.is_valid())
+ return ParseFailedButFallbackUrlAvailable(fallback_url);
+
+ if (input.size() < before_fallback_url.ComputeFallbackUrlAndAfterLength()) {
+ signed_exchange_utils::ReportErrorAndTraceEvent(
+ devtools_proxy,
+ "End of stream reached before reading `sigLength` and `headerLength` "
+ "fields.");
+ return ParseFailedButFallbackUrlAvailable(fallback_url);
+ }
+
+ const auto encoded_signature_header_field_length = input.subspan(
+ before_fallback_url.fallback_url_length(), kSigLengthFieldLengthInBytes);
+ const auto encoded_cbor_header_length = input.subspan(
+ before_fallback_url.fallback_url_length() + kSigLengthFieldLengthInBytes,
+ kHeaderLengthFieldLengthInBytes);
size_t signature_header_field_length =
- ParseEncodedLength(encoded_signature_header_field_length);
- size_t cbor_header_length = ParseEncodedLength(encoded_cbor_header_length);
+ Parse3BytesEncodedLength(encoded_signature_header_field_length);
+ size_t cbor_header_length =
+ Parse3BytesEncodedLength(encoded_cbor_header_length);
if (signature_header_field_length > kMaximumSignatureHeaderFieldLength) {
signed_exchange_utils::ReportErrorAndTraceEvent(
devtools_proxy,
base::StringPrintf("Signature header field too long: %zu",
signature_header_field_length));
- return base::nullopt;
+ return ParseFailedButFallbackUrlAvailable(fallback_url);
}
if (cbor_header_length > kMaximumCBORHeaderLength) {
signed_exchange_utils::ReportErrorAndTraceEvent(
devtools_proxy,
base::StringPrintf("CBOR header too long: %zu", cbor_header_length));
- return base::nullopt;
+ return ParseFailedButFallbackUrlAvailable(fallback_url);
}
- return SignedExchangePrologue(signature_header_field_length,
- cbor_header_length);
+ return FallbackUrlAndAfter(true, fallback_url, signature_header_field_length,
+ cbor_header_length);
}
-size_t SignedExchangePrologue::ComputeFollowingSectionsLength() const {
+size_t FallbackUrlAndAfter::signature_header_field_length() const {
+ DCHECK(is_valid());
+ return signature_header_field_length_;
+}
+
+size_t FallbackUrlAndAfter::cbor_header_length() const {
+ DCHECK(is_valid());
+ return cbor_header_length_;
+}
+
+size_t FallbackUrlAndAfter::ComputeFollowingSectionsLength() const {
+ DCHECK(is_valid());
return signature_header_field_length_ + cbor_header_length_;
}
+} // namespace signed_exchange_prologue
+
} // namespace content
diff --git a/chromium/content/browser/web_package/signed_exchange_prologue.h b/chromium/content/browser/web_package/signed_exchange_prologue.h
index 2106d417e42..1414e718cb1 100644
--- a/chromium/content/browser/web_package/signed_exchange_prologue.h
+++ b/chromium/content/browser/web_package/signed_exchange_prologue.h
@@ -11,64 +11,129 @@
#include "base/gtest_prod_util.h"
#include "base/optional.h"
#include "content/common/content_export.h"
+#include "url/gurl.h"
namespace content {
class SignedExchangeDevToolsProxy;
-// SignedExchangePrologue maps to the first bytes of
-// the "application/signed-exchange" format.
-// SignedExchangePrologue derives the lengths of the variable-length sections
-// following the prologue bytes.
-class CONTENT_EXPORT SignedExchangePrologue {
+// signed_exchange_prologue namespace contains parsers for the first bytes of
+// the "application/signed-exchange" format, preceding the cbor-encoded
+// response header.
+namespace signed_exchange_prologue {
+
+// Parse 2-byte encoded length of the variable-length field in the signed
+// exchange. Note: |input| must be pointing to a valid memory address that has
+// at least 2 bytes.
+CONTENT_EXPORT size_t Parse2BytesEncodedLength(base::span<const uint8_t> input);
+
+// Parse 3-byte encoded length of the variable-length field in the signed
+// exchange. Note: |input| must be pointing to a valid memory address that has
+// at least 3 bytes.
+CONTENT_EXPORT size_t Parse3BytesEncodedLength(base::span<const uint8_t> input);
+
+// BeforeFallbackUrl holds the decoded data from the first
+// |BeforeFallbackUrl::kEncodedSizeInBytes| bytes of the
+// "application/signed-exchange" format.
+class CONTENT_EXPORT BeforeFallbackUrl {
public:
- // Parse encoded length of the variable-length field in the signed exchange.
- // Note: |input| must be pointing to a valid memory address that has at least
- // |kEncodedLengthInBytes|.
- static size_t ParseEncodedLength(base::span<const uint8_t> input);
-
- // Size of the prologue bytes of the "application/signed-exchange" format
- // which maps to this class.
- static size_t kEncodedPrologueInBytes;
-
- // Parses the first bytes of the "application/signed-exchange" format.
- // |input| must be a valid span with length of kEncodedPrologueInBytes.
- // If success, returns the result. Otherwise, returns nullopt and
- // reports the error to |devtools_proxy|.
- static base::Optional<SignedExchangePrologue> Parse(
- base::span<const uint8_t> input,
- SignedExchangeDevToolsProxy* devtools_proxy);
-
- SignedExchangePrologue(size_t signature_header_field_length,
- size_t cbor_header_length)
- : signature_header_field_length_(signature_header_field_length),
- cbor_header_length_(cbor_header_length) {}
- SignedExchangePrologue(const SignedExchangePrologue&) = default;
- ~SignedExchangePrologue() = default;
+ // Size of the BeforeFallbackUrl part of "application/signed-exchange"
+ // prologue.
+ static const size_t kEncodedSizeInBytes;
+
+ BeforeFallbackUrl() = default;
+ BeforeFallbackUrl(bool is_valid, size_t fallback_url_length)
+ : is_valid_(is_valid), fallback_url_length_(fallback_url_length) {}
+ BeforeFallbackUrl(const BeforeFallbackUrl&) = default;
+ ~BeforeFallbackUrl() = default;
+
+ // Parses the first |kEncodedSizeInBytes| bytes of the
+ // "application/signed-exchange" format.
+ // |input| must be a valid span with length of |kEncodedSizeInBytes|.
+ // If success, returns a |is_valid()| result.
+ // Otherwise, returns a |!is_valid()| result and report the error to
+ // |devtools_proxy|.
+ static BeforeFallbackUrl Parse(base::span<const uint8_t> input,
+ SignedExchangeDevToolsProxy* devtools_proxy);
+
+ size_t ComputeFallbackUrlAndAfterLength() const;
+
+ // |is_valid()| returns false if magic string was invalid.
+ bool is_valid() const { return is_valid_; }
- size_t signature_header_field_length() const {
- return signature_header_field_length_;
- }
- size_t cbor_header_length() const { return cbor_header_length_; }
+ size_t fallback_url_length() const { return fallback_url_length_; }
+
+ private:
+ bool is_valid_ = false;
+
+ // Corresponds to `fallbackUrlLength` in the spec text.
+ // Encoded length of the Signature header field's value.
+ // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#application-signed-exchange
+ size_t fallback_url_length_ = 0;
+};
+
+class CONTENT_EXPORT FallbackUrlAndAfter {
+ public:
+ FallbackUrlAndAfter() = default;
+ FallbackUrlAndAfter(const FallbackUrlAndAfter&) = default;
+ ~FallbackUrlAndAfter() = default;
+
+ // Parses the bytes of the "application/signed-exchange" format,
+ // proceeding the BeforeFallbackUrl bytes.
+ // |input| must be a valid span with length of
+ // |before_fallback_url.ComputeFallbackUrlAndAfterLength()|.
+ // If success, returns a |is_valid()| result.
+ // Otherwise, returns a |!is_valid()| result and report the error to
+ // |devtools_proxy|.
+ static FallbackUrlAndAfter Parse(base::span<const uint8_t> input,
+ const BeforeFallbackUrl& before_fallback_url,
+ SignedExchangeDevToolsProxy* devtools_proxy);
+
+ bool is_valid() const { return is_valid_; }
+
+ // Note: fallback_url() may still be called even if |!is_valid()|,
+ // for trigering fallback redirect.
+ const GURL& fallback_url() const { return fallback_url_; }
+
+ size_t signature_header_field_length() const;
+ size_t cbor_header_length() const;
size_t ComputeFollowingSectionsLength() const;
private:
- FRIEND_TEST_ALL_PREFIXES(SignedExchangePrologueTest, ParseEncodedLength);
+ static FallbackUrlAndAfter ParseFailedButFallbackUrlAvailable(
+ GURL fallback_url);
+
+ FallbackUrlAndAfter(bool is_valid,
+ GURL fallback_url,
+ size_t signature_header_field_length,
+ size_t cbor_header_length)
+ : is_valid_(is_valid),
+ fallback_url_(std::move(fallback_url)),
+ signature_header_field_length_(signature_header_field_length),
+ cbor_header_length_(cbor_header_length) {}
+
+ bool is_valid_ = false;
- static constexpr size_t kEncodedLengthInBytes = 3;
+ // Corresponds to `fallbackUrl` in the spec text.
+ // The URL to redirect navigation to when the signed exchange processing steps
+ // has failed.
+ // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#application-signed-exchange
+ GURL fallback_url_;
// Corresponds to `sigLength` in the spec text.
// Encoded length of the Signature header field's value.
// https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#application-signed-exchange
- size_t signature_header_field_length_;
+ size_t signature_header_field_length_ = 0;
// Corresponds to `headerLength` in the spec text.
// Length of the CBOR representation of the request and response headers.
// https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#application-signed-exchange
- size_t cbor_header_length_;
+ size_t cbor_header_length_ = 0;
};
+} // namespace signed_exchange_prologue
+
} // namespace content
#endif // CONTENT_BROWSER_WEB_PACKAGE_SIGNED_EXCHANGE_PROLOGUE_H_
diff --git a/chromium/content/browser/web_package/signed_exchange_prologue_unittest.cc b/chromium/content/browser/web_package/signed_exchange_prologue_unittest.cc
index befb942e039..03febaea9d9 100644
--- a/chromium/content/browser/web_package/signed_exchange_prologue_unittest.cc
+++ b/chromium/content/browser/web_package/signed_exchange_prologue_unittest.cc
@@ -7,10 +7,26 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
+namespace signed_exchange_prologue {
-TEST(SignedExchangePrologueTest, ParseEncodedLength) {
+TEST(SignedExchangePrologueTest, Parse2BytesEncodedLength) {
constexpr struct {
- uint8_t bytes[SignedExchangePrologue::kEncodedLengthInBytes];
+ uint8_t bytes[2];
+ size_t expected;
+ } kTestCases[] = {
+ {{0x00, 0x01}, 1u}, {{0xab, 0xcd}, 43981u},
+ };
+
+ int test_element_index = 0;
+ for (const auto& test_case : kTestCases) {
+ SCOPED_TRACE(testing::Message() << "testing case " << test_element_index++);
+ EXPECT_EQ(Parse2BytesEncodedLength(test_case.bytes), test_case.expected);
+ }
+}
+
+TEST(SignedExchangePrologueTest, Parse3BytesEncodedLength) {
+ constexpr struct {
+ uint8_t bytes[3];
size_t expected;
} kTestCases[] = {
{{0x00, 0x00, 0x01}, 1u}, {{0x01, 0xe2, 0x40}, 123456u},
@@ -19,45 +35,109 @@ TEST(SignedExchangePrologueTest, ParseEncodedLength) {
int test_element_index = 0;
for (const auto& test_case : kTestCases) {
SCOPED_TRACE(testing::Message() << "testing case " << test_element_index++);
- EXPECT_EQ(SignedExchangePrologue::ParseEncodedLength(test_case.bytes),
- test_case.expected);
+ EXPECT_EQ(Parse3BytesEncodedLength(test_case.bytes), test_case.expected);
}
}
-TEST(SignedExchangePrologueTest, Simple) {
- uint8_t bytes[] = {'s', 'x', 'g', '1', '-', 'b', '1',
- '\0', 0x00, 0x12, 0x34, 0x00, 0x23, 0x45};
+TEST(SignedExchangePrologueTest, BeforeFallbackUrl_Success) {
+ uint8_t bytes[] = {'s', 'x', 'g', '1', '-', 'b', '2', '\0', 0x12, 0x34};
+
+ BeforeFallbackUrl before_fallback_url = BeforeFallbackUrl::Parse(
+ base::make_span(bytes), nullptr /* devtools_proxy */);
+ EXPECT_TRUE(before_fallback_url.is_valid());
+ EXPECT_EQ(0x1234u, before_fallback_url.fallback_url_length());
+}
+
+TEST(SignedExchangePrologueTest, BeforeFallbackUrl_WrongMagic) {
+ uint8_t bytes[] = {'s', 'x', 'g', '!', '-', 'b', '2', '\0', 0x12, 0x34};
- auto prologue = SignedExchangePrologue::Parse(base::make_span(bytes),
- nullptr /* devtools_proxy */);
- EXPECT_TRUE(prologue);
- EXPECT_EQ(0x1234u, prologue->signature_header_field_length());
- EXPECT_EQ(0x2345u, prologue->cbor_header_length());
- EXPECT_EQ(0x3579u, prologue->ComputeFollowingSectionsLength());
+ BeforeFallbackUrl before_fallback_url = BeforeFallbackUrl::Parse(
+ base::make_span(bytes), nullptr /* devtools_proxy */);
+ EXPECT_FALSE(before_fallback_url.is_valid());
+ EXPECT_EQ(0x1234u, before_fallback_url.fallback_url_length());
}
-TEST(SignedExchangePrologueTest, WrongMagic) {
- uint8_t bytes[] = {'s', 'x', 'g', '!', '-', 'b', '1',
- '\0', 0x00, 0x12, 0x34, 0x00, 0x23, 0x45};
+TEST(SignedExchangePrologueTest, FallbackUrlAndAfter_Success) {
+ uint8_t bytes[] = {'h', 't', 't', 'p', 's', ':', '/', '/', 'e',
+ 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o',
+ 'm', '/', 0x00, 0x12, 0x34, 0x00, 0x23, 0x45};
+
+ BeforeFallbackUrl before_fallback_url(true,
+ sizeof("https://example.com/") - 1);
+ EXPECT_TRUE(before_fallback_url.is_valid());
- EXPECT_FALSE(SignedExchangePrologue::Parse(base::make_span(bytes),
- nullptr /* devtools_proxy */));
+ FallbackUrlAndAfter fallback_url_and_after =
+ FallbackUrlAndAfter::Parse(base::make_span(bytes), before_fallback_url,
+ nullptr /* devtools_proxy */);
+
+ EXPECT_TRUE(fallback_url_and_after.is_valid());
+ EXPECT_EQ("https://example.com/",
+ fallback_url_and_after.fallback_url().spec());
+ EXPECT_EQ(0x1234u, fallback_url_and_after.signature_header_field_length());
+ EXPECT_EQ(0x2345u, fallback_url_and_after.cbor_header_length());
}
-TEST(SignedExchangePrologueTest, LongSignatureHeaderField) {
- uint8_t bytes[] = {'s', 'x', 'g', '1', '-', 'b', '1',
- '\0', 0xff, 0x12, 0x34, 0x00, 0x23, 0x45};
+TEST(SignedExchangePrologueTest, FallbackUrlAndAfter_NonHttpsUrl) {
+ uint8_t bytes[] = {'h', 't', 't', 'p', ':', '/', '/', 'e', 'x',
+ 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm',
+ '/', 0x00, 0x12, 0x34, 0x00, 0x23, 0x45};
+
+ BeforeFallbackUrl before_fallback_url(true,
+ sizeof("http://example.com/") - 1);
+ FallbackUrlAndAfter fallback_url_and_after =
+ FallbackUrlAndAfter::Parse(base::make_span(bytes), before_fallback_url,
+ nullptr /* devtools_proxy */);
- EXPECT_FALSE(SignedExchangePrologue::Parse(base::make_span(bytes),
- nullptr /* devtools_proxy */));
+ EXPECT_FALSE(fallback_url_and_after.is_valid());
+ EXPECT_FALSE(fallback_url_and_after.fallback_url().is_valid());
}
-TEST(SignedExchangePrologueTest, LongCBORHeader) {
- uint8_t bytes[] = {'s', 'x', 'g', '1', '-', 'b', '1',
- '\0', 0x00, 0x12, 0x34, 0xff, 0x23, 0x45};
+TEST(SignedExchangePrologueTest, FallbackUrlAndAfter_UrlWithFragment) {
+ uint8_t bytes[] = {'h', 't', 't', 'p', 's', ':', '/', '/', 'e', 'x',
+ 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm', '/',
+ '#', 'f', 'o', 'o', 0x00, 0x12, 0x34, 0x00, 0x23, 0x45};
+
+ BeforeFallbackUrl before_fallback_url(true,
+ sizeof("https://example.com/#foo") - 1);
+ FallbackUrlAndAfter fallback_url_and_after =
+ FallbackUrlAndAfter::Parse(base::make_span(bytes), before_fallback_url,
+ nullptr /* devtools_proxy */);
+
+ EXPECT_FALSE(fallback_url_and_after.is_valid());
+ EXPECT_FALSE(fallback_url_and_after.fallback_url().is_valid());
+}
+
+TEST(SignedExchangePrologueTest, FallbackUrlAndAfter_LongSignatureHeader) {
+ uint8_t bytes[] = {'h', 't', 't', 'p', 's', ':', '/', '/', 'e',
+ 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o',
+ 'm', '/', 0xff, 0x12, 0x34, 0x00, 0x23, 0x45};
+
+ BeforeFallbackUrl before_fallback_url(true,
+ sizeof("https://example.com/") - 1);
+ FallbackUrlAndAfter fallback_url_and_after =
+ FallbackUrlAndAfter::Parse(base::make_span(bytes), before_fallback_url,
+ nullptr /* devtools_proxy */);
+
+ EXPECT_FALSE(fallback_url_and_after.is_valid());
+ EXPECT_EQ("https://example.com/",
+ fallback_url_and_after.fallback_url().spec());
+}
+
+TEST(SignedExchangePrologueTest, FallbackUrlAndAfter_LongCBORHeader) {
+ uint8_t bytes[] = {'h', 't', 't', 'p', 's', ':', '/', '/', 'e',
+ 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o',
+ 'm', '/', 0x00, 0x12, 0x34, 0xff, 0x23, 0x45};
+
+ BeforeFallbackUrl before_fallback_url(true,
+ sizeof("https://example.com/") - 1);
+ FallbackUrlAndAfter fallback_url_and_after =
+ FallbackUrlAndAfter::Parse(base::make_span(bytes), before_fallback_url,
+ nullptr /* devtools_proxy */);
- EXPECT_FALSE(SignedExchangePrologue::Parse(base::make_span(bytes),
- nullptr /* devtools_proxy */));
+ EXPECT_FALSE(fallback_url_and_after.is_valid());
+ EXPECT_EQ("https://example.com/",
+ fallback_url_and_after.fallback_url().spec());
}
+} // namespace signed_exchange_prologue
} // namespace content
diff --git a/chromium/content/browser/web_package/signed_exchange_request_handler.cc b/chromium/content/browser/web_package/signed_exchange_request_handler.cc
index e5d33126395..97e0b1e0765 100644
--- a/chromium/content/browser/web_package/signed_exchange_request_handler.cc
+++ b/chromium/content/browser/web_package/signed_exchange_request_handler.cc
@@ -15,7 +15,6 @@
#include "content/public/common/content_features.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "net/http/http_response_headers.h"
-#include "net/url_request/url_request_context_getter.h"
#include "services/network/public/cpp/resource_response.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/mojom/url_loader.mojom.h"
@@ -39,8 +38,7 @@ SignedExchangeRequestHandler::SignedExchangeRequestHandler(
bool report_raw_headers,
int load_flags,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
- URLLoaderThrottlesGetter url_loader_throttles_getter,
- scoped_refptr<net::URLRequestContextGetter> request_context_getter)
+ URLLoaderThrottlesGetter url_loader_throttles_getter)
: request_initiator_(std::move(request_initiator)),
url_(url),
url_loader_options_(url_loader_options),
@@ -51,7 +49,6 @@ SignedExchangeRequestHandler::SignedExchangeRequestHandler(
load_flags_(load_flags),
url_loader_factory_(url_loader_factory),
url_loader_throttles_getter_(std::move(url_loader_throttles_getter)),
- request_context_getter_(std::move(request_context_getter)),
weak_factory_(this) {
DCHECK(signed_exchange_utils::IsSignedExchangeHandlingEnabled());
}
@@ -59,17 +56,19 @@ SignedExchangeRequestHandler::SignedExchangeRequestHandler(
SignedExchangeRequestHandler::~SignedExchangeRequestHandler() = default;
void SignedExchangeRequestHandler::MaybeCreateLoader(
- const network::ResourceRequest& resource_request,
+ const network::ResourceRequest& /* tentative_resource_request */,
ResourceContext* resource_context,
- LoaderCallback callback) {
- // TODO(https://crbug.com/803774): Ask WebPackageFetchManager to get the
- // ongoing matching SignedExchangeHandler which was created by a
- // WebPackagePrefetcher.
-
+ LoaderCallback callback,
+ FallbackCallback fallback_callback) {
if (!signed_exchange_loader_) {
std::move(callback).Run({});
return;
}
+ if (signed_exchange_loader_->HasRedirectedToFallbackURL()) {
+ signed_exchange_loader_ = nullptr;
+ std::move(callback).Run({});
+ return;
+ }
std::move(callback).Run(
base::BindOnce(&SignedExchangeRequestHandler::StartResponse,
@@ -81,6 +80,7 @@ bool SignedExchangeRequestHandler::MaybeCreateLoaderForResponse(
network::mojom::URLLoaderPtr* loader,
network::mojom::URLLoaderClientRequest* client_request,
ThrottlingURLLoader* url_loader) {
+ DCHECK(!signed_exchange_loader_);
if (!signed_exchange_utils::ShouldHandleAsSignedHTTPExchange(
request_initiator_.GetURL(), response)) {
return false;
@@ -89,23 +89,26 @@ bool SignedExchangeRequestHandler::MaybeCreateLoaderForResponse(
network::mojom::URLLoaderClientPtr client;
*client_request = mojo::MakeRequest(&client);
- // TODO(https://crbug.com/803774): Consider creating a new ThrottlingURLLoader
- // or reusing the existing ThrottlingURLLoader by reattaching URLLoaderClient,
- // to support SafeBrowsing checking of the content of the WebPackage.
+ // This lets the SignedExchangeLoader directly returns an artificial redirect
+ // to the downstream client without going through ThrottlingURLLoader, which
+ // means some checks like SafeBrowsing may not see the redirect. Given that
+ // the redirected request will be checked when it's restarted we suppose
+ // this is fine.
signed_exchange_loader_ = std::make_unique<SignedExchangeLoader>(
url_, response, std::move(client), url_loader->Unbind(),
- std::move(request_initiator_), url_loader_options_, load_flags_,
- throttling_profile_id_,
+ request_initiator_, url_loader_options_, load_flags_,
+ true /* should_redirect_to_fallback */, throttling_profile_id_,
std::make_unique<SignedExchangeDevToolsProxy>(
url_, response,
base::BindRepeating([](int id) { return id; }, frame_tree_node_id_),
- std::move(devtools_navigation_token_), report_raw_headers_),
- std::move(url_loader_factory_), std::move(url_loader_throttles_getter_),
- std::move(request_context_getter_));
+ devtools_navigation_token_, report_raw_headers_),
+ url_loader_factory_, url_loader_throttles_getter_,
+ base::BindRepeating([](int id) { return id; }, frame_tree_node_id_));
return true;
}
void SignedExchangeRequestHandler::StartResponse(
+ const network::ResourceRequest& resource_request,
network::mojom::URLLoaderRequest request,
network::mojom::URLLoaderClientPtr client) {
signed_exchange_loader_->ConnectToClient(std::move(client));
diff --git a/chromium/content/browser/web_package/signed_exchange_request_handler.h b/chromium/content/browser/web_package/signed_exchange_request_handler.h
index 02fbd7af3d5..b0037c69d84 100644
--- a/chromium/content/browser/web_package/signed_exchange_request_handler.h
+++ b/chromium/content/browser/web_package/signed_exchange_request_handler.h
@@ -12,10 +12,6 @@
#include "content/public/common/resource_type.h"
#include "url/origin.h"
-namespace net {
-class URLRequestContextGetter;
-} // namespace net
-
namespace network {
class SharedURLLoaderFactory;
} // namespace network
@@ -42,14 +38,15 @@ class SignedExchangeRequestHandler final : public NavigationLoaderInterceptor {
bool report_raw_headers,
int load_flags,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
- URLLoaderThrottlesGetter url_loader_throttles_getter,
- scoped_refptr<net::URLRequestContextGetter> request_context_getter);
+ URLLoaderThrottlesGetter url_loader_throttles_getter);
~SignedExchangeRequestHandler() override;
// NavigationLoaderInterceptor implementation
- void MaybeCreateLoader(const network::ResourceRequest& resource_request,
- ResourceContext* resource_context,
- LoaderCallback callback) override;
+ void MaybeCreateLoader(
+ const network::ResourceRequest& tentative_resource_request,
+ ResourceContext* resource_context,
+ LoaderCallback callback,
+ FallbackCallback fallback_callback) override;
bool MaybeCreateLoaderForResponse(
const network::ResourceResponseHead& response,
network::mojom::URLLoaderPtr* loader,
@@ -57,7 +54,8 @@ class SignedExchangeRequestHandler final : public NavigationLoaderInterceptor {
ThrottlingURLLoader* url_loader) override;
private:
- void StartResponse(network::mojom::URLLoaderRequest request,
+ void StartResponse(const network::ResourceRequest& resource_request,
+ network::mojom::URLLoaderRequest request,
network::mojom::URLLoaderClientPtr client);
// Valid after MaybeCreateLoaderForResponse intercepts the request and until
@@ -75,7 +73,6 @@ class SignedExchangeRequestHandler final : public NavigationLoaderInterceptor {
const int load_flags_;
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
URLLoaderThrottlesGetter url_loader_throttles_getter_;
- scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
base::WeakPtrFactory<SignedExchangeRequestHandler> weak_factory_;
diff --git a/chromium/content/browser/web_package/signed_exchange_request_handler_browsertest.cc b/chromium/content/browser/web_package/signed_exchange_request_handler_browsertest.cc
index a2251cab8ce..03a54596795 100644
--- a/chromium/content/browser/web_package/signed_exchange_request_handler_browsertest.cc
+++ b/chromium/content/browser/web_package/signed_exchange_request_handler_browsertest.cc
@@ -21,8 +21,8 @@
#include "content/public/common/content_paths.h"
#include "content/public/common/page_type.h"
#include "content/public/test/browser_test_utils.h"
-#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/content_cert_verifier_browser_test.h"
#include "content/public/test/test_navigation_throttle.h"
#include "content/public/test/url_loader_interceptor.h"
#include "content/shell/browser/shell.h"
@@ -44,38 +44,31 @@ namespace {
const uint64_t kSignatureHeaderDate = 1520834000; // 2018-03-12T05:53:20Z
-class NavigationFailureObserver : public WebContentsObserver {
+class RedirectObserver : public WebContentsObserver {
public:
- explicit NavigationFailureObserver(WebContents* web_contents)
+ explicit RedirectObserver(WebContents* web_contents)
: WebContentsObserver(web_contents) {}
- ~NavigationFailureObserver() override = default;
-
- void DidStartNavigation(NavigationHandle* handle) override {
- auto throttle = std::make_unique<TestNavigationThrottle>(handle);
- throttle->SetCallback(
- TestNavigationThrottle::WILL_FAIL_REQUEST,
- base::BindRepeating(&NavigationFailureObserver::OnWillFailRequestCalled,
- base::Unretained(this)));
- handle->RegisterThrottleForTesting(
- std::unique_ptr<TestNavigationThrottle>(std::move(throttle)));
+ ~RedirectObserver() override = default;
+
+ void DidRedirectNavigation(NavigationHandle* handle) override {
+ const net::HttpResponseHeaders* response = handle->GetResponseHeaders();
+ if (response)
+ response_code_ = response->response_code();
}
- bool did_fail() const { return did_fail_; }
+ const base::Optional<int>& response_code() const { return response_code_; }
private:
- void OnWillFailRequestCalled() { did_fail_ = true; }
-
- bool did_fail_ = false;
+ base::Optional<int> response_code_;
- DISALLOW_COPY_AND_ASSIGN(NavigationFailureObserver);
+ DISALLOW_COPY_AND_ASSIGN(RedirectObserver);
};
} // namespace
-class SignedExchangeRequestHandlerBrowserTest : public ContentBrowserTest {
+class SignedExchangeRequestHandlerBrowserTest : public CertVerifierBrowserTest {
public:
- SignedExchangeRequestHandlerBrowserTest()
- : mock_cert_verifier_(std::make_unique<net::MockCertVerifier>()) {
+ SignedExchangeRequestHandlerBrowserTest() {
// This installs "root_ca_cert.pem" from which our test certificates are
// created. (Needed for the tests that use real certificate, i.e.
// RealCertVerifier)
@@ -83,25 +76,22 @@ class SignedExchangeRequestHandlerBrowserTest : public ContentBrowserTest {
}
void SetUp() override {
- SignedExchangeHandler::SetCertVerifierForTesting(mock_cert_verifier_.get());
SignedExchangeHandler::SetVerificationTimeForTesting(
base::Time::UnixEpoch() +
base::TimeDelta::FromSeconds(kSignatureHeaderDate));
SetUpFeatures();
- ContentBrowserTest::SetUp();
+ CertVerifierBrowserTest::SetUp();
}
void TearDownOnMainThread() override {
interceptor_.reset();
- SignedExchangeHandler::SetCertVerifierForTesting(nullptr);
SignedExchangeHandler::SetVerificationTimeForTesting(
base::Optional<base::Time>());
}
protected:
virtual void SetUpFeatures() {
- feature_list_.InitWithFeatures({features::kSignedHTTPExchange},
- {network::features::kNetworkService});
+ feature_list_.InitWithFeatures({features::kSignedHTTPExchange}, {});
}
static scoped_refptr<net::X509Certificate> LoadCertificate(
@@ -132,12 +122,10 @@ class SignedExchangeRequestHandlerBrowserTest : public ContentBrowserTest {
}
base::test::ScopedFeatureList feature_list_;
- std::unique_ptr<net::MockCertVerifier> mock_cert_verifier_;
private:
static void InstallMockInterceptors(const GURL& url,
const std::string& data_path) {
- DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
base::FilePath root_path;
CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &root_path));
net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
@@ -146,7 +134,6 @@ class SignedExchangeRequestHandlerBrowserTest : public ContentBrowserTest {
}
bool OnInterceptCallback(URLLoaderInterceptor::RequestParams* params) {
- DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService));
const auto it = interceptor_data_path_map_.find(params->url_request.url);
if (it == interceptor_data_path_map_.end())
return false;
@@ -160,15 +147,6 @@ class SignedExchangeRequestHandlerBrowserTest : public ContentBrowserTest {
DISALLOW_COPY_AND_ASSIGN(SignedExchangeRequestHandlerBrowserTest);
};
-class SignedExchangeRequestHandlerWithNetworkServiceBrowserTest
- : public SignedExchangeRequestHandlerBrowserTest {
- void SetUpFeatures() override {
- feature_list_.InitWithFeatures(
- {features::kSignedHTTPExchange, network::features::kNetworkService},
- {});
- }
-};
-
IN_PROC_BROWSER_TEST_F(SignedExchangeRequestHandlerBrowserTest, Simple) {
InstallUrlInterceptor(
GURL("https://cert.example.org/cert.msg"),
@@ -183,7 +161,7 @@ IN_PROC_BROWSER_TEST_F(SignedExchangeRequestHandlerBrowserTest, Simple) {
dummy_result.cert_status = net::OK;
dummy_result.ocsp_result.response_status = net::OCSPVerifyResult::PROVIDED;
dummy_result.ocsp_result.revocation_status = net::OCSPRevocationStatus::GOOD;
- mock_cert_verifier_->AddResultForCertAndHost(
+ mock_cert_verifier()->AddResultForCertAndHost(
original_cert, "test.example.org", dummy_result, net::OK);
embedded_test_server()->RegisterRequestMonitor(
@@ -191,7 +169,7 @@ IN_PROC_BROWSER_TEST_F(SignedExchangeRequestHandlerBrowserTest, Simple) {
if (request.relative_url == "/sxg/test.example.org_test.sxg") {
const auto& accept_value = request.headers.find("accept")->second;
EXPECT_THAT(accept_value,
- ::testing::HasSubstr("application/signed-exchange;v=b1"));
+ ::testing::HasSubstr("application/signed-exchange;v=b2"));
}
}));
embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data");
@@ -199,8 +177,11 @@ IN_PROC_BROWSER_TEST_F(SignedExchangeRequestHandlerBrowserTest, Simple) {
GURL url = embedded_test_server()->GetURL("/sxg/test.example.org_test.sxg");
base::string16 title = base::ASCIIToUTF16("https://test.example.org/test/");
TitleWatcher title_watcher(shell()->web_contents(), title);
+ RedirectObserver redirect_observer(shell()->web_contents());
+
NavigateToURL(shell(), url);
EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
+ EXPECT_EQ(303, redirect_observer.response_code());
NavigationEntry* entry =
shell()->web_contents()->GetController().GetVisibleEntry();
@@ -226,6 +207,8 @@ IN_PROC_BROWSER_TEST_F(SignedExchangeRequestHandlerBrowserTest,
InstallUrlInterceptor(
GURL("https://cert.example.org/cert.msg"),
"content/test/data/sxg/test.example.org.public.pem.cbor");
+ InstallUrlInterceptor(GURL("https://test.example.org/test/"),
+ "content/test/data/sxg/fallback.html");
// Make the MockCertVerifier treat the certificate
// "prime256v1-sha256.public.pem" as valid for "test.example.org".
@@ -236,7 +219,7 @@ IN_PROC_BROWSER_TEST_F(SignedExchangeRequestHandlerBrowserTest,
dummy_result.cert_status = net::OK;
dummy_result.ocsp_result.response_status = net::OCSPVerifyResult::PROVIDED;
dummy_result.ocsp_result.revocation_status = net::OCSPRevocationStatus::GOOD;
- mock_cert_verifier_->AddResultForCertAndHost(
+ mock_cert_verifier()->AddResultForCertAndHost(
original_cert, "test.example.org", dummy_result, net::OK);
embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data");
@@ -244,76 +227,79 @@ IN_PROC_BROWSER_TEST_F(SignedExchangeRequestHandlerBrowserTest,
GURL url = embedded_test_server()->GetURL(
"/sxg/test.example.org_test_invalid_content_type.sxg");
- NavigationFailureObserver failure_observer(shell()->web_contents());
+ base::string16 title = base::ASCIIToUTF16("Fallback URL response");
+ TitleWatcher title_watcher(shell()->web_contents(), title);
+ RedirectObserver redirect_observer(shell()->web_contents());
NavigateToURL(shell(), url);
- EXPECT_TRUE(failure_observer.did_fail());
- NavigationEntry* entry =
- shell()->web_contents()->GetController().GetVisibleEntry();
- EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
+ EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
+ EXPECT_EQ(303, redirect_observer.response_code());
}
-IN_PROC_BROWSER_TEST_F(SignedExchangeRequestHandlerBrowserTest, CertNotFound) {
- InstallUrlInterceptor(GURL("https://cert.example.org/cert.msg"),
- "content/test/data/sxg/404.msg");
+IN_PROC_BROWSER_TEST_F(SignedExchangeRequestHandlerBrowserTest,
+ RedirectBrokenSignedExchanges) {
+ InstallUrlInterceptor(GURL("https://test.example.org/test/"),
+ "content/test/data/sxg/fallback.html");
embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data");
ASSERT_TRUE(embedded_test_server()->Start());
- GURL url = embedded_test_server()->GetURL("/sxg/test.example.org_test.sxg");
- NavigationFailureObserver failure_observer(shell()->web_contents());
- NavigateToURL(shell(), url);
- EXPECT_TRUE(failure_observer.did_fail());
- NavigationEntry* entry =
- shell()->web_contents()->GetController().GetVisibleEntry();
- EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
-}
+ constexpr const char* kBrokenExchanges[] = {
+ "/sxg/test.example.org_test_invalid_magic_string.sxg",
+ "/sxg/test.example.org_test_invalid_cbor_header.sxg",
+ };
-IN_PROC_BROWSER_TEST_F(
- SignedExchangeRequestHandlerWithNetworkServiceBrowserTest,
- NetworkServiceEnabled) {
- InstallUrlInterceptor(
- GURL("https://test.example.org/cert.msg"),
- "content/test/data/sxg/test.example.org.public.pem.cbor");
+ for (const auto* broken_exchange : kBrokenExchanges) {
+ SCOPED_TRACE(testing::Message()
+ << "testing broken exchange: " << broken_exchange);
- // Make the MockCertVerifier treat the certificate
- // "prime256v1-sha256.public.pem" as valid for "test.example.org".
- scoped_refptr<net::X509Certificate> original_cert =
- LoadCertificate("prime256v1-sha256.public.pem");
- net::CertVerifyResult dummy_result;
- dummy_result.verified_cert = original_cert;
- dummy_result.cert_status = net::OK;
- dummy_result.ocsp_result.response_status = net::OCSPVerifyResult::PROVIDED;
- dummy_result.ocsp_result.revocation_status = net::OCSPRevocationStatus::GOOD;
- mock_cert_verifier_->AddResultForCertAndHost(
- original_cert, "test.example.org", dummy_result, net::OK);
+ GURL url = embedded_test_server()->GetURL(broken_exchange);
+
+ base::string16 title = base::ASCIIToUTF16("Fallback URL response");
+ TitleWatcher title_watcher(shell()->web_contents(), title);
+ NavigateToURL(shell(), url);
+ EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
+ }
+}
+
+IN_PROC_BROWSER_TEST_F(SignedExchangeRequestHandlerBrowserTest, CertNotFound) {
+ InstallUrlInterceptor(GURL("https://cert.example.org/cert.msg"),
+ "content/test/data/sxg/404.msg");
+ InstallUrlInterceptor(GURL("https://test.example.org/test/"),
+ "content/test/data/sxg/fallback.html");
embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data");
ASSERT_TRUE(embedded_test_server()->Start());
GURL url = embedded_test_server()->GetURL("/sxg/test.example.org_test.sxg");
- NavigationFailureObserver failure_observer(shell()->web_contents());
+ base::string16 title = base::ASCIIToUTF16("Fallback URL response");
+ TitleWatcher title_watcher(shell()->web_contents(), title);
NavigateToURL(shell(), url);
- EXPECT_TRUE(failure_observer.did_fail());
- NavigationEntry* entry =
- shell()->web_contents()->GetController().GetVisibleEntry();
- EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
+ EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
}
-IN_PROC_BROWSER_TEST_F(SignedExchangeRequestHandlerBrowserTest,
- RealCertVerifier) {
+class SignedExchangeRequestHandlerRealCertVerifierBrowserTest
+ : public SignedExchangeRequestHandlerBrowserTest {
+ public:
+ SignedExchangeRequestHandlerRealCertVerifierBrowserTest() {
+ // Use "real" CertVerifier.
+ disable_mock_cert_verifier();
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(SignedExchangeRequestHandlerRealCertVerifierBrowserTest,
+ Basic) {
InstallUrlInterceptor(
GURL("https://cert.example.org/cert.msg"),
"content/test/data/sxg/test.example.org.public.pem.cbor");
-
- // Use "real" CertVerifier.
- SignedExchangeHandler::SetCertVerifierForTesting(nullptr);
+ InstallUrlInterceptor(GURL("https://test.example.org/test/"),
+ "content/test/data/sxg/fallback.html");
embedded_test_server()->RegisterRequestMonitor(
base::BindRepeating([](const net::test_server::HttpRequest& request) {
if (request.relative_url == "/sxg/test.example.org_test.sxg") {
const auto& accept_value = request.headers.find("accept")->second;
EXPECT_THAT(accept_value,
- ::testing::HasSubstr("application/signed-exchange;v=b1"));
+ ::testing::HasSubstr("application/signed-exchange;v=b2"));
}
}));
embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data");
@@ -330,18 +316,17 @@ IN_PROC_BROWSER_TEST_F(SignedExchangeRequestHandlerBrowserTest,
"*OCSP*");
shell()->web_contents()->SetDelegate(&console_observer);
- NavigationFailureObserver failure_observer(shell()->web_contents());
+ base::string16 title = base::ASCIIToUTF16("Fallback URL response");
+ TitleWatcher title_watcher(shell()->web_contents(), title);
NavigateToURL(shell(), url);
- EXPECT_TRUE(failure_observer.did_fail());
- NavigationEntry* entry =
- shell()->web_contents()->GetController().GetVisibleEntry();
- EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
+ EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
// Verify that it failed at the OCSP check step.
// TODO(https://crbug.com/803774): Find a better way than matching against the
// error message. We can probably make DevToolsProxy derive some context from
// StoragePartition so that we can record and extract the detailed error
// status for testing via that.
+ console_observer.Wait();
EXPECT_TRUE(base::StartsWith(console_observer.message(), "OCSP check failed.",
base::CompareCase::SENSITIVE));
}
diff --git a/chromium/content/browser/web_package/signed_exchange_signature_header_field.cc b/chromium/content/browser/web_package/signed_exchange_signature_header_field.cc
index b7bcef2acae..f6e3cfdeb81 100644
--- a/chromium/content/browser/web_package/signed_exchange_signature_header_field.cc
+++ b/chromium/content/browser/web_package/signed_exchange_signature_header_field.cc
@@ -294,8 +294,8 @@ bool SignedExchangeSignatureHeaderField::GetVersionParamFromContentType(
if (it == parameterised_identifier.params.end()) {
*version_param = base::nullopt;
} else {
- if (it->second == "b1")
- *version_param = SignedExchangeVersion::kB1;
+ if (it->second == "b2")
+ *version_param = SignedExchangeVersion::kB2;
else
return false;
}
diff --git a/chromium/content/browser/web_package/signed_exchange_signature_header_field_unittest.cc b/chromium/content/browser/web_package/signed_exchange_signature_header_field_unittest.cc
index d47655171a9..e34fd133926 100644
--- a/chromium/content/browser/web_package/signed_exchange_signature_header_field_unittest.cc
+++ b/chromium/content/browser/web_package/signed_exchange_signature_header_field_unittest.cc
@@ -300,34 +300,34 @@ TEST_F(SignedExchangeSignatureHeaderFieldTest, VersionParam_EmptyString) {
}
TEST_F(SignedExchangeSignatureHeaderFieldTest, VersionParam_Simple) {
- const char content_type[] = "application/signed-exchange;v=b1";
+ const char content_type[] = "application/signed-exchange;v=b2";
base::Optional<SignedExchangeVersion> version;
EXPECT_TRUE(
SignedExchangeSignatureHeaderField::GetVersionParamFromContentType(
content_type, &version));
ASSERT_TRUE(version);
- EXPECT_EQ(*version, SignedExchangeVersion::kB1);
+ EXPECT_EQ(*version, SignedExchangeVersion::kB2);
}
TEST_F(SignedExchangeSignatureHeaderFieldTest, VersionParam_SimpleWithSpace) {
- const char content_type[] = "application/signed-exchange; v=b1";
+ const char content_type[] = "application/signed-exchange; v=b2";
base::Optional<SignedExchangeVersion> version;
EXPECT_TRUE(
SignedExchangeSignatureHeaderField::GetVersionParamFromContentType(
content_type, &version));
ASSERT_TRUE(version);
- EXPECT_EQ(*version, SignedExchangeVersion::kB1);
+ EXPECT_EQ(*version, SignedExchangeVersion::kB2);
}
TEST_F(SignedExchangeSignatureHeaderFieldTest,
VersionParam_SimpleWithDoublequotes) {
- const char content_type[] = "application/signed-exchange;v=\"b1\"";
+ const char content_type[] = "application/signed-exchange;v=\"b2\"";
base::Optional<SignedExchangeVersion> version;
EXPECT_TRUE(
SignedExchangeSignatureHeaderField::GetVersionParamFromContentType(
content_type, &version));
ASSERT_TRUE(version);
- EXPECT_EQ(*version, SignedExchangeVersion::kB1);
+ EXPECT_EQ(*version, SignedExchangeVersion::kB2);
}
} // namespace content
diff --git a/chromium/content/browser/web_package/signed_exchange_signature_verifier.cc b/chromium/content/browser/web_package/signed_exchange_signature_verifier.cc
index e29e5c8cf49..f19306b6f9a 100644
--- a/chromium/content/browser/web_package/signed_exchange_signature_verifier.cc
+++ b/chromium/content/browser/web_package/signed_exchange_signature_verifier.cc
@@ -4,6 +4,7 @@
#include "content/browser/web_package/signed_exchange_signature_verifier.h"
+#include "base/big_endian.h"
#include "base/containers/span.h"
#include "base/format_macros.h"
#include "base/strings/string_number_conversions.h"
@@ -30,20 +31,20 @@ namespace content {
namespace {
// https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#signature-validity
-// Step 7. "Let message be the concatenation of the following byte strings."
+// Step 5. "Let message be the concatenation of the following byte strings."
constexpr uint8_t kMessageHeader[] =
- // 7.1. "A string that consists of octet 32 (0x20) repeated 64 times."
+ // 5.1. "A string that consists of octet 32 (0x20) repeated 64 times."
// [spec text]
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
- // 7.2. "A context string: the ASCII encoding of "HTTP Exchange 1"." ...
+ // 5.2. "A context string: the ASCII encoding of "HTTP Exchange 1"." ...
// "but implementations of drafts MUST NOT use it and MUST use another
// draft-specific string beginning with "HTTP Exchange 1 " instead."
// [spec text]
- // 7.3. "A single 0 byte which serves as a separator." [spec text]
- "HTTP Exchange 1 b1";
+ // 5.3. "A single 0 byte which serves as a separator." [spec text]
+ "HTTP Exchange 1 b2";
base::Optional<cbor::CBORValue> GenerateCanonicalRequestCBOR(
const SignedExchangeEnvelope& envelope) {
@@ -94,56 +95,6 @@ base::Optional<cbor::CBORValue> GenerateCanonicalExchangeHeadersCBOR(
return cbor::CBORValue(array);
}
-// Generate a CBOR map value as specified in
-// https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#signature-validity
-// Step 7.4.
-base::Optional<cbor::CBORValue> GenerateSignedMessageCBOR(
- const SignedExchangeEnvelope& envelope) {
- auto headers_val = GenerateCanonicalExchangeHeadersCBOR(envelope);
- if (!headers_val)
- return base::nullopt;
-
- // 7.4. "The bytes of the canonical CBOR serialization (Section 3.4) of
- // a CBOR map mapping:" [spec text]
- cbor::CBORValue::MapValue map;
- // 7.4.1. "If cert-sha256 is set: The text string "cert-sha256" to the byte
- // string value of cert-sha256." [spec text]
- if (envelope.signature().cert_sha256.has_value()) {
- map.insert_or_assign(
- cbor::CBORValue(kCertSha256Key),
- cbor::CBORValue(
- base::StringPiece(reinterpret_cast<const char*>(
- envelope.signature().cert_sha256->data),
- sizeof(envelope.signature().cert_sha256->data)),
- cbor::CBORValue::Type::BYTE_STRING));
- }
- // 7.4.2. "The text string "validity-url" to the byte string value of
- // validity-url." [spec text]
- map.insert_or_assign(cbor::CBORValue(kValidityUrlKey),
- cbor::CBORValue(envelope.signature().validity_url.spec(),
- cbor::CBORValue::Type::BYTE_STRING));
- // 7.4.3. "The text string "date" to the integer value of date." [spec text]
- if (!base::IsValueInRangeForNumericType<int64_t>(envelope.signature().date))
- return base::nullopt;
-
- map.insert_or_assign(
- cbor::CBORValue(kDateKey),
- cbor::CBORValue(base::checked_cast<int64_t>(envelope.signature().date)));
- // 7.4.4. "The text string "expires" to the integer value of expires."
- // [spec text]
- if (!base::IsValueInRangeForNumericType<int64_t>(
- envelope.signature().expires))
- return base::nullopt;
-
- map.insert_or_assign(cbor::CBORValue(kExpiresKey),
- cbor::CBORValue(base::checked_cast<int64_t>(
- envelope.signature().expires)));
- // 7.4.5. "The text string "headers" to the CBOR representation
- // (Section 3.2) of exchange's headers." [spec text]
- map.insert_or_assign(cbor::CBORValue(kHeadersKey), std::move(*headers_val));
- return cbor::CBORValue(map);
-}
-
base::Optional<crypto::SignatureVerifier::SignatureAlgorithm>
GetSignatureAlgorithm(scoped_refptr<net::X509Certificate> cert,
SignedExchangeDevToolsProxy* devtools_proxy) {
@@ -217,40 +168,62 @@ std::string HexDump(const std::vector<uint8_t>& msg) {
return output;
}
+void AppendToBuf8BytesBigEndian(std::vector<uint8_t>* buf, uint64_t n) {
+ char encoded[8];
+ base::WriteBigEndian(encoded, n);
+ buf->insert(buf->end(), std::begin(encoded), std::end(encoded));
+}
+
base::Optional<std::vector<uint8_t>> GenerateSignedMessage(
const SignedExchangeEnvelope& envelope) {
TRACE_EVENT_BEGIN0(TRACE_DISABLED_BY_DEFAULT("loading"),
"GenerateSignedMessage");
- // GenerateSignedMessageCBOR corresponds to Step 7.4.
- base::Optional<cbor::CBORValue> cbor_val =
- GenerateSignedMessageCBOR(envelope);
- if (!cbor_val) {
- TRACE_EVENT_END1(TRACE_DISABLED_BY_DEFAULT("loading"),
- "GenerateSignedMessage", "error",
- "GenerateSignedMessageCBOR failed.");
- return base::nullopt;
- }
-
- base::Optional<std::vector<uint8_t>> cbor_message =
- cbor::CBORWriter::Write(*cbor_val);
- if (!cbor_message) {
- TRACE_EVENT_END1(TRACE_DISABLED_BY_DEFAULT("loading"),
- "GenerateSignedMessage", "error",
- "CBORWriter::Write failed.");
- return base::nullopt;
- }
+ const auto signature = envelope.signature();
// https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#signature-validity
- // Step 7. "Let message be the concatenation of the following byte strings."
+ // Step 5. "Let message be the concatenation of the following byte strings."
std::vector<uint8_t> message;
- // see kMessageHeader for Steps 7.1 to 7.3.
- message.reserve(arraysize(kMessageHeader) + cbor_message->size());
+ // see kMessageHeader for Steps 5.1 to 5.3.
message.insert(message.end(), std::begin(kMessageHeader),
std::end(kMessageHeader));
- // 7.4. "The bytes of the canonical CBOR serialization (Section 3.4) of
- // a CBOR map mapping:" [spec text]
- message.insert(message.end(), cbor_message->begin(), cbor_message->end());
+
+ // Step 5.4. "If cert-sha256 is set, a byte holding the value 32 followed by
+ // the 32 bytes of the value of cert-sha256. Otherwise a 0 byte." [spec text]
+ // Note: cert-sha256 must be set for application/signed-exchange envelope
+ // format.
+ message.push_back(32);
+ const auto& cert_sha256 = envelope.signature().cert_sha256.value();
+ message.insert(message.end(), std::begin(cert_sha256.data),
+ std::end(cert_sha256.data));
+
+ // Step 5.5. "The 8-byte big-endian encoding of the length in bytes of
+ // validity-url, followed by the bytes of validity-url." [spec text]
+ const auto& validity_url_spec = signature.validity_url.spec();
+ AppendToBuf8BytesBigEndian(&message, validity_url_spec.size());
+ message.insert(message.end(), std::begin(validity_url_spec),
+ std::end(validity_url_spec));
+
+ // Step 5.6. "The 8-byte big-endian encoding of date." [spec text]
+ AppendToBuf8BytesBigEndian(&message, signature.date);
+
+ // Step 5.7. "The 8-byte big-endian encoding of expires." [spec text]
+ AppendToBuf8BytesBigEndian(&message, signature.expires);
+
+ // Step 5.8. "The 8-byte big-endian encoding of the length in bytes of
+ // requestUrl, followed by the bytes of requestUrl." [spec text]
+ const auto& request_url_spec = envelope.request_url().spec();
+
+ AppendToBuf8BytesBigEndian(&message, request_url_spec.size());
+ message.insert(message.end(), std::begin(request_url_spec),
+ std::end(request_url_spec));
+
+ // Step 5.9. "The 8-byte big-endian encoding of the length in bytes of
+ // headers, followed by the bytes of headers." [spec text]
+ AppendToBuf8BytesBigEndian(&message, envelope.cbor_header().size());
+ message.insert(message.end(), envelope.cbor_header().begin(),
+ envelope.cbor_header().end());
+
TRACE_EVENT_END1(TRACE_DISABLED_BY_DEFAULT("loading"),
"GenerateSignedMessage", "dump", HexDump(message));
return message;
@@ -260,7 +233,7 @@ base::Time TimeFromSignedExchangeUnixTime(uint64_t t) {
return base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(t);
}
-// Implements steps 5-6 of
+// Implements steps 3-4 of
// https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#signature-validity
bool VerifyTimestamps(const SignedExchangeEnvelope& envelope,
const base::Time& verification_time) {
@@ -269,12 +242,12 @@ bool VerifyTimestamps(const SignedExchangeEnvelope& envelope,
base::Time creation_time =
TimeFromSignedExchangeUnixTime(envelope.signature().date);
- // 5. "If expires is more than 7 days (604800 seconds) after date, return
+ // 3. "If expires is more than 7 days (604800 seconds) after date, return
// "invalid"." [spec text]
if ((expires_time - creation_time).InSeconds() > 604800)
return false;
- // 6. "If the current time is before date or after expires, return
+ // 4. "If the current time is before date or after expires, return
// "invalid"."
if (verification_time < creation_time || expires_time < verification_time)
return false;
@@ -347,10 +320,11 @@ SignedExchangeSignatureVerifier::Result SignedExchangeSignatureVerifier::Verify(
}
if (!base::EqualsCaseInsensitiveASCII(envelope.signature().integrity,
- "mi-draft2")) {
+ "digest/mi-sha256-03")) {
signed_exchange_utils::ReportErrorAndTraceEvent(
devtools_proxy,
- "The current implemention only supports \"mi\" integrity scheme.");
+ "The current implemention only supports \"digest/mi-sha256-03\" "
+ "integrity scheme.");
return Result::kErrInvalidSignatureIntegrity;
}
return Result::kSuccess;
diff --git a/chromium/content/browser/web_package/signed_exchange_signature_verifier_unittest.cc b/chromium/content/browser/web_package/signed_exchange_signature_verifier_unittest.cc
index 9dbab4e6422..25a6ab70296 100644
--- a/chromium/content/browser/web_package/signed_exchange_signature_verifier_unittest.cc
+++ b/chromium/content/browser/web_package/signed_exchange_signature_verifier_unittest.cc
@@ -20,7 +20,7 @@ TEST(SignedExchangeSignatureVerifier, EncodeCanonicalExchangeHeaders) {
envelope.set_request_url(GURL("https://example.com/index.html"));
envelope.set_response_code(net::HTTP_OK);
envelope.AddResponseHeader("content-type", "text/html; charset=utf-8");
- envelope.AddResponseHeader("content-encoding", "mi-sha256-draft2");
+ envelope.AddResponseHeader("content-encoding", "mi-sha256-03");
base::Optional<std::vector<uint8_t>> encoded =
SignedExchangeSignatureVerifier::EncodeCanonicalExchangeHeaders(envelope);
@@ -51,9 +51,9 @@ TEST(SignedExchangeSignatureVerifier, EncodeCanonicalExchangeHeaders) {
0x50, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e,
0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, // bytes "content-encoding"
- 0x50, 0x6d, 0x69, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x2d,
- 0x64, 0x72, 0x61, 0x66, 0x74, 0x32
- // bytes "mi-sha256-draft2"
+ 0x4c, 0x6d, 0x69, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x2d,
+ 0x30, 0x33
+ // bytes "mi-sha256-03"
// clang-format on
};
EXPECT_THAT(*encoded,
@@ -65,9 +65,25 @@ const uint64_t kSignatureHeaderExpires = 1517895941;
// See content/testdata/sxg/README on how to generate these data.
// clang-format off
-constexpr char kSignatureHeaderRSA[] = R"(label; sig=*yYFb09i7VXuqsGBxc3RuJzGL4XMD9bZ20kXWSv1JObEf7KIG0MznSE1nu1fE+7DrgWQxH7FQfSWjyseOAvxsBOfkptmCCi/Ffklz3N1UU8LfwfaLWj80oBqDeofiIYwevSSpsaRKBYie7KjiVOjslFLOGe82MmHyF2utFRKY/i6UAHgMrg2FGfbwBaJsxEgtpPcN8/QnFKgt1la+JjwvYbMHpJhHTedDqx9GCxJOzbJjKRL1E2tIBvhDfK2m3eJv/nqvgWkK3MOd/Xp4FkndciS3eNyZZjwvJ6IL/3x4e0AZ36KvglpS092ZftiE4lKQWnHmVeDRmEHW6qOyv1Q3+w==*; validity-url="https://example.com/resource.validity.msg"; integrity="mi-draft2"; cert-url="https://example.com/cert.msg"; cert-sha256=*tJGJP8ej7KCEW8VnVK3bKwpBza/oLrtWA75z5ZPptuc=*; date=1517892341; expires=1517895941)";
-constexpr char kSignatureHeaderECDSAP256[] = R"(label; sig=*MEQCIA0w6auOuWGT6//MO/h43/xkXBchJUOp53GU5dmA8U+/AiAe0FggCblVxzosT2Ow9rrC2Q8zO0DZPLSNbcu29xYP6g==*; validity-url="https://example.com/resource.validity.msg"; integrity="mi-draft2"; cert-url="https://example.com/cert.msg"; cert-sha256=*KX+BYLSMgDOON8Ju65RoId39Qvajxa12HO+WnD4HpS0=*; date=1517892341; expires=1517895941)";
-constexpr char kSignatureHeaderECDSAP384[] = R"(label; sig=*MGYCMQC/P8m0ZnPrIMlI3I412MixcK9cQSirIECUNR7pOIlTiLaH95L72KXqq2aL+lxxKIICMQDU3s/BhoWtR61eKG9SqgGHd0ZtUJVY24xaJ2yHiYWxZU/QhOr5ZArSj3x1khivpRg=*; validity-url="https://example.com/resource.validity.msg"; integrity="mi-draft2"; cert-url="https://example.com/cert.msg"; cert-sha256=*8X8y8nj8vDJHSSa0cxn+TCu+8zGpIJfbdzAnd5cW+jA=*; date=1517892341; expires=1517895941)";
+constexpr char kSignatureHeaderRSA[] = R"(label; sig=*DDeXzJshGnPT+ei1rS1KmZx+QLwwLTbNKDVSmTb2HjGfgPngv+C+uMbjZiliOmGe0b514JcAlYAM57t0kZY2FPd9JdqwYPIiAWEwxByfV2iXBbsGZNWGtS/AAq1SaPwIMfrzdLXAFbKbtTRhS7B5LHCo/6hEIXu0TJJFbv5fKaLgTTLF0AK5dV0/En0uz+bnVARuBIH/ez2gPEFc6KbGnTTp8LYcCe/YjlHQy/Oac28ACBtn70rP1TerWEaYBwMMDckJ2gfsVyLqMcFtJqV0uGLT6Atb2wBSUZlZDTEZf228362r+EHLrADAuhz4bdSMKFsFgWyceOriDyHhc0PSwQ==*; validity-url="https://example.com/resource.validity.msg"; integrity="digest/mi-sha256-03"; cert-url="https://example.com/cert.msg"; cert-sha256=*tJGJP8ej7KCEW8VnVK3bKwpBza/oLrtWA75z5ZPptuc=*; date=1517892341; expires=1517895941)";
+constexpr char kSignatureHeaderECDSAP256[] = R"(label; sig=*MEUCIQC7tM/B6YxVgrJmgfFawtwBKPev2vFCh7amR+JTDBMgTQIga9LkS51vteYr8NWPTCSZRy10lcLaFNN9m1G3OBS9lBs=*; validity-url="https://example.com/resource.validity.msg"; integrity="digest/mi-sha256-03"; cert-url="https://example.com/cert.msg"; cert-sha256=*KX+BYLSMgDOON8Ju65RoId39Qvajxa12HO+WnD4HpS0=*; date=1517892341; expires=1517895941)";
+constexpr uint8_t kCborHeadersECDSAP256[] = {
+ 0x82, 0xa1, 0x47, 0x3a, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x43, 0x47,
+ 0x45, 0x54, 0xa4, 0x46, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x58, 0x39,
+ 0x6d, 0x69, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x2d, 0x30, 0x33,
+ 0x3d, 0x77, 0x6d, 0x70, 0x34, 0x64, 0x52, 0x4d, 0x59, 0x67, 0x78, 0x50,
+ 0x33, 0x74, 0x53, 0x4d, 0x43, 0x77, 0x56, 0x2f, 0x49, 0x30, 0x43, 0x57,
+ 0x4f, 0x43, 0x69, 0x48, 0x5a, 0x70, 0x41, 0x69, 0x68, 0x4b, 0x5a, 0x6b,
+ 0x31, 0x39, 0x62, 0x73, 0x4e, 0x39, 0x52, 0x49, 0x3d, 0x47, 0x3a, 0x73,
+ 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x32, 0x30, 0x30, 0x4c, 0x63, 0x6f,
+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x58, 0x18,
+ 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3b, 0x20, 0x63,
+ 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38,
+ 0x50, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63,
+ 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x4c, 0x6d, 0x69, 0x2d, 0x73, 0x68, 0x61,
+ 0x32, 0x35, 0x36, 0x2d, 0x30, 0x33
+};
+constexpr char kSignatureHeaderECDSAP384[] = R"(label; sig=*MGUCMQDm3+Mf3ymTQOF2EUFk+NDIpOIqbFCboYsPD9YOV9rpayKTmAXzUD7Hxtp+XP/8mQECMEfTRcJmvL9QMAMKuDIzQqy/ib8MPeJHap9kQVQT1OdROaYj4EISngkJeT5om9/YlA==*; validity-url="https://example.com/resource.validity.msg"; integrity="digest/mi-sha256-03"; cert-url="https://example.com/cert.msg"; cert-sha256=*8X8y8nj8vDJHSSa0cxn+TCu+8zGpIJfbdzAnd5cW+jA=*; date=1517892341; expires=1517895941)";
// clang-format on
// |expires| (1518497142) is more than 7 days (604800 seconds) after |date|
@@ -255,10 +271,9 @@ TEST_F(SignedExchangeSignatureVerifierTest, VerifyRSA) {
envelope.set_request_url(GURL("https://test.example.org/test/"));
envelope.set_response_code(net::HTTP_OK);
envelope.AddResponseHeader("content-type", "text/html; charset=utf-8");
- envelope.AddResponseHeader("content-encoding", "mi-sha256-draft2");
+ envelope.AddResponseHeader("content-encoding", "mi-sha256-03");
envelope.AddResponseHeader(
- "mi-draft2",
- "mi-sha256-draft2=wmp4dRMYgxP3tSMCwV_I0CWOCiHZpAihKZk19bsN9RI");
+ "digest", "mi-sha256-03=wmp4dRMYgxP3tSMCwV/I0CWOCiHZpAihKZk19bsN9RI=");
envelope.SetSignatureForTesting((*signature)[0]);
EXPECT_EQ(SignedExchangeSignatureVerifier::Result::kErrUnsupportedCertType,
@@ -284,10 +299,10 @@ TEST_F(SignedExchangeSignatureVerifierTest, VerifyECDSAP256) {
envelope.set_request_url(GURL("https://test.example.org/test/"));
envelope.set_response_code(net::HTTP_OK);
envelope.AddResponseHeader("content-type", "text/html; charset=utf-8");
- envelope.AddResponseHeader("content-encoding", "mi-sha256-draft2");
+ envelope.AddResponseHeader("content-encoding", "mi-sha256-03");
envelope.AddResponseHeader(
- "mi-draft2",
- "mi-sha256-draft2=wmp4dRMYgxP3tSMCwV_I0CWOCiHZpAihKZk19bsN9RI");
+ "digest", "mi-sha256-03=wmp4dRMYgxP3tSMCwV/I0CWOCiHZpAihKZk19bsN9RI=");
+ envelope.set_cbor_header(base::make_span(kCborHeadersECDSAP256));
envelope.SetSignatureForTesting((*signature)[0]);
@@ -311,10 +326,9 @@ TEST_F(SignedExchangeSignatureVerifierTest, VerifyECDSAP384) {
envelope.set_request_url(GURL("https://test.example.org/test/"));
envelope.set_response_code(net::HTTP_OK);
envelope.AddResponseHeader("content-type", "text/html; charset=utf-8");
- envelope.AddResponseHeader("content-encoding", "mi-sha256-draft2");
+ envelope.AddResponseHeader("content-encoding", "mi-sha256-03");
envelope.AddResponseHeader(
- "mi-draft2",
- "mi-sha256-draft2=wmp4dRMYgxP3tSMCwV_I0CWOCiHZpAihKZk19bsN9RIG");
+ "digest", "mi-sha256-03=wmp4dRMYgxP3tSMCwV/I0CWOCiHZpAihKZk19bsN9RIG=");
envelope.SetSignatureForTesting((*signature)[0]);
diff --git a/chromium/content/browser/webauth/authenticator_impl.cc b/chromium/content/browser/webauth/authenticator_impl.cc
index 80b95998948..b2ffb181123 100644
--- a/chromium/content/browser/webauth/authenticator_impl.cc
+++ b/chromium/content/browser/webauth/authenticator_impl.cc
@@ -18,6 +18,7 @@
#include "content/browser/bad_message.h"
#include "content/browser/webauth/authenticator_type_converters.h"
#include "content/public/browser/authenticator_request_client_delegate.h"
+#include "content/public/browser/browser_context.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_frame_host.h"
@@ -30,6 +31,7 @@
#include "content/public/common/service_manager_connection.h"
#include "crypto/sha2.h"
#include "device/base/features.h"
+#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/fido/authenticator_selection_criteria.h"
#include "device/fido/ctap_get_assertion_request.h"
#include "device/fido/ctap_make_credential_request.h"
@@ -218,8 +220,7 @@ device::CtapGetAssertionRequest CreateCtapGetAssertionRequest(
if (!options->cable_authentication_data.empty()) {
request_parameter.SetCableExtension(
- mojo::ConvertTo<
- std::vector<device::FidoCableDiscovery::CableDiscoveryData>>(
+ mojo::ConvertTo<std::vector<device::CableDiscoveryData>>(
options->cable_authentication_data));
}
return request_parameter;
@@ -280,7 +281,7 @@ CreateMakeCredentialResponse(
blink::mojom::GetAssertionAuthenticatorResponsePtr CreateGetAssertionResponse(
const std::string& client_data_json,
device::AuthenticatorGetAssertionResponse response_data,
- bool echo_appid_extension) {
+ base::Optional<bool> echo_appid_extension) {
auto response = blink::mojom::GetAssertionAuthenticatorResponse::New();
auto common_info = blink::mojom::CommonCredentialInfo::New();
common_info->client_data_json.assign(client_data_json.begin(),
@@ -291,7 +292,10 @@ blink::mojom::GetAssertionAuthenticatorResponsePtr CreateGetAssertionResponse(
response->authenticator_data =
response_data.auth_data().SerializeToByteArray();
response->signature = response_data.signature();
- response->echo_appid_extension = echo_appid_extension;
+ if (echo_appid_extension) {
+ response->echo_appid_extension = true;
+ response->appid_extension = *echo_appid_extension;
+ }
response_data.user_entity()
? response->user_handle.emplace(response_data.user_entity()->user_id())
: response->user_handle.emplace();
@@ -307,6 +311,32 @@ std::string Base64UrlEncode(const base::span<const uint8_t> input) {
return ret;
}
+base::flat_set<device::FidoTransportProtocol> GetTransportsEnabledByFlags() {
+ base::flat_set<device::FidoTransportProtocol> transports;
+ transports.insert(device::FidoTransportProtocol::kUsbHumanInterfaceDevice);
+ transports.insert(device::FidoTransportProtocol::kInternal);
+
+ // TODO(crbug.com/885165): We should not directly access the BLE stack here.
+ // It is used by //device/fido, so its availability should be checked there.
+ if (!device::BluetoothAdapterFactory::Get().IsLowEnergySupported())
+ return transports;
+
+ if (base::FeatureList::IsEnabled(features::kWebAuthBle)) {
+ transports.insert(device::FidoTransportProtocol::kBluetoothLowEnergy);
+ }
+
+#if defined(OS_WIN)
+ if (base::FeatureList::IsEnabled(features::kWebAuthCable) &&
+ base::FeatureList::IsEnabled(features::kWebAuthCableWin)) {
+#else
+ if (base::FeatureList::IsEnabled(features::kWebAuthCable)) {
+#endif // defined(OS_WIN)
+ transports.insert(
+ device::FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy);
+ }
+ return transports;
+}
+
} // namespace
AuthenticatorImpl::AuthenticatorImpl(RenderFrameHost* render_frame_host)
@@ -320,21 +350,12 @@ AuthenticatorImpl::AuthenticatorImpl(RenderFrameHost* render_frame_host,
: WebContentsObserver(WebContents::FromRenderFrameHost(render_frame_host)),
render_frame_host_(render_frame_host),
connector_(connector),
+ transports_(GetTransportsEnabledByFlags()),
timer_(std::move(timer)),
binding_(this),
weak_factory_(this) {
DCHECK(render_frame_host_);
DCHECK(timer_);
-
- protocols_.insert(device::FidoTransportProtocol::kUsbHumanInterfaceDevice);
- if (base::FeatureList::IsEnabled(features::kWebAuthBle)) {
- protocols_.insert(device::FidoTransportProtocol::kBluetoothLowEnergy);
- }
-
- if (base::FeatureList::IsEnabled(features::kWebAuthCable)) {
- protocols_.insert(
- device::FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy);
- }
}
AuthenticatorImpl::~AuthenticatorImpl() {
@@ -354,6 +375,13 @@ void AuthenticatorImpl::Bind(blink::mojom::AuthenticatorRequest request) {
binding_.Bind(std::move(request));
}
+void AuthenticatorImpl::UpdateRequestDelegate() {
+ DCHECK(!request_delegate_);
+ request_delegate_ =
+ GetContentClient()->browser()->GetWebAuthenticationRequestDelegate(
+ render_frame_host_);
+}
+
bool AuthenticatorImpl::IsFocused() const {
return render_frame_host_->IsCurrent() && request_delegate_->IsFocused();
}
@@ -362,38 +390,16 @@ bool AuthenticatorImpl::IsFocused() const {
std::string AuthenticatorImpl::SerializeCollectedClientDataToJson(
const std::string& type,
const url::Origin& origin,
- base::span<const uint8_t> challenge,
- base::Optional<base::span<const uint8_t>> token_binding) {
+ base::span<const uint8_t> challenge) {
static constexpr char kTypeKey[] = "type";
static constexpr char kChallengeKey[] = "challenge";
static constexpr char kOriginKey[] = "origin";
- static constexpr char kTokenBindingKey[] = "tokenBinding";
base::DictionaryValue client_data;
client_data.SetKey(kTypeKey, base::Value(type));
client_data.SetKey(kChallengeKey, base::Value(Base64UrlEncode(challenge)));
client_data.SetKey(kOriginKey, base::Value(origin.Serialize()));
- if (token_binding) {
- base::DictionaryValue token_binding_dict;
- static constexpr char kTokenBindingStatusKey[] = "status";
- static constexpr char kTokenBindingIdKey[] = "id";
- static constexpr char kTokenBindingSupportedStatus[] = "supported";
- static constexpr char kTokenBindingPresentStatus[] = "present";
-
- if (token_binding->empty()) {
- token_binding_dict.SetKey(kTokenBindingStatusKey,
- base::Value(kTokenBindingSupportedStatus));
- } else {
- token_binding_dict.SetKey(kTokenBindingStatusKey,
- base::Value(kTokenBindingPresentStatus));
- token_binding_dict.SetKey(kTokenBindingIdKey,
- base::Value(Base64UrlEncode(*token_binding)));
- }
-
- client_data.SetKey(kTokenBindingKey, std::move(token_binding_dict));
- }
-
if (base::RandDouble() < 0.2) {
// An extra key is sometimes added to ensure that RPs do not make
// unreasonably specific assumptions about the clientData JSON. This is
@@ -419,10 +425,7 @@ void AuthenticatorImpl::MakeCredential(
return;
}
- DCHECK(!request_delegate_);
- request_delegate_ =
- GetContentClient()->browser()->GetWebAuthenticationRequestDelegate(
- render_frame_host_);
+ UpdateRequestDelegate();
if (!request_delegate_) {
InvokeCallbackAndCleanup(std::move(callback),
blink::mojom::AuthenticatorStatus::PENDING_REQUEST,
@@ -460,11 +463,10 @@ void AuthenticatorImpl::MakeCredential(
DCHECK(make_credential_response_callback_.is_null());
make_credential_response_callback_ = std::move(callback);
- request_delegate_->DidStartRequest();
timer_->Start(
FROM_HERE, options->adjusted_timeout,
- base::Bind(&AuthenticatorImpl::OnTimeout, base::Unretained(this)));
+ base::BindOnce(&AuthenticatorImpl::OnTimeout, base::Unretained(this)));
if (!connector_)
connector_ = ServiceManagerConnection::GetForProcess()->GetConnector();
@@ -472,8 +474,7 @@ void AuthenticatorImpl::MakeCredential(
// TODO(kpaulhamus): Fetch and add the Token Binding ID public key used to
// communicate with the origin.
client_data_json_ = SerializeCollectedClientDataToJson(
- client_data::kCreateType, caller_origin, std::move(options->challenge),
- base::nullopt);
+ client_data::kCreateType, caller_origin, std::move(options->challenge));
const bool individual_attestation =
options->attestation ==
@@ -482,11 +483,6 @@ void AuthenticatorImpl::MakeCredential(
attestation_preference_ = options->attestation;
- // Communication using Cable protocol is only supported for GetAssertion
- // request on CTAP2 devices.
- protocols_.erase(
- device::FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy);
-
auto authenticator_selection_criteria =
options->authenticator_selection
? mojo::ConvertTo<device::AuthenticatorSelectionCriteria>(
@@ -494,15 +490,27 @@ void AuthenticatorImpl::MakeCredential(
: device::AuthenticatorSelectionCriteria();
request_ = std::make_unique<device::MakeCredentialRequestHandler>(
- connector_, protocols_,
+ connector_, transports_,
CreateCtapMakeCredentialRequest(
ConstructClientDataHash(client_data_json_), options,
individual_attestation),
std::move(authenticator_selection_criteria),
base::BindOnce(&AuthenticatorImpl::OnRegisterResponse,
- weak_factory_.GetWeakPtr()),
- base::BindOnce(&AuthenticatorImpl::MaybeCreatePlatformAuthenticator,
- base::Unretained(this)));
+ weak_factory_.GetWeakPtr()));
+
+ request_delegate_->RegisterActionCallbacks(
+ base::BindOnce(&AuthenticatorImpl::Cancel,
+ weak_factory_.GetWeakPtr()) /* cancel_callback */,
+ base::BindRepeating(
+ &device::FidoRequestHandlerBase::StartAuthenticatorRequest,
+ request_->GetWeakPtr()) /* request_callback */,
+ base::BindRepeating(
+ &device::FidoRequestHandlerBase::PowerOnBluetoothAdapter,
+ request_->GetWeakPtr()) /* bluetooth_adapter_power_on_callback */);
+ request_->set_observer(request_delegate_.get());
+
+ request_->SetPlatformAuthenticatorOrMarkUnavailable(
+ CreatePlatformAuthenticatorIfAvailable());
}
// mojom:Authenticator
@@ -515,10 +523,7 @@ void AuthenticatorImpl::GetAssertion(
return;
}
- DCHECK(!request_delegate_);
- request_delegate_ =
- GetContentClient()->browser()->GetWebAuthenticationRequestDelegate(
- render_frame_host_);
+ UpdateRequestDelegate();
if (!request_delegate_) {
InvokeCallbackAndCleanup(std::move(callback),
blink::mojom::AuthenticatorStatus::PENDING_REQUEST,
@@ -546,28 +551,22 @@ void AuthenticatorImpl::GetAssertion(
return;
}
- base::Optional<std::array<uint8_t, crypto::kSHA256Length>>
- alternative_application_parameter;
if (options->appid) {
- auto appid_hash = ProcessAppIdExtension(*options->appid, caller_origin);
- if (!appid_hash) {
+ alternative_application_parameter_ =
+ ProcessAppIdExtension(*options->appid, caller_origin);
+ if (!alternative_application_parameter_) {
std::move(callback).Run(blink::mojom::AuthenticatorStatus::INVALID_DOMAIN,
nullptr);
return;
}
-
- alternative_application_parameter = std::move(appid_hash);
- // TODO(agl): needs a test once a suitable, mock U2F device exists.
- echo_appid_extension_ = true;
}
DCHECK(get_assertion_response_callback_.is_null());
get_assertion_response_callback_ = std::move(callback);
- request_delegate_->DidStartRequest();
timer_->Start(
FROM_HERE, options->adjusted_timeout,
- base::Bind(&AuthenticatorImpl::OnTimeout, base::Unretained(this)));
+ base::BindOnce(&AuthenticatorImpl::OnTimeout, base::Unretained(this)));
if (!connector_)
connector_ = ServiceManagerConnection::GetForProcess()->GetConnector();
@@ -576,27 +575,58 @@ void AuthenticatorImpl::GetAssertion(
// TODO(kpaulhamus): Fetch and add the Token Binding ID public key used to
// communicate with the origin.
client_data_json_ = SerializeCollectedClientDataToJson(
- client_data::kGetType, caller_origin, std::move(options->challenge),
- base::nullopt);
+ client_data::kGetType, caller_origin, std::move(options->challenge));
+
+ auto ctap_request = CreateCtapGetAssertionRequest(
+ ConstructClientDataHash(client_data_json_), std::move(options),
+ alternative_application_parameter_);
+ auto opt_platform_authenticator_info =
+ CreatePlatformAuthenticatorIfAvailableAndCheckIfCredentialExists(
+ ctap_request);
request_ = std::make_unique<device::GetAssertionRequestHandler>(
- connector_, protocols_,
- CreateCtapGetAssertionRequest(
- ConstructClientDataHash(client_data_json_), std::move(options),
- std::move(alternative_application_parameter)),
+ connector_, transports_, std::move(ctap_request),
base::BindOnce(&AuthenticatorImpl::OnSignResponse,
- weak_factory_.GetWeakPtr()),
- base::BindOnce(&AuthenticatorImpl::MaybeCreatePlatformAuthenticator,
- base::Unretained(this)));
+ weak_factory_.GetWeakPtr()));
+
+ request_delegate_->RegisterActionCallbacks(
+ base::BindOnce(&AuthenticatorImpl::Cancel,
+ weak_factory_.GetWeakPtr()) /* cancel_callback */,
+ base::BindRepeating(
+ &device::FidoRequestHandlerBase::StartAuthenticatorRequest,
+ request_->GetWeakPtr()) /* request_callback */,
+ base::BindRepeating(
+ &device::FidoRequestHandlerBase::PowerOnBluetoothAdapter,
+ request_->GetWeakPtr()) /* bluetooth_adapter_power_on_callback */);
+ request_->set_observer(request_delegate_.get());
+
+ request_->SetPlatformAuthenticatorOrMarkUnavailable(
+ std::move(opt_platform_authenticator_info));
}
void AuthenticatorImpl::IsUserVerifyingPlatformAuthenticatorAvailable(
IsUserVerifyingPlatformAuthenticatorAvailableCallback callback) {
- bool result = false;
+ const bool result = IsUserVerifyingPlatformAuthenticatorAvailableImpl();
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback), result));
+}
+
+bool AuthenticatorImpl::IsUserVerifyingPlatformAuthenticatorAvailableImpl() {
#if defined(OS_MACOSX)
- result = device::fido::mac::TouchIdAuthenticator::IsAvailable();
+ // Touch ID is disabled, regardless of hardware support, if the embedder
+ // doesn't support it or if this is an Incognito session. N.B.
+ // request_delegate_ may be nullptr at this point.
+ if (!GetContentClient()
+ ->browser()
+ ->IsWebAuthenticationTouchIdAuthenticatorSupported() ||
+ browser_context()->IsOffTheRecord()) {
+ return false;
+ }
+
+ return device::fido::mac::TouchIdAuthenticator::IsAvailable();
+#else
+ return false;
#endif
- std::move(callback).Run(result);
}
void AuthenticatorImpl::DidFinishNavigation(
@@ -619,7 +649,8 @@ void AuthenticatorImpl::DidFinishNavigation(
// Callback to handle the async registration response from a U2fDevice.
void AuthenticatorImpl::OnRegisterResponse(
device::FidoReturnCode status_code,
- base::Optional<device::AuthenticatorMakeCredentialResponse> response_data) {
+ base::Optional<device::AuthenticatorMakeCredentialResponse> response_data,
+ device::FidoTransportProtocol transport_used) {
if (!request_) {
// Either the callback was called immediately and |request_| has not yet
// been assigned (this is a bug), or a navigation caused the request to be
@@ -632,6 +663,10 @@ void AuthenticatorImpl::OnRegisterResponse(
// Duplicate registration: the new credential would be created on an
// authenticator that already contains one of the credentials in
// |exclude_credentials|.
+ DCHECK(request_delegate_);
+ request_delegate_->DidFailWithInterestingReason(
+ AuthenticatorRequestClientDelegate::InterestingFailureReason::
+ kKeyAlreadyRegistered);
InvokeCallbackAndCleanup(
std::move(make_credential_response_callback_),
blink::mojom::AuthenticatorStatus::CREDENTIAL_EXCLUDED, nullptr,
@@ -645,10 +680,18 @@ void AuthenticatorImpl::OnRegisterResponse(
Focus::kDoCheck);
return;
case device::FidoReturnCode::kUserConsentButCredentialNotRecognized:
+ // TODO(crbug/876109): This isn't strictly unreachable.
NOTREACHED();
return;
+ case device::FidoReturnCode::kUserConsentDenied:
+ InvokeCallbackAndCleanup(
+ std::move(make_credential_response_callback_),
+ blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR, nullptr,
+ Focus::kDoCheck);
+ return;
case device::FidoReturnCode::kSuccess:
DCHECK(response_data.has_value());
+ request_delegate_->UpdateLastTransportUsed(transport_used);
if (attestation_preference_ !=
blink::mojom::AttestationConveyancePreference::NONE) {
@@ -660,7 +703,10 @@ void AuthenticatorImpl::OnRegisterResponse(
return;
}
- response_data->EraseAttestationStatement();
+ if (!response_data->IsSelfAttestation()) {
+ response_data->EraseAttestationStatement();
+ }
+
InvokeCallbackAndCleanup(
std::move(make_credential_response_callback_),
blink::mojom::AuthenticatorStatus::SUCCESS,
@@ -722,7 +768,8 @@ void AuthenticatorImpl::OnRegisterResponseAttestationDecided(
void AuthenticatorImpl::OnSignResponse(
device::FidoReturnCode status_code,
- base::Optional<device::AuthenticatorGetAssertionResponse> response_data) {
+ base::Optional<device::AuthenticatorGetAssertionResponse> response_data,
+ device::FidoTransportProtocol transport_used) {
if (!request_) {
// Either the callback was called immediately and |request_| has not yet
// been assigned (this is a bug), or a navigation caused the request to be
@@ -733,6 +780,10 @@ void AuthenticatorImpl::OnSignResponse(
switch (status_code) {
case device::FidoReturnCode::kUserConsentButCredentialNotRecognized:
// No authenticators contained the credential.
+ DCHECK(request_delegate_);
+ request_delegate_->DidFailWithInterestingReason(
+ AuthenticatorRequestClientDelegate::InterestingFailureReason::
+ kKeyNotRegistered);
InvokeCallbackAndCleanup(
std::move(get_assertion_response_callback_),
blink::mojom::AuthenticatorStatus::CREDENTIAL_NOT_RECOGNIZED,
@@ -745,24 +796,35 @@ void AuthenticatorImpl::OnSignResponse(
blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR, nullptr);
return;
case device::FidoReturnCode::kUserConsentButCredentialExcluded:
+ // TODO(crbug/876109): This isn't strictly unreachable.
NOTREACHED();
return;
+ case device::FidoReturnCode::kUserConsentDenied:
+ InvokeCallbackAndCleanup(
+ std::move(get_assertion_response_callback_),
+ blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR, nullptr);
+ return;
case device::FidoReturnCode::kSuccess:
DCHECK(response_data.has_value());
+ request_delegate_->UpdateLastTransportUsed(transport_used);
+
+ base::Optional<bool> echo_appid_extension;
+ if (alternative_application_parameter_) {
+ echo_appid_extension = (response_data->GetRpIdHash() ==
+ *alternative_application_parameter_);
+ }
InvokeCallbackAndCleanup(
std::move(get_assertion_response_callback_),
blink::mojom::AuthenticatorStatus::SUCCESS,
CreateGetAssertionResponse(std::move(client_data_json_),
std::move(*response_data),
- echo_appid_extension_));
+ echo_appid_extension));
return;
}
NOTREACHED();
}
-void AuthenticatorImpl::OnTimeout() {
- // TODO(crbug.com/814418): Add layout tests to verify timeouts are
- // indistinguishable from NOT_ALLOWED_ERROR cases.
+void AuthenticatorImpl::FailWithNotAllowedErrorAndCleanup() {
DCHECK(make_credential_response_callback_ ||
get_assertion_response_callback_);
if (make_credential_response_callback_) {
@@ -777,6 +839,24 @@ void AuthenticatorImpl::OnTimeout() {
}
}
+void AuthenticatorImpl::OnTimeout() {
+ DCHECK(request_delegate_);
+ request_delegate_->DidFailWithInterestingReason(
+ AuthenticatorRequestClientDelegate::InterestingFailureReason::kTimeout);
+
+ // TODO(crbug.com/814418): Add layout tests to verify timeouts are
+ // indistinguishable from NOT_ALLOWED_ERROR cases.
+ FailWithNotAllowedErrorAndCleanup();
+}
+
+void AuthenticatorImpl::Cancel() {
+ // If response callback is invoked already, then ignore cancel request.
+ if (!make_credential_response_callback_ && !get_assertion_response_callback_)
+ return;
+
+ FailWithNotAllowedErrorAndCleanup();
+}
+
void AuthenticatorImpl::InvokeCallbackAndCleanup(
MakeCredentialCallback callback,
blink::mojom::AuthenticatorStatus status,
@@ -807,21 +887,65 @@ void AuthenticatorImpl::Cleanup() {
make_credential_response_callback_.Reset();
get_assertion_response_callback_.Reset();
client_data_json_.clear();
- echo_appid_extension_ = false;
+ alternative_application_parameter_.reset();
+}
+
+BrowserContext* AuthenticatorImpl::browser_context() const {
+ return content::WebContents::FromRenderFrameHost(render_frame_host_)
+ ->GetBrowserContext();
}
-std::unique_ptr<device::FidoAuthenticator>
-AuthenticatorImpl::MaybeCreatePlatformAuthenticator() {
#if defined(OS_MACOSX)
+namespace {
+std::unique_ptr<device::fido::mac::TouchIdAuthenticator>
+CreateTouchIdAuthenticatorIfAvailable(
+ const AuthenticatorRequestClientDelegate* request_delegate) {
+ // Not all embedders may provide an authenticator config.
auto opt_authenticator_config =
- request_delegate_->GetTouchIdAuthenticatorConfig();
- if (opt_authenticator_config) {
- return device::fido::mac::TouchIdAuthenticator::CreateIfAvailable(
- std::move(opt_authenticator_config->keychain_access_group),
- std::move(opt_authenticator_config->metadata_secret));
- }
-#endif // defined(OS_MACOSX)
- return nullptr;
+ request_delegate->GetTouchIdAuthenticatorConfig();
+ if (!opt_authenticator_config) {
+ return nullptr;
+ }
+ return device::fido::mac::TouchIdAuthenticator::CreateIfAvailable(
+ std::move(opt_authenticator_config->keychain_access_group),
+ std::move(opt_authenticator_config->metadata_secret));
+}
+} // namespace
+#endif
+
+base::Optional<device::PlatformAuthenticatorInfo>
+AuthenticatorImpl::CreatePlatformAuthenticatorIfAvailable() {
+ // Incognito mode disables platform authenticators, so check for availability
+ // first.
+ if (!IsUserVerifyingPlatformAuthenticatorAvailableImpl()) {
+ return base::nullopt;
+ }
+#if defined(OS_MACOSX)
+ return device::PlatformAuthenticatorInfo(
+ CreateTouchIdAuthenticatorIfAvailable(request_delegate_.get()), false);
+#else
+ return base::nullopt;
+#endif
+}
+
+base::Optional<device::PlatformAuthenticatorInfo> AuthenticatorImpl::
+ CreatePlatformAuthenticatorIfAvailableAndCheckIfCredentialExists(
+ const device::CtapGetAssertionRequest& request) {
+ // Incognito mode disables platform authenticators, so check for availability
+ // first.
+ if (!IsUserVerifyingPlatformAuthenticatorAvailableImpl()) {
+ return base::nullopt;
+ }
+#if defined(OS_MACOSX)
+ std::unique_ptr<device::fido::mac::TouchIdAuthenticator> authenticator =
+ CreateTouchIdAuthenticatorIfAvailable(request_delegate_.get());
+ const bool has_credential =
+ authenticator->HasCredentialForGetAssertionRequest(request);
+ return device::PlatformAuthenticatorInfo(std::move(authenticator),
+ has_credential);
+#else
+ return base::nullopt;
+#endif
}
} // namespace content
diff --git a/chromium/content/browser/webauth/authenticator_impl.h b/chromium/content/browser/webauth/authenticator_impl.h
index 538b06b559c..df8cdf26eb4 100644
--- a/chromium/content/browser/webauth/authenticator_impl.h
+++ b/chromium/content/browser/webauth/authenticator_impl.h
@@ -16,12 +16,13 @@
#include "base/optional.h"
#include "content/common/content_export.h"
#include "content/public/browser/web_contents_observer.h"
+#include "crypto/sha2.h"
#include "device/fido/authenticator_get_assertion_response.h"
#include "device/fido/authenticator_make_credential_response.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_transport_protocol.h"
#include "mojo/public/cpp/bindings/binding.h"
-#include "third_party/blink/public/platform/modules/webauth/authenticator.mojom.h"
+#include "third_party/blink/public/platform/modules/webauthn/authenticator.mojom.h"
#include "url/origin.h"
namespace base {
@@ -30,7 +31,8 @@ class OneShotTimer;
namespace device {
-class FidoAuthenticator;
+struct PlatformAuthenticatorInfo;
+class CtapGetAssertionRequest;
class FidoRequestHandlerBase;
enum class FidoReturnCode : uint8_t;
@@ -48,6 +50,7 @@ class Origin;
namespace content {
class AuthenticatorRequestClientDelegate;
+class BrowserContext;
class RenderFrameHost;
namespace client_data {
@@ -79,6 +82,16 @@ class CONTENT_EXPORT AuthenticatorImpl : public blink::mojom::Authenticator,
// to a new active document.
void Bind(blink::mojom::AuthenticatorRequest request);
+ base::flat_set<device::FidoTransportProtocol> enabled_transports_for_testing()
+ const {
+ return transports_;
+ }
+
+ protected:
+ virtual void UpdateRequestDelegate();
+
+ std::unique_ptr<AuthenticatorRequestClientDelegate> request_delegate_;
+
private:
friend class AuthenticatorImplTest;
@@ -96,8 +109,7 @@ class CONTENT_EXPORT AuthenticatorImpl : public blink::mojom::Authenticator,
static std::string SerializeCollectedClientDataToJson(
const std::string& type,
const url::Origin& origin,
- base::span<const uint8_t> challenge,
- base::Optional<base::span<const uint8_t>> token_binding);
+ base::span<const uint8_t> challenge);
// mojom:Authenticator
void MakeCredential(
@@ -108,14 +120,17 @@ class CONTENT_EXPORT AuthenticatorImpl : public blink::mojom::Authenticator,
void IsUserVerifyingPlatformAuthenticatorAvailable(
IsUserVerifyingPlatformAuthenticatorAvailableCallback callback) override;
+ // Synchronous implementation of IsUserVerfyingPlatformAuthenticatorAvailable.
+ bool IsUserVerifyingPlatformAuthenticatorAvailableImpl();
+
// WebContentsObserver:
void DidFinishNavigation(NavigationHandle* navigation_handle) override;
// Callback to handle the async response from a U2fDevice.
void OnRegisterResponse(
device::FidoReturnCode status_code,
- base::Optional<device::AuthenticatorMakeCredentialResponse>
- response_data);
+ base::Optional<device::AuthenticatorMakeCredentialResponse> response_data,
+ device::FidoTransportProtocol transport_used);
// Callback to complete the registration process once a decision about
// whether or not to return attestation data has been made.
@@ -126,10 +141,15 @@ class CONTENT_EXPORT AuthenticatorImpl : public blink::mojom::Authenticator,
// Callback to handle the async response from a U2fDevice.
void OnSignResponse(
device::FidoReturnCode status_code,
- base::Optional<device::AuthenticatorGetAssertionResponse> response_data);
+ base::Optional<device::AuthenticatorGetAssertionResponse> response_data,
+ device::FidoTransportProtocol transport_used);
+
+ void FailWithNotAllowedErrorAndCleanup();
// Runs when timer expires and cancels all issued requests to a U2fDevice.
void OnTimeout();
+ // Runs when the user cancels WebAuthN request via UI dialog.
+ void Cancel();
void InvokeCallbackAndCleanup(
MakeCredentialCallback callback,
@@ -142,26 +162,30 @@ class CONTENT_EXPORT AuthenticatorImpl : public blink::mojom::Authenticator,
blink::mojom::GetAssertionAuthenticatorResponsePtr response);
void Cleanup();
- std::unique_ptr<device::FidoAuthenticator> MaybeCreatePlatformAuthenticator();
+ base::Optional<device::PlatformAuthenticatorInfo>
+ CreatePlatformAuthenticatorIfAvailable();
+ base::Optional<device::PlatformAuthenticatorInfo>
+ CreatePlatformAuthenticatorIfAvailableAndCheckIfCredentialExists(
+ const device::CtapGetAssertionRequest& request);
+
+ BrowserContext* browser_context() const;
RenderFrameHost* const render_frame_host_;
service_manager::Connector* connector_ = nullptr;
- base::flat_set<device::FidoTransportProtocol> protocols_;
+ const base::flat_set<device::FidoTransportProtocol> transports_;
std::unique_ptr<device::FidoRequestHandlerBase> request_;
- std::unique_ptr<AuthenticatorRequestClientDelegate> request_delegate_;
MakeCredentialCallback make_credential_response_callback_;
GetAssertionCallback get_assertion_response_callback_;
std::string client_data_json_;
blink::mojom::AttestationConveyancePreference attestation_preference_;
std::string relying_party_id_;
std::unique_ptr<base::OneShotTimer> timer_;
-
- // Whether or not a GetAssertion call should return a PublicKeyCredential
- // instance whose getClientExtensionResults() method yields a
- // AuthenticationExtensions dictionary that contains the `appid: true`
- // extension output.
- bool echo_appid_extension_ = false;
+ // If the "appid" extension is in use then this is the SHA-256 hash of a U2F
+ // AppID. This is used to detect when an assertion request was successfully
+ // retried with this value.
+ base::Optional<std::array<uint8_t, crypto::kSHA256Length>>
+ alternative_application_parameter_;
// Owns pipes to this Authenticator from |render_frame_host_|.
mojo::Binding<blink::mojom::Authenticator> binding_;
diff --git a/chromium/content/browser/webauth/authenticator_impl_unittest.cc b/chromium/content/browser/webauth/authenticator_impl_unittest.cc
index 4dc815e0ebe..fdb9b181f0e 100644
--- a/chromium/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/chromium/content/browser/webauth/authenticator_impl_unittest.cc
@@ -18,6 +18,7 @@
#include "base/test/test_mock_time_task_runner.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "components/cbor/cbor_reader.h"
#include "components/cbor/cbor_values.h"
#include "content/public/browser/authenticator_request_client_delegate.h"
@@ -26,7 +27,13 @@
#include "content/public/test/test_service_manager_context.h"
#include "content/test/test_render_frame_host.h"
#include "device/base/features.h"
-#include "device/fido/fake_hid_impl_for_testing.h"
+#include "device/bluetooth/bluetooth_adapter_factory.h"
+#include "device/bluetooth/test/mock_bluetooth_adapter.h"
+#include "device/fido/attested_credential_data.h"
+#include "device/fido/authenticator_data.h"
+#include "device/fido/fake_fido_discovery.h"
+#include "device/fido/hid/fake_hid_impl_for_testing.h"
+#include "device/fido/mock_fido_device.h"
#include "device/fido/scoped_virtual_fido_device.h"
#include "device/fido/test_callback_receiver.h"
#include "mojo/public/cpp/bindings/binding.h"
@@ -34,6 +41,10 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(OS_MACOSX)
+#include "device/fido/mac/scoped_touch_id_test_environment.h"
+#endif
+
namespace content {
using ::testing::_;
@@ -58,11 +69,17 @@ using blink::mojom::PublicKeyCredentialRpEntityPtr;
using blink::mojom::PublicKeyCredentialType;
using blink::mojom::PublicKeyCredentialUserEntity;
using blink::mojom::PublicKeyCredentialUserEntityPtr;
+using blink::mojom::AuthenticatorTransport;
using cbor::CBORValue;
using cbor::CBORReader;
namespace {
+using InterestingFailureReason =
+ ::content::AuthenticatorRequestClientDelegate::InterestingFailureReason;
+using FailureReasonCallbackReceiver =
+ ::device::test::TestCallbackReceiver<InterestingFailureReason>;
+
typedef struct {
const char* origin;
// Either a relying party ID or a U2F AppID.
@@ -193,6 +210,7 @@ constexpr OriginClaimedAuthorityPair kInvalidRelyingPartyTestCases[] = {
{"https://com", "https://www.gstatic.com/securitykey/origins.json"},
};
+using TestIsUvpaaCallback = device::test::ValueCallbackReceiver<bool>;
using TestMakeCredentialCallback = device::test::StatusAndValueCallbackReceiver<
AuthenticatorStatus,
MakeCredentialAuthenticatorResponsePtr>;
@@ -249,6 +267,8 @@ std::vector<PublicKeyCredentialDescriptorPtr> GetTestAllowCredentials() {
credential->type = PublicKeyCredentialType::PUBLIC_KEY;
std::vector<uint8_t> id(32, 0x0A);
credential->id = id;
+ credential->transports.push_back(AuthenticatorTransport::USB);
+ credential->transports.push_back(AuthenticatorTransport::BLE);
descriptors.push_back(std::move(credential));
return descriptors;
}
@@ -348,15 +368,7 @@ class AuthenticatorImplTest : public content::RenderViewHostTestHarness {
std::string GetTestClientDataJSON(std::string type) {
return AuthenticatorImpl::SerializeCollectedClientDataToJson(
- std::move(type), GetTestOrigin(), GetTestChallengeBytes(),
- base::nullopt);
- }
-
- std::string GetTokenBindingTestClientDataJSON(
- base::Optional<base::span<const uint8_t>> token_binding) {
- return AuthenticatorImpl::SerializeCollectedClientDataToJson(
- client_data::kGetType, GetTestOrigin(), GetTestChallengeBytes(),
- token_binding);
+ std::move(type), GetTestOrigin(), GetTestChallengeBytes());
}
AuthenticatorStatus TryAuthenticationWithAppId(const std::string& origin,
@@ -378,7 +390,13 @@ class AuthenticatorImplTest : public content::RenderViewHostTestHarness {
}
bool SupportsTransportProtocol(::device::FidoTransportProtocol protocol) {
- return base::ContainsKey(authenticator_impl_->protocols_, protocol);
+ return base::ContainsKey(
+ authenticator_impl_->enabled_transports_for_testing(), protocol);
+ }
+
+ void EnableFeature(const base::Feature& feature) {
+ scoped_feature_list_.emplace();
+ scoped_feature_list_->InitAndEnableFeature(feature);
}
protected:
@@ -386,6 +404,7 @@ class AuthenticatorImplTest : public content::RenderViewHostTestHarness {
service_manager::mojom::ConnectorRequest request_;
std::unique_ptr<service_manager::Connector> connector_;
std::unique_ptr<device::FakeHidManager> fake_hid_manager_;
+ base::Optional<base::test::ScopedFeatureList> scoped_feature_list_;
};
// Verify behavior for various combinations of origins and RP IDs.
@@ -592,34 +611,6 @@ TEST_F(AuthenticatorImplTest, TestSerializedSignClientData) {
GetTestClientDataJSON(client_data::kGetType));
}
-TEST_F(AuthenticatorImplTest, TestTokenBindingClientData) {
- const std::vector<
- std::pair<base::Optional<std::vector<uint8_t>>, const char*>>
- kTestCases = {
- std::make_pair(base::nullopt, ""),
- std::make_pair(std::vector<uint8_t>{},
- R"({"tokenBinding":{"status":"supported"}})"),
- std::make_pair(
- std::vector<uint8_t>{1, 2, 3, 4},
- R"({"tokenBinding":{"status":"present","id":"AQIDBA"}})"),
- };
-
- for (const auto& test : kTestCases) {
- const auto& token_binding = test.first;
- const std::string expected_json_subset = test.second;
- SCOPED_TRACE(expected_json_subset);
- const std::string client_data =
- GetTokenBindingTestClientDataJSON(token_binding);
-
- if (!expected_json_subset.empty()) {
- CheckJSONIsSubsetOfJSON(expected_json_subset, client_data);
- } else {
- EXPECT_TRUE(client_data.find("tokenBinding") == std::string::npos)
- << client_data;
- }
- }
-}
-
TEST_F(AuthenticatorImplTest, TestMakeCredentialTimeout) {
SimulateNavigation(GURL(kTestOrigin1));
PublicKeyCredentialCreationOptionsPtr options =
@@ -710,26 +701,71 @@ TEST_F(AuthenticatorImplTest, AppIdExtensionValues) {
// Verify that a credential registered with U2F can be used via webauthn.
TEST_F(AuthenticatorImplTest, AppIdExtension) {
SimulateNavigation(GURL(kTestOrigin1));
- PublicKeyCredentialRequestOptionsPtr options =
- GetTestPublicKeyCredentialRequestOptions();
- TestGetAssertionCallback callback_receiver;
auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
base::Time::Now(), base::TimeTicks::Now());
auto authenticator = ConstructAuthenticatorWithTimer(task_runner);
- device::test::ScopedVirtualFidoDevice virtual_device;
- // Inject a registration for the URL (which is a U2F AppID).
- ASSERT_TRUE(virtual_device.mutable_state()->InjectRegistration(
- options->allow_credentials[0]->id, kTestOrigin1));
+ {
+ // First, test that the appid extension isn't echoed at all when not
+ // requested.
+ PublicKeyCredentialRequestOptionsPtr options =
+ GetTestPublicKeyCredentialRequestOptions();
+ device::test::ScopedVirtualFidoDevice virtual_device;
+ ASSERT_TRUE(virtual_device.mutable_state()->InjectRegistration(
+ options->allow_credentials[0]->id, kTestRelyingPartyId));
- // Set the same URL as the appid parameter.
- options->appid = kTestOrigin1;
+ TestGetAssertionCallback callback_receiver;
+ authenticator->GetAssertion(std::move(options),
+ callback_receiver.callback());
+ callback_receiver.WaitForCallback();
+ ASSERT_EQ(AuthenticatorStatus::SUCCESS, callback_receiver.status());
- authenticator->GetAssertion(std::move(options), callback_receiver.callback());
+ EXPECT_EQ(false, callback_receiver.value()->echo_appid_extension);
+ }
- // Trigger timer.
- callback_receiver.WaitForCallback();
- EXPECT_EQ(AuthenticatorStatus::SUCCESS, callback_receiver.status());
+ {
+ // Second, test that the appid extension is echoed, but is false, when appid
+ // is requested but not used.
+ PublicKeyCredentialRequestOptionsPtr options =
+ GetTestPublicKeyCredentialRequestOptions();
+ device::test::ScopedVirtualFidoDevice virtual_device;
+ ASSERT_TRUE(virtual_device.mutable_state()->InjectRegistration(
+ options->allow_credentials[0]->id, kTestRelyingPartyId));
+
+ // This AppID won't be used because the RP ID will be tried (successfully)
+ // first.
+ options->appid = kTestOrigin1;
+
+ TestGetAssertionCallback callback_receiver;
+ authenticator->GetAssertion(std::move(options),
+ callback_receiver.callback());
+ callback_receiver.WaitForCallback();
+ ASSERT_EQ(AuthenticatorStatus::SUCCESS, callback_receiver.status());
+
+ EXPECT_EQ(true, callback_receiver.value()->echo_appid_extension);
+ EXPECT_EQ(false, callback_receiver.value()->appid_extension);
+ }
+
+ {
+ // Lastly, when used, the appid extension result should be "true".
+ PublicKeyCredentialRequestOptionsPtr options =
+ GetTestPublicKeyCredentialRequestOptions();
+ device::test::ScopedVirtualFidoDevice virtual_device;
+ // Inject a registration for the URL (which is a U2F AppID).
+ ASSERT_TRUE(virtual_device.mutable_state()->InjectRegistration(
+ options->allow_credentials[0]->id, kTestOrigin1));
+
+ options->appid = kTestOrigin1;
+
+ TestGetAssertionCallback callback_receiver;
+ authenticator->GetAssertion(std::move(options),
+ callback_receiver.callback());
+ callback_receiver.WaitForCallback();
+ ASSERT_EQ(AuthenticatorStatus::SUCCESS, callback_receiver.status());
+
+ EXPECT_EQ(true, callback_receiver.value()->echo_appid_extension);
+ EXPECT_EQ(true, callback_receiver.value()->appid_extension);
+ }
}
TEST_F(AuthenticatorImplTest, TestGetAssertionTimeout) {
@@ -768,6 +804,7 @@ TEST_F(AuthenticatorImplTest, OversizedCredentialId) {
auto credential = PublicKeyCredentialDescriptor::New();
credential->type = PublicKeyCredentialType::PUBLIC_KEY;
credential->id.resize(size);
+ credential->transports.push_back(AuthenticatorTransport::USB);
const bool should_be_valid = size < 256;
if (should_be_valid) {
@@ -791,78 +828,61 @@ TEST_F(AuthenticatorImplTest, OversizedCredentialId) {
}
}
-TEST_F(AuthenticatorImplTest, TestCableDiscoveryEnabledWithSwitch) {
- TestServiceManagerContext service_manager_context;
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitWithFeatures(
- std::vector<base::Feature>{features::kWebAuthCable},
- std::vector<base::Feature>{});
-
- SimulateNavigation(GURL(kTestOrigin1));
- PublicKeyCredentialRequestOptionsPtr options =
- GetTestPublicKeyCredentialRequestOptions();
- TestGetAssertionCallback callback_receiver;
-
- auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
- base::Time::Now(), base::TimeTicks::Now());
- auto authenticator = ConstructAuthenticatorWithTimer(task_runner);
- authenticator->GetAssertion(std::move(options), callback_receiver.callback());
-
- // Trigger timer.
- base::RunLoop().RunUntilIdle();
- task_runner->FastForwardBy(base::TimeDelta::FromMinutes(1));
- callback_receiver.WaitForCallback();
-
- EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR, callback_receiver.status());
- EXPECT_TRUE(SupportsTransportProtocol(
+TEST_F(AuthenticatorImplTest, TestCableDiscoveryByDefault) {
+ auto authenticator = ConnectToAuthenticator();
+// On Windows caBLE should be disabled by default regardless of version.
+#if defined(OS_WIN)
+ EXPECT_FALSE(SupportsTransportProtocol(
device::FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy));
+// Otherwise, it should be enabled by default if BLE is supported.
+#else
+ EXPECT_EQ(
+ device::BluetoothAdapterFactory::Get().IsLowEnergySupported(),
+ SupportsTransportProtocol(
+ device::FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy));
+#endif
}
-TEST_F(AuthenticatorImplTest, TestCableDiscoveryDisabledForMakeCredential) {
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndEnableFeature(features::kWebAuthCable);
-
- SimulateNavigation(GURL(kTestOrigin1));
- PublicKeyCredentialCreationOptionsPtr options =
- GetTestPublicKeyCredentialCreationOptions();
- TestMakeCredentialCallback callback_receiver;
-
- auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
- base::Time::Now(), base::TimeTicks::Now());
- auto authenticator = ConstructAuthenticatorWithTimer(task_runner);
- authenticator->MakeCredential(std::move(options),
- callback_receiver.callback());
+TEST_F(AuthenticatorImplTest, TestCableDiscoveryDisabledWithFlag) {
+ scoped_feature_list_.emplace();
+ scoped_feature_list_->InitAndDisableFeature(features::kWebAuthCable);
- // Trigger timer.
- base::RunLoop().RunUntilIdle();
- task_runner->FastForwardBy(base::TimeDelta::FromMinutes(1));
- callback_receiver.WaitForCallback();
-
- EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR, callback_receiver.status());
+ auto authenticator = ConnectToAuthenticator();
EXPECT_FALSE(SupportsTransportProtocol(
device::FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy));
}
-TEST_F(AuthenticatorImplTest, TestCableDiscoveryDisabledWithoutSwitch) {
- SimulateNavigation(GURL(kTestOrigin1));
- PublicKeyCredentialRequestOptionsPtr options =
- GetTestPublicKeyCredentialRequestOptions();
- TestGetAssertionCallback callback_receiver;
+#if defined(OS_WIN)
+TEST_F(AuthenticatorImplTest, TestCableDiscoveryEnabledWithWinFlag) {
+ EnableFeature(features::kWebAuthCableWin);
- auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
- base::Time::Now(), base::TimeTicks::Now());
- auto authenticator = ConstructAuthenticatorWithTimer(task_runner);
- authenticator->GetAssertion(std::move(options), callback_receiver.callback());
+ auto authenticator = ConnectToAuthenticator();
- // Trigger timer.
- base::RunLoop().RunUntilIdle();
- task_runner->FastForwardBy(base::TimeDelta::FromMinutes(1));
- callback_receiver.WaitForCallback();
+ // Should be enabled if the new Windows BLE stack is.
+ EXPECT_EQ(
+ device::BluetoothAdapterFactory::Get().IsLowEnergySupported(),
+ SupportsTransportProtocol(
+ device::FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy));
+}
- EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR, callback_receiver.status());
- EXPECT_FALSE(SupportsTransportProtocol(
- device::FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy));
+// Tests that caBLE is not supported when features::kWebAuthCable is disabled,
+// regardless of the state of features::kWebAuthCableWin.
+TEST_F(AuthenticatorImplTest, TestCableDiscoveryDisabledWithoutFlagWin) {
+ for (bool enable_win_flag : {false, true}) {
+ std::vector<base::Feature> enabled_features;
+ std::vector<base::Feature> disabled_features = {features::kWebAuthCable};
+ enable_win_flag ? enabled_features.push_back(features::kWebAuthCableWin)
+ : disabled_features.push_back(features::kWebAuthCableWin);
+
+ scoped_feature_list_.emplace();
+ scoped_feature_list_->InitWithFeatures(enabled_features, disabled_features);
+
+ auto authenticator = ConnectToAuthenticator();
+ EXPECT_FALSE(SupportsTransportProtocol(
+ device::FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy));
+ }
}
+#endif
TEST_F(AuthenticatorImplTest, TestGetAssertionU2fDeviceBackwardsCompatibility) {
SimulateNavigation(GURL(kTestOrigin1));
@@ -886,6 +906,15 @@ TEST_F(AuthenticatorImplTest, TestGetAssertionU2fDeviceBackwardsCompatibility) {
}
TEST_F(AuthenticatorImplTest, GetAssertionWithEmptyAllowCredentials) {
+ auto mock_adapter =
+ base::MakeRefCounted<::testing::NiceMock<device::MockBluetoothAdapter>>();
+ EXPECT_CALL(*mock_adapter, IsPresent())
+ .WillRepeatedly(::testing::Return(true));
+ device::BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
+ auto bluetooth_adapter_factory_overrides =
+ device::BluetoothAdapterFactory::Get().InitGlobalValuesForTesting();
+ bluetooth_adapter_factory_overrides->SetLESupported(true);
+
SimulateNavigation(GURL(kTestOrigin1));
PublicKeyCredentialRequestOptionsPtr options =
GetTestPublicKeyCredentialRequestOptions();
@@ -1069,23 +1098,36 @@ enum class AttestationConsent {
DENIED,
};
+enum class AttestationType {
+ ANY,
+ NONE,
+ U2F,
+ SELF,
+};
+
class TestAuthenticatorRequestDelegate
: public AuthenticatorRequestClientDelegate {
public:
- TestAuthenticatorRequestDelegate(RenderFrameHost* render_frame_host,
- base::OnceClosure did_start_request_callback,
- IndividualAttestation individual_attestation,
- AttestationConsent attestation_consent,
- bool is_focused)
- : did_start_request_callback_(std::move(did_start_request_callback)),
+ TestAuthenticatorRequestDelegate(
+ RenderFrameHost* render_frame_host,
+ base::OnceClosure action_callbacks_registered_callback,
+ IndividualAttestation individual_attestation,
+ AttestationConsent attestation_consent,
+ bool is_focused)
+ : action_callbacks_registered_callback_(
+ std::move(action_callbacks_registered_callback)),
individual_attestation_(individual_attestation),
attestation_consent_(attestation_consent),
is_focused_(is_focused) {}
~TestAuthenticatorRequestDelegate() override {}
- void DidStartRequest() override {
- ASSERT_TRUE(did_start_request_callback_) << "DidStartRequest called twice.";
- std::move(did_start_request_callback_).Run();
+ void RegisterActionCallbacks(
+ base::OnceClosure cancel_callback,
+ device::FidoRequestHandlerBase::RequestCallback request_callback,
+ base::RepeatingClosure bluetooth_adapter_power_on_callback) override {
+ ASSERT_TRUE(action_callbacks_registered_callback_)
+ << "RegisterActionCallbacks called twice.";
+ std::move(action_callbacks_registered_callback_).Run();
}
bool ShouldPermitIndividualAttestation(
@@ -1102,7 +1144,7 @@ class TestAuthenticatorRequestDelegate
bool IsFocused() override { return is_focused_; }
- base::OnceClosure did_start_request_callback_;
+ base::OnceClosure action_callbacks_registered_callback_;
const IndividualAttestation individual_attestation_;
const AttestationConsent attestation_consent_;
const bool is_focused_;
@@ -1120,14 +1162,23 @@ class TestAuthenticatorContentBrowserClient : public ContentBrowserClient {
return nullptr;
return std::make_unique<TestAuthenticatorRequestDelegate>(
render_frame_host,
- request_started_callback ? std::move(request_started_callback)
- : base::DoNothing(),
+ action_callbacks_registered_callback
+ ? std::move(action_callbacks_registered_callback)
+ : base::DoNothing(),
individual_attestation, attestation_consent, is_focused);
}
+#if defined(OS_MACOSX)
+ bool IsWebAuthenticationTouchIdAuthenticatorSupported() override {
+ return supports_touch_id;
+ }
+
+ bool supports_touch_id = true;
+#endif
+
// If set, this closure will be called when the subsequently constructed
// delegate is informed that the request has started.
- base::OnceClosure request_started_callback;
+ base::OnceClosure action_callbacks_registered_callback;
IndividualAttestation individual_attestation =
IndividualAttestation::NOT_REQUESTED;
@@ -1151,7 +1202,7 @@ class AuthenticatorContentBrowserClientTest : public AuthenticatorImplTest {
IndividualAttestation individual_attestation;
AttestationConsent attestation_consent;
AuthenticatorStatus expected_status;
- const char* expected_attestation_format;
+ AttestationType expected_attestation;
const char* expected_certificate_substring;
};
@@ -1197,7 +1248,7 @@ class AuthenticatorContentBrowserClientTest : public AuthenticatorImplTest {
ASSERT_EQ(test.expected_status, callback_receiver.status());
if (test.expected_status != AuthenticatorStatus::SUCCESS) {
- ASSERT_STREQ("", test.expected_attestation_format);
+ ASSERT_EQ(AttestationType::ANY, test.expected_attestation);
continue;
}
@@ -1206,11 +1257,56 @@ class AuthenticatorContentBrowserClientTest : public AuthenticatorImplTest {
ASSERT_TRUE(attestation_value);
ASSERT_TRUE(attestation_value->is_map());
const auto& attestation = attestation_value->GetMap();
- ExpectMapHasKeyWithStringValue(attestation, "fmt",
- test.expected_attestation_format);
- if (strlen(test.expected_certificate_substring) > 0) {
- ExpectCertificateContainingSubstring(
- attestation, test.expected_certificate_substring);
+
+ switch (test.expected_attestation) {
+ case AttestationType::ANY:
+ ASSERT_STREQ("", test.expected_certificate_substring);
+ break;
+
+ case AttestationType::NONE:
+ ASSERT_STREQ("", test.expected_certificate_substring);
+ ExpectMapHasKeyWithStringValue(attestation, "fmt", "none");
+ break;
+
+ case AttestationType::U2F:
+ ExpectMapHasKeyWithStringValue(attestation, "fmt", "fido-u2f");
+ if (strlen(test.expected_certificate_substring) > 0) {
+ ExpectCertificateContainingSubstring(
+ attestation, test.expected_certificate_substring);
+ }
+ break;
+
+ case AttestationType::SELF:
+ ASSERT_STREQ("", test.expected_certificate_substring);
+ ExpectMapHasKeyWithStringValue(attestation, "fmt", "packed");
+
+ // A self-attestation should not include an X.509 chain nor ECDAA key.
+ const auto attestation_statement_it =
+ attestation.find(CBORValue("attStmt"));
+ ASSERT_TRUE(attestation_statement_it != attestation.end());
+ ASSERT_TRUE(attestation_statement_it->second.is_map());
+ const auto& attestation_statement =
+ attestation_statement_it->second.GetMap();
+
+ ASSERT_TRUE(attestation_statement.find(CBORValue("x5c")) ==
+ attestation_statement.end());
+ ASSERT_TRUE(attestation_statement.find(CBORValue("ecdaaKeyId")) ==
+ attestation_statement.end());
+
+ // The AAGUID should be all zero.
+ const auto auth_data_it = attestation.find(CBORValue("authData"));
+ ASSERT_TRUE(auth_data_it != attestation.end());
+ ASSERT_TRUE(auth_data_it->second.is_bytestring());
+ const std::vector<uint8_t>& auth_data =
+ auth_data_it->second.GetBytestring();
+ base::Optional<device::AuthenticatorData> parsed_auth_data =
+ device::AuthenticatorData::DecodeAuthenticatorData(auth_data);
+ ASSERT_TRUE(parsed_auth_data);
+ const base::Optional<device::AttestedCredentialData>& cred_data(
+ parsed_auth_data->attested_data());
+ ASSERT_TRUE(cred_data);
+ EXPECT_TRUE(cred_data->IsAaguidZero());
+ break;
}
}
}
@@ -1287,72 +1383,78 @@ TEST_F(AuthenticatorContentBrowserClientTest, AttestationBehaviour) {
{
AttestationConveyancePreference::NONE,
IndividualAttestation::NOT_REQUESTED, AttestationConsent::DENIED,
- AuthenticatorStatus::SUCCESS, "none", "",
+ AuthenticatorStatus::SUCCESS, AttestationType::NONE, "",
},
{
AttestationConveyancePreference::NONE,
IndividualAttestation::REQUESTED, AttestationConsent::DENIED,
- AuthenticatorStatus::SUCCESS, "none", "",
+ AuthenticatorStatus::SUCCESS, AttestationType::NONE, "",
},
{
AttestationConveyancePreference::INDIRECT,
IndividualAttestation::NOT_REQUESTED, AttestationConsent::DENIED,
- AuthenticatorStatus::NOT_ALLOWED_ERROR, "", "",
+ AuthenticatorStatus::NOT_ALLOWED_ERROR, AttestationType::ANY, "",
},
{
AttestationConveyancePreference::INDIRECT,
IndividualAttestation::REQUESTED, AttestationConsent::DENIED,
- AuthenticatorStatus::NOT_ALLOWED_ERROR, "", "",
+ AuthenticatorStatus::NOT_ALLOWED_ERROR, AttestationType::ANY, "",
},
{
AttestationConveyancePreference::INDIRECT,
IndividualAttestation::NOT_REQUESTED, AttestationConsent::GRANTED,
- AuthenticatorStatus::SUCCESS, "fido-u2f", kStandardCommonName,
+ AuthenticatorStatus::SUCCESS, AttestationType::U2F,
+ kStandardCommonName,
},
{
AttestationConveyancePreference::INDIRECT,
IndividualAttestation::REQUESTED, AttestationConsent::GRANTED,
- AuthenticatorStatus::SUCCESS, "fido-u2f", kStandardCommonName,
+ AuthenticatorStatus::SUCCESS, AttestationType::U2F,
+ kStandardCommonName,
},
{
AttestationConveyancePreference::DIRECT,
IndividualAttestation::NOT_REQUESTED, AttestationConsent::DENIED,
- AuthenticatorStatus::NOT_ALLOWED_ERROR, "", "",
+ AuthenticatorStatus::NOT_ALLOWED_ERROR, AttestationType::ANY, "",
},
{
AttestationConveyancePreference::DIRECT,
IndividualAttestation::REQUESTED, AttestationConsent::DENIED,
- AuthenticatorStatus::NOT_ALLOWED_ERROR, "", "",
+ AuthenticatorStatus::NOT_ALLOWED_ERROR, AttestationType::ANY, "",
},
{
AttestationConveyancePreference::DIRECT,
IndividualAttestation::NOT_REQUESTED, AttestationConsent::GRANTED,
- AuthenticatorStatus::SUCCESS, "fido-u2f", kStandardCommonName,
+ AuthenticatorStatus::SUCCESS, AttestationType::U2F,
+ kStandardCommonName,
},
{
AttestationConveyancePreference::DIRECT,
IndividualAttestation::REQUESTED, AttestationConsent::GRANTED,
- AuthenticatorStatus::SUCCESS, "fido-u2f", kStandardCommonName,
+ AuthenticatorStatus::SUCCESS, AttestationType::U2F,
+ kStandardCommonName,
},
{
AttestationConveyancePreference::ENTERPRISE,
IndividualAttestation::NOT_REQUESTED, AttestationConsent::DENIED,
- AuthenticatorStatus::NOT_ALLOWED_ERROR, "", "",
+ AuthenticatorStatus::NOT_ALLOWED_ERROR, AttestationType::ANY, "",
},
{
AttestationConveyancePreference::ENTERPRISE,
IndividualAttestation::REQUESTED, AttestationConsent::DENIED,
- AuthenticatorStatus::NOT_ALLOWED_ERROR, "", "",
+ AuthenticatorStatus::NOT_ALLOWED_ERROR, AttestationType::ANY, "",
},
{
AttestationConveyancePreference::ENTERPRISE,
IndividualAttestation::NOT_REQUESTED, AttestationConsent::GRANTED,
- AuthenticatorStatus::SUCCESS, "fido-u2f", kStandardCommonName,
+ AuthenticatorStatus::SUCCESS, AttestationType::U2F,
+ kStandardCommonName,
},
{
AttestationConveyancePreference::ENTERPRISE,
IndividualAttestation::REQUESTED, AttestationConsent::GRANTED,
- AuthenticatorStatus::SUCCESS, "fido-u2f", kIndividualCommonName,
+ AuthenticatorStatus::SUCCESS, AttestationType::U2F,
+ kIndividualCommonName,
},
};
@@ -1375,7 +1477,7 @@ TEST_F(AuthenticatorContentBrowserClientTest,
{
AttestationConveyancePreference::ENTERPRISE,
IndividualAttestation::NOT_REQUESTED, AttestationConsent::DENIED,
- AuthenticatorStatus::NOT_ALLOWED_ERROR, "", "",
+ AuthenticatorStatus::NOT_ALLOWED_ERROR, AttestationType::ANY, "",
},
{
AttestationConveyancePreference::DIRECT,
@@ -1384,7 +1486,7 @@ TEST_F(AuthenticatorContentBrowserClientTest,
// If individual attestation was not requested then the attestation
// certificate will be removed, even if consent is given, because
// the consent isn't to be tracked.
- "none", "",
+ AttestationType::NONE, "",
},
{
AttestationConveyancePreference::ENTERPRISE,
@@ -1393,13 +1495,13 @@ TEST_F(AuthenticatorContentBrowserClientTest,
// If individual attestation was not requested then the attestation
// certificate will be removed, even if consent is given, because
// the consent isn't to be tracked.
- "none", "",
+ AttestationType::NONE, "",
},
{
AttestationConveyancePreference::ENTERPRISE,
IndividualAttestation::REQUESTED, AttestationConsent::GRANTED,
- AuthenticatorStatus::SUCCESS, "fido-u2f", kCommonName,
+ AuthenticatorStatus::SUCCESS, AttestationType::U2F, kCommonName,
},
};
@@ -1411,6 +1513,59 @@ TEST_F(AuthenticatorContentBrowserClientTest,
RunTestCases(kTests);
}
+TEST_F(AuthenticatorContentBrowserClientTest, Ctap2SelfAttestation) {
+ virtual_device_.SetSupportedProtocol(device::ProtocolVersion::kCtap);
+ virtual_device_.mutable_state()->self_attestation = true;
+ NavigateAndCommit(GURL("https://example.com"));
+
+ const std::vector<TestCase> kTests = {
+ {
+ // If no attestation is requested, we'll return the self attestation
+ // rather than erasing it.
+ AttestationConveyancePreference::NONE,
+ IndividualAttestation::NOT_REQUESTED, AttestationConsent::DENIED,
+ AuthenticatorStatus::SUCCESS, AttestationType::SELF, "",
+ },
+ {
+ // If attestation is requested, but denied, we'll still fail the
+ // request.
+ AttestationConveyancePreference::DIRECT,
+ IndividualAttestation::NOT_REQUESTED, AttestationConsent::DENIED,
+ AuthenticatorStatus::NOT_ALLOWED_ERROR, AttestationType::ANY, "",
+ },
+ {
+ // If attestation is requested and granted, the self attestation
+ // will be returned.
+ AttestationConveyancePreference::DIRECT,
+ IndividualAttestation::NOT_REQUESTED, AttestationConsent::GRANTED,
+ AuthenticatorStatus::SUCCESS, AttestationType::SELF, "",
+ },
+ };
+
+ RunTestCases(kTests);
+}
+
+TEST_F(AuthenticatorContentBrowserClientTest,
+ Ctap2SelfAttestationNonZeroAaguid) {
+ virtual_device_.SetSupportedProtocol(device::ProtocolVersion::kCtap);
+ virtual_device_.mutable_state()->self_attestation = true;
+ virtual_device_.mutable_state()->non_zero_aaguid_with_self_attestation = true;
+ NavigateAndCommit(GURL("https://example.com"));
+
+ const std::vector<TestCase> kTests = {
+ {
+ // Since the virtual device is configured to set a non-zero AAGUID
+ // the self-attestation should still be replaced with a "none"
+ // attestation.
+ AttestationConveyancePreference::NONE,
+ IndividualAttestation::NOT_REQUESTED, AttestationConsent::DENIED,
+ AuthenticatorStatus::SUCCESS, AttestationType::NONE, "",
+ },
+ };
+
+ RunTestCases(kTests);
+}
+
TEST_F(AuthenticatorContentBrowserClientTest,
MakeCredentialRequestStartedCallback) {
TestServiceManagerContext smc;
@@ -1421,7 +1576,8 @@ TEST_F(AuthenticatorContentBrowserClientTest,
GetTestPublicKeyCredentialCreationOptions();
TestRequestStartedCallback request_started;
- test_client_.request_started_callback = request_started.callback();
+ test_client_.action_callbacks_registered_callback =
+ request_started.callback();
authenticator->MakeCredential(std::move(options), base::DoNothing());
request_started.WaitForCallback();
}
@@ -1436,7 +1592,8 @@ TEST_F(AuthenticatorContentBrowserClientTest,
GetTestPublicKeyCredentialRequestOptions();
TestRequestStartedCallback request_started;
- test_client_.request_started_callback = request_started.callback();
+ test_client_.action_callbacks_registered_callback =
+ request_started.callback();
authenticator->GetAssertion(std::move(options), base::DoNothing());
request_started.WaitForCallback();
}
@@ -1457,7 +1614,8 @@ TEST_F(AuthenticatorContentBrowserClientTest, Unfocused) {
TestMakeCredentialCallback cb;
TestRequestStartedCallback request_started;
- test_client_.request_started_callback = request_started.callback();
+ test_client_.action_callbacks_registered_callback =
+ request_started.callback();
authenticator->MakeCredential(std::move(options), cb.callback());
cb.WaitForCallback();
@@ -1475,13 +1633,16 @@ TEST_F(AuthenticatorContentBrowserClientTest, Unfocused) {
auto credential = PublicKeyCredentialDescriptor::New();
credential->type = PublicKeyCredentialType::PUBLIC_KEY;
credential->id.resize(16);
+ credential->transports = {AuthenticatorTransport::USB};
+
ASSERT_TRUE(virtual_device_.mutable_state()->InjectRegistration(
credential->id, kTestRelyingPartyId));
options->allow_credentials.emplace_back(std::move(credential));
TestGetAssertionCallback cb;
TestRequestStartedCallback request_started;
- test_client_.request_started_callback = request_started.callback();
+ test_client_.action_callbacks_registered_callback =
+ request_started.callback();
authenticator->GetAssertion(std::move(options), cb.callback());
cb.WaitForCallback();
@@ -1519,4 +1680,333 @@ TEST_F(AuthenticatorContentBrowserClientTest,
}
}
+#if defined(OS_MACOSX)
+TEST_F(AuthenticatorContentBrowserClientTest,
+ IsUVPAAFalseIfEmbedderDoesNotSupportTouchId) {
+ if (__builtin_available(macOS 10.12.2, *)) {
+ // Touch ID is hardware-supported, and flag-enabled, but not enabled by the
+ // embedder.
+ EnableFeature(device::kWebAuthTouchId);
+ device::fido::mac::ScopedTouchIdTestEnvironment touch_id_test_environment;
+ touch_id_test_environment.SetTouchIdAvailable(true);
+ test_client_.supports_touch_id = false;
+
+ NavigateAndCommit(GURL(kTestOrigin1));
+ AuthenticatorPtr authenticator = ConnectToAuthenticator();
+
+ TestIsUvpaaCallback cb;
+ authenticator->IsUserVerifyingPlatformAuthenticatorAvailable(cb.callback());
+ cb.WaitForCallback();
+ EXPECT_FALSE(cb.value());
+ }
+}
+
+TEST_F(AuthenticatorContentBrowserClientTest, IsUVPAAFalseIfFeatureFlagOff) {
+ if (__builtin_available(macOS 10.12.2, *)) {
+ // Touch ID is hardware-supported and embedder-enabled, but the flag is off.
+ device::fido::mac::ScopedTouchIdTestEnvironment touch_id_test_environment;
+ touch_id_test_environment.SetTouchIdAvailable(true);
+ test_client_.supports_touch_id = true;
+
+ NavigateAndCommit(GURL(kTestOrigin1));
+ AuthenticatorPtr authenticator = ConnectToAuthenticator();
+
+ TestIsUvpaaCallback cb;
+ authenticator->IsUserVerifyingPlatformAuthenticatorAvailable(cb.callback());
+ cb.WaitForCallback();
+ EXPECT_FALSE(cb.value());
+ }
+}
+
+TEST_F(AuthenticatorContentBrowserClientTest, IsUVPAATrueIfTouchIdAvailable) {
+ if (__builtin_available(macOS 10.12.2, *)) {
+ // Touch ID is available.
+ EnableFeature(device::kWebAuthTouchId);
+ device::fido::mac::ScopedTouchIdTestEnvironment touch_id_test_environment;
+ touch_id_test_environment.SetTouchIdAvailable(true);
+ test_client_.supports_touch_id = true;
+
+ NavigateAndCommit(GURL(kTestOrigin1));
+ AuthenticatorPtr authenticator = ConnectToAuthenticator();
+
+ TestIsUvpaaCallback cb;
+ authenticator->IsUserVerifyingPlatformAuthenticatorAvailable(cb.callback());
+ cb.WaitForCallback();
+ EXPECT_TRUE(cb.value());
+ }
+}
+#endif // defined(OS_MACOSX)
+
+#if !defined(OS_MACOSX)
+TEST_F(AuthenticatorContentBrowserClientTest, IsUVPAAFalse) {
+ // No platform authenticator on non-macOS platforms.
+ NavigateAndCommit(GURL(kTestOrigin1));
+ AuthenticatorPtr authenticator = ConnectToAuthenticator();
+
+ TestIsUvpaaCallback cb;
+ authenticator->IsUserVerifyingPlatformAuthenticatorAvailable(cb.callback());
+ cb.WaitForCallback();
+ EXPECT_FALSE(cb.value());
+}
+#endif // !defined(OS_MACOSX)
+
+class MockAuthenticatorRequestDelegateObserver
+ : public TestAuthenticatorRequestDelegate {
+ public:
+ using InterestingFailureReasonCallback =
+ base::OnceCallback<void(InterestingFailureReason)>;
+
+ MockAuthenticatorRequestDelegateObserver(
+ InterestingFailureReasonCallback failure_reasons_callback =
+ base::DoNothing())
+ : TestAuthenticatorRequestDelegate(
+ nullptr /* render_frame_host */,
+ base::DoNothing() /* did_start_request_callback */,
+ IndividualAttestation::NOT_REQUESTED,
+ AttestationConsent::DENIED,
+ true /* is_focused */),
+ failure_reasons_callback_(std::move(failure_reasons_callback)) {}
+ ~MockAuthenticatorRequestDelegateObserver() override = default;
+
+ void DidFailWithInterestingReason(InterestingFailureReason reason) override {
+ ASSERT_TRUE(failure_reasons_callback_);
+ std::move(failure_reasons_callback_).Run(reason);
+ }
+
+ MOCK_METHOD1(
+ OnTransportAvailabilityEnumerated,
+ void(device::FidoRequestHandlerBase::TransportAvailabilityInfo data));
+ MOCK_METHOD1(EmbedderControlsAuthenticatorDispatch,
+ bool(const device::FidoAuthenticator&));
+ MOCK_METHOD1(FidoAuthenticatorAdded, void(const device::FidoAuthenticator&));
+ MOCK_METHOD1(FidoAuthenticatorRemoved, void(base::StringPiece));
+
+ private:
+ InterestingFailureReasonCallback failure_reasons_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockAuthenticatorRequestDelegateObserver);
+};
+
+// Fake test construct that shares all other behavior with AuthenticatorImpl
+// except that:
+// - FakeAuthenticatorImpl does not trigger UI activity.
+// - MockAuthenticatorRequestDelegateObserver is injected to
+// |request_delegate_|
+// instead of ChromeAuthenticatorRequestDelegate.
+class FakeAuthenticatorImpl : public AuthenticatorImpl {
+ public:
+ explicit FakeAuthenticatorImpl(
+ RenderFrameHost* render_frame_host,
+ service_manager::Connector* connector,
+ std::unique_ptr<base::OneShotTimer> timer,
+ std::unique_ptr<MockAuthenticatorRequestDelegateObserver> mock_delegate)
+ : AuthenticatorImpl(render_frame_host, connector, std::move(timer)),
+ mock_delegate_(std::move(mock_delegate)) {}
+ ~FakeAuthenticatorImpl() override = default;
+
+ void UpdateRequestDelegate() override {
+ DCHECK(mock_delegate_);
+ request_delegate_ = std::move(mock_delegate_);
+ }
+
+ private:
+ friend class AuthenticatorImplRequestDelegateTest;
+
+ std::unique_ptr<MockAuthenticatorRequestDelegateObserver> mock_delegate_;
+};
+
+class AuthenticatorImplRequestDelegateTest : public AuthenticatorImplTest {
+ public:
+ AuthenticatorImplRequestDelegateTest() {}
+ ~AuthenticatorImplRequestDelegateTest() override {}
+
+ void TearDown() override {
+ // The |RenderFrameHost| must outlive |AuthenticatorImpl|.
+ authenticator_impl_.reset();
+ content::RenderViewHostTestHarness::TearDown();
+ }
+
+ AuthenticatorPtr ConnectToFakeAuthenticator(
+ std::unique_ptr<MockAuthenticatorRequestDelegateObserver> delegate,
+ service_manager::Connector* connector,
+ std::unique_ptr<base::OneShotTimer> timer) {
+ authenticator_impl_.reset(new FakeAuthenticatorImpl(
+ main_rfh(), connector, std::move(timer), std::move(delegate)));
+ AuthenticatorPtr authenticator;
+ authenticator_impl_->Bind(mojo::MakeRequest(&authenticator));
+ return authenticator;
+ }
+
+ AuthenticatorPtr ConstructFakeAuthenticatorWithTimer(
+ std::unique_ptr<MockAuthenticatorRequestDelegateObserver> delegate,
+ scoped_refptr<base::TestMockTimeTaskRunner> task_runner) {
+ connector_ = service_manager::Connector::Create(&request_);
+ fake_hid_manager_ = std::make_unique<device::FakeHidManager>();
+ service_manager::Connector::TestApi test_api(connector_.get());
+ test_api.OverrideBinderForTesting(
+ service_manager::Identity(device::mojom::kServiceName),
+ device::mojom::HidManager::Name_,
+ base::Bind(&device::FakeHidManager::AddBinding,
+ base::Unretained(fake_hid_manager_.get())));
+
+ // Set up a timer for testing.
+ auto timer =
+ std::make_unique<base::OneShotTimer>(task_runner->GetMockTickClock());
+ timer->SetTaskRunner(task_runner);
+ return ConnectToFakeAuthenticator(std::move(delegate), connector_.get(),
+ std::move(timer));
+ }
+
+ protected:
+ std::unique_ptr<FakeAuthenticatorImpl> authenticator_impl_;
+};
+
+TEST_F(AuthenticatorImplRequestDelegateTest,
+ TestRequestDelegateObservesFidoRequestHandler) {
+ EnableFeature(features::kWebAuthBle);
+ auto mock_adapter =
+ base::MakeRefCounted<::testing::NiceMock<device::MockBluetoothAdapter>>();
+ EXPECT_CALL(*mock_adapter, IsPresent())
+ .WillRepeatedly(::testing::Return(true));
+ device::BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
+ auto bluetooth_adapter_factory_overrides =
+ device::BluetoothAdapterFactory::Get().InitGlobalValuesForTesting();
+ bluetooth_adapter_factory_overrides->SetLESupported(true);
+
+ device::test::ScopedFakeFidoDiscoveryFactory discovery_factory;
+ auto* fake_ble_discovery = discovery_factory.ForgeNextBleDiscovery();
+
+ SimulateNavigation(GURL(kTestOrigin1));
+ PublicKeyCredentialRequestOptionsPtr options =
+ GetTestPublicKeyCredentialRequestOptions();
+ TestGetAssertionCallback callback_receiver;
+ auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
+ base::Time::Now(), base::TimeTicks::Now());
+
+ auto mock_delegate =
+ std::make_unique<MockAuthenticatorRequestDelegateObserver>();
+ auto* const mock_delegate_ptr = mock_delegate.get();
+ auto authenticator = ConstructFakeAuthenticatorWithTimer(
+ std::move(mock_delegate), task_runner);
+
+ auto mock_ble_device = device::MockFidoDevice::MakeCtap();
+ mock_ble_device->StubGetId();
+ mock_ble_device->SetDeviceTransport(
+ device::FidoTransportProtocol::kBluetoothLowEnergy);
+ const auto device_id = mock_ble_device->GetId();
+
+ EXPECT_CALL(*mock_delegate_ptr, OnTransportAvailabilityEnumerated(_));
+ EXPECT_CALL(*mock_delegate_ptr, EmbedderControlsAuthenticatorDispatch(_))
+ .WillOnce(testing::Return(true));
+
+ base::RunLoop ble_device_found_done;
+ EXPECT_CALL(*mock_delegate_ptr, FidoAuthenticatorAdded(_))
+ .WillOnce(testing::InvokeWithoutArgs(
+ [&ble_device_found_done]() { ble_device_found_done.Quit(); }));
+
+ base::RunLoop ble_device_lost_done;
+ EXPECT_CALL(*mock_delegate_ptr, FidoAuthenticatorRemoved(_))
+ .WillOnce(testing::InvokeWithoutArgs(
+ [&ble_device_lost_done]() { ble_device_lost_done.Quit(); }));
+
+ authenticator->GetAssertion(std::move(options), callback_receiver.callback());
+ fake_ble_discovery->WaitForCallToStartAndSimulateSuccess();
+ fake_ble_discovery->AddDevice(std::move(mock_ble_device));
+ ble_device_found_done.Run();
+
+ fake_ble_discovery->RemoveDevice(device_id);
+ ble_device_lost_done.Run();
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(AuthenticatorImplRequestDelegateTest, FailureReasonForTimeout) {
+ SimulateNavigation(GURL(kTestOrigin1));
+
+ FailureReasonCallbackReceiver failure_reason_receiver;
+ auto mock_delegate = std::make_unique<
+ ::testing::NiceMock<MockAuthenticatorRequestDelegateObserver>>(
+ failure_reason_receiver.callback());
+ auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
+ base::Time::Now(), base::TimeTicks::Now());
+ auto authenticator = ConstructFakeAuthenticatorWithTimer(
+ std::move(mock_delegate), task_runner);
+
+ TestGetAssertionCallback callback_receiver;
+ authenticator->GetAssertion(GetTestPublicKeyCredentialRequestOptions(),
+ callback_receiver.callback());
+
+ base::RunLoop().RunUntilIdle();
+ task_runner->FastForwardBy(base::TimeDelta::FromMinutes(1));
+
+ callback_receiver.WaitForCallback();
+ EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR, callback_receiver.status());
+
+ ASSERT_TRUE(failure_reason_receiver.was_called());
+ EXPECT_EQ(content::AuthenticatorRequestClientDelegate::
+ InterestingFailureReason::kTimeout,
+ std::get<0>(*failure_reason_receiver.result()));
+}
+
+TEST_F(AuthenticatorImplRequestDelegateTest,
+ FailureReasonForDuplicateRegistration) {
+ device::test::ScopedVirtualFidoDevice scoped_virtual_device;
+ SimulateNavigation(GURL(kTestOrigin1));
+
+ FailureReasonCallbackReceiver failure_reason_receiver;
+ auto mock_delegate = std::make_unique<
+ ::testing::NiceMock<MockAuthenticatorRequestDelegateObserver>>(
+ failure_reason_receiver.callback());
+ auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
+ base::Time::Now(), base::TimeTicks::Now());
+ auto authenticator = ConstructFakeAuthenticatorWithTimer(
+ std::move(mock_delegate), task_runner);
+
+ PublicKeyCredentialCreationOptionsPtr options =
+ GetTestPublicKeyCredentialCreationOptions();
+ options->exclude_credentials = GetTestAllowCredentials();
+ ASSERT_TRUE(scoped_virtual_device.mutable_state()->InjectRegistration(
+ options->exclude_credentials[0]->id, kTestRelyingPartyId));
+
+ TestMakeCredentialCallback callback_receiver;
+ authenticator->MakeCredential(std::move(options),
+ callback_receiver.callback());
+
+ callback_receiver.WaitForCallback();
+ EXPECT_EQ(AuthenticatorStatus::CREDENTIAL_EXCLUDED,
+ callback_receiver.status());
+
+ ASSERT_TRUE(failure_reason_receiver.was_called());
+ EXPECT_EQ(content::AuthenticatorRequestClientDelegate::
+ InterestingFailureReason::kKeyAlreadyRegistered,
+ std::get<0>(*failure_reason_receiver.result()));
+}
+
+TEST_F(AuthenticatorImplRequestDelegateTest,
+ FailureReasonForMissingRegistration) {
+ device::test::ScopedVirtualFidoDevice scoped_virtual_device;
+ SimulateNavigation(GURL(kTestOrigin1));
+
+ FailureReasonCallbackReceiver failure_reason_receiver;
+ auto mock_delegate = std::make_unique<
+ ::testing::NiceMock<MockAuthenticatorRequestDelegateObserver>>(
+ failure_reason_receiver.callback());
+ auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
+ base::Time::Now(), base::TimeTicks::Now());
+ auto authenticator = ConstructFakeAuthenticatorWithTimer(
+ std::move(mock_delegate), task_runner);
+
+ TestGetAssertionCallback callback_receiver;
+ authenticator->GetAssertion(GetTestPublicKeyCredentialRequestOptions(),
+ callback_receiver.callback());
+
+ callback_receiver.WaitForCallback();
+ EXPECT_EQ(AuthenticatorStatus::CREDENTIAL_NOT_RECOGNIZED,
+ callback_receiver.status());
+
+ ASSERT_TRUE(failure_reason_receiver.was_called());
+ EXPECT_EQ(content::AuthenticatorRequestClientDelegate::
+ InterestingFailureReason::kKeyNotRegistered,
+ std::get<0>(*failure_reason_receiver.result()));
+}
+
} // namespace content
diff --git a/chromium/content/browser/webauth/authenticator_type_converters.cc b/chromium/content/browser/webauth/authenticator_type_converters.cc
index 28985e8756f..b916b86a15c 100644
--- a/chromium/content/browser/webauth/authenticator_type_converters.cc
+++ b/chromium/content/browser/webauth/authenticator_type_converters.cc
@@ -5,7 +5,9 @@
#include "content/browser/webauth/authenticator_type_converters.h"
#include <algorithm>
+#include <utility>
+#include "base/containers/flat_set.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_parsing_utils.h"
@@ -33,6 +35,10 @@ TypeConverter<::device::FidoTransportProtocol, AuthenticatorTransport>::Convert(
return ::device::FidoTransportProtocol::kNearFieldCommunication;
case AuthenticatorTransport::BLE:
return ::device::FidoTransportProtocol::kBluetoothLowEnergy;
+ case AuthenticatorTransport::CABLE:
+ return ::device::FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy;
+ case AuthenticatorTransport::INTERNAL:
+ return ::device::FidoTransportProtocol::kInternal;
}
NOTREACHED();
return ::device::FidoTransportProtocol::kUsbHumanInterfaceDevice;
@@ -78,8 +84,14 @@ TypeConverter<std::vector<::device::PublicKeyCredentialDescriptor>,
credential_descriptors.reserve(input.size());
for (const auto& credential : input) {
+ base::flat_set<::device::FidoTransportProtocol> protocols;
+ for (const auto& protocol : credential->transports) {
+ protocols.emplace(ConvertTo<::device::FidoTransportProtocol>(protocol));
+ }
+
credential_descriptors.emplace_back(::device::PublicKeyCredentialDescriptor(
- ConvertTo<::device::CredentialType>(credential->type), credential->id));
+ ConvertTo<::device::CredentialType>(credential->type), credential->id,
+ std::move(protocols)));
}
return credential_descriptors;
}
@@ -162,30 +174,30 @@ TypeConverter<::device::PublicKeyCredentialUserEntity,
}
// static
-std::vector<::device::FidoCableDiscovery::CableDiscoveryData>
-TypeConverter<std::vector<::device::FidoCableDiscovery::CableDiscoveryData>,
+std::vector<::device::CableDiscoveryData>
+TypeConverter<std::vector<::device::CableDiscoveryData>,
std::vector<CableAuthenticationPtr>>::
Convert(const std::vector<CableAuthenticationPtr>& input) {
- std::vector<::device::FidoCableDiscovery::CableDiscoveryData> discovery_data;
+ std::vector<::device::CableDiscoveryData> discovery_data;
discovery_data.reserve(input.size());
for (const auto& data : input) {
- ::device::FidoCableDiscovery::EidArray client_eid;
+ ::device::EidArray client_eid;
DCHECK_EQ(client_eid.size(), data->client_eid.size());
std::copy(data->client_eid.begin(), data->client_eid.end(),
client_eid.begin());
- ::device::FidoCableDiscovery::EidArray authenticator_eid;
+ ::device::EidArray authenticator_eid;
DCHECK_EQ(authenticator_eid.size(), data->authenticator_eid.size());
std::copy(data->authenticator_eid.begin(), data->authenticator_eid.end(),
authenticator_eid.begin());
- ::device::FidoCableDiscovery::SessionPreKeyArray session_pre_key;
+ ::device::SessionPreKeyArray session_pre_key;
DCHECK_EQ(session_pre_key.size(), data->session_pre_key.size());
std::copy(data->session_pre_key.begin(), data->session_pre_key.end(),
session_pre_key.begin());
- discovery_data.push_back(::device::FidoCableDiscovery::CableDiscoveryData{
+ discovery_data.push_back(::device::CableDiscoveryData{
data->version, client_eid, authenticator_eid, session_pre_key});
}
diff --git a/chromium/content/browser/webauth/authenticator_type_converters.h b/chromium/content/browser/webauth/authenticator_type_converters.h
index cc4a53db728..90fd80fb7c6 100644
--- a/chromium/content/browser/webauth/authenticator_type_converters.h
+++ b/chromium/content/browser/webauth/authenticator_type_converters.h
@@ -8,14 +8,14 @@
#include <vector>
#include "device/fido/authenticator_selection_criteria.h"
-#include "device/fido/fido_cable_discovery.h"
+#include "device/fido/cable/cable_discovery_data.h"
#include "device/fido/fido_transport_protocol.h"
#include "device/fido/public_key_credential_descriptor.h"
#include "device/fido/public_key_credential_params.h"
#include "device/fido/public_key_credential_rp_entity.h"
#include "device/fido/public_key_credential_user_entity.h"
#include "mojo/public/cpp/bindings/type_converter.h"
-#include "third_party/blink/public/platform/modules/webauth/authenticator.mojom.h"
+#include "third_party/blink/public/platform/modules/webauthn/authenticator.mojom.h"
// TODO(hongjunchoi): Remove type converters and instead expose mojo interface
// directly from device/fido service.
@@ -91,10 +91,9 @@ struct TypeConverter<::device::PublicKeyCredentialUserEntity,
};
template <>
-struct TypeConverter<
- std::vector<::device::FidoCableDiscovery::CableDiscoveryData>,
- std::vector<::blink::mojom::CableAuthenticationPtr>> {
- static std::vector<::device::FidoCableDiscovery::CableDiscoveryData> Convert(
+struct TypeConverter<std::vector<::device::CableDiscoveryData>,
+ std::vector<::blink::mojom::CableAuthenticationPtr>> {
+ static std::vector<::device::CableDiscoveryData> Convert(
const std::vector<::blink::mojom::CableAuthenticationPtr>& input);
};
diff --git a/chromium/content/browser/webauth/scoped_virtual_authenticator_environment.h b/chromium/content/browser/webauth/scoped_virtual_authenticator_environment.h
index 378de2ff2db..0c0bf6f47b9 100644
--- a/chromium/content/browser/webauth/scoped_virtual_authenticator_environment.h
+++ b/chromium/content/browser/webauth/scoped_virtual_authenticator_environment.h
@@ -15,7 +15,7 @@
#include "content/common/content_export.h"
#include "device/fido/fido_discovery.h"
#include "mojo/public/cpp/bindings/binding_set.h"
-#include "third_party/blink/public/platform/modules/webauth/virtual_authenticator.mojom.h"
+#include "third_party/blink/public/platform/modules/webauthn/virtual_authenticator.mojom.h"
namespace content {
diff --git a/chromium/content/browser/webauth/virtual_authenticator.cc b/chromium/content/browser/webauth/virtual_authenticator.cc
index b93637c3189..4fbc6ae976e 100644
--- a/chromium/content/browser/webauth/virtual_authenticator.cc
+++ b/chromium/content/browser/webauth/virtual_authenticator.cc
@@ -7,6 +7,7 @@
#include <utility>
#include <vector>
+#include "base/containers/span.h"
#include "base/guid.h"
#include "crypto/ec_private_key.h"
#include "device/fido/virtual_u2f_device.h"
@@ -64,7 +65,9 @@ void VirtualAuthenticator::AddRegistration(
::device::VirtualFidoDevice::RegistrationData(
crypto::ECPrivateKey::CreateFromPrivateKeyInfo(
registration->private_key),
- registration->application_parameter, registration->counter));
+ base::make_span<device::kRpIdHashLength>(
+ registration->application_parameter),
+ registration->counter));
std::move(callback).Run(success);
}
diff --git a/chromium/content/browser/webauth/virtual_authenticator.h b/chromium/content/browser/webauth/virtual_authenticator.h
index d048250f30b..fe8ecc1719f 100644
--- a/chromium/content/browser/webauth/virtual_authenticator.h
+++ b/chromium/content/browser/webauth/virtual_authenticator.h
@@ -14,7 +14,7 @@
#include "device/fido/fido_transport_protocol.h"
#include "device/fido/virtual_fido_device.h"
#include "mojo/public/cpp/bindings/binding_set.h"
-#include "third_party/blink/public/platform/modules/webauth/virtual_authenticator.mojom.h"
+#include "third_party/blink/public/platform/modules/webauthn/virtual_authenticator.mojom.h"
namespace content {
diff --git a/chromium/content/browser/webauth/webauth_browsertest.cc b/chromium/content/browser/webauth/webauth_browsertest.cc
index 3943e65820e..57bc30c924b 100644
--- a/chromium/content/browser/webauth/webauth_browsertest.cc
+++ b/chromium/content/browser/webauth/webauth_browsertest.cc
@@ -32,8 +32,8 @@
#include "content/test/did_commit_provisional_load_interceptor.h"
#include "device/base/features.h"
#include "device/fido/fake_fido_discovery.h"
-#include "device/fido/fake_hid_impl_for_testing.h"
#include "device/fido/fido_test_data.h"
+#include "device/fido/hid/fake_hid_impl_for_testing.h"
#include "device/fido/mock_fido_device.h"
#include "device/fido/scoped_virtual_fido_device.h"
#include "device/fido/test_callback_receiver.h"
@@ -42,7 +42,7 @@
#include "services/service_manager/public/cpp/connector.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/modules/webauth/authenticator.mojom.h"
+#include "third_party/blink/public/platform/modules/webauthn/authenticator.mojom.h"
namespace content {
diff --git a/chromium/content/browser/webrtc/webrtc_audio_browsertest.cc b/chromium/content/browser/webrtc/webrtc_audio_browsertest.cc
index d0679ee756a..308f749f75d 100644
--- a/chromium/content/browser/webrtc/webrtc_audio_browsertest.cc
+++ b/chromium/content/browser/webrtc/webrtc_audio_browsertest.cc
@@ -16,12 +16,10 @@
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "media/base/media_switches.h"
+#include "media/webrtc/webrtc_switches.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "testing/gtest/include/gtest/gtest-param-test.h"
-
-#if defined(OS_WIN)
#include "services/service_manager/sandbox/features.h"
-#endif
+#include "testing/gtest/include/gtest/gtest-param-test.h"
namespace content {
@@ -37,6 +35,9 @@ enum class AudioServiceFeatures {
#if defined(OS_WIN)
kSandboxed,
#endif
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
+ kSandboxedWithAudioServiceAPM
+#endif
};
} // namespace
@@ -77,6 +78,13 @@ class WebRtcAudioBrowserTest
{});
break;
#endif
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
+ case AudioServiceFeatures::kSandboxedWithAudioServiceAPM:
+ audio_service_oop_features.push_back(
+ service_manager::features::kAudioServiceSandbox);
+ audio_service_oop_features.push_back(
+ features::kWebRtcApmInAudioService);
+#endif
}
}
~WebRtcAudioBrowserTest() override {}
@@ -172,17 +180,21 @@ IN_PROC_BROWSER_TEST_P(WebRtcAudioBrowserTest,
// removed after launch.
#if defined(OS_LINUX) || defined(OS_MACOSX)
// Supported platforms.
-INSTANTIATE_TEST_CASE_P(,
- WebRtcAudioBrowserTest,
- ::testing::Values(AudioServiceFeatures::kDisabled,
- AudioServiceFeatures::kOutOfProcess));
+INSTANTIATE_TEST_CASE_P(
+ ,
+ WebRtcAudioBrowserTest,
+ ::testing::Values(AudioServiceFeatures::kDisabled,
+ AudioServiceFeatures::kOutOfProcess,
+ AudioServiceFeatures::kSandboxedWithAudioServiceAPM));
#elif defined(OS_WIN)
// On Windows, also run in sandboxed mode.
-INSTANTIATE_TEST_CASE_P(,
- WebRtcAudioBrowserTest,
- ::testing::Values(AudioServiceFeatures::kDisabled,
- AudioServiceFeatures::kOutOfProcess,
- AudioServiceFeatures::kSandboxed));
+INSTANTIATE_TEST_CASE_P(
+ ,
+ WebRtcAudioBrowserTest,
+ ::testing::Values(AudioServiceFeatures::kDisabled,
+ AudioServiceFeatures::kOutOfProcess,
+ AudioServiceFeatures::kSandboxed,
+ AudioServiceFeatures::kSandboxedWithAudioServiceAPM));
#elif defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
// Renderer crashes under Android ASAN: https://crbug.com/408496.
#else
diff --git a/chromium/content/browser/webrtc/webrtc_audio_debug_recordings_browsertest.cc b/chromium/content/browser/webrtc/webrtc_audio_debug_recordings_browsertest.cc
index 965c78d992f..65b3adef54f 100644
--- a/chromium/content/browser/webrtc/webrtc_audio_debug_recordings_browsertest.cc
+++ b/chromium/content/browser/webrtc/webrtc_audio_debug_recordings_browsertest.cc
@@ -34,19 +34,6 @@ const int kWaveHeaderSizeBytes = 44;
const base::FilePath::CharType kBaseFilename[] =
FILE_PATH_LITERAL("audio_debug");
-// Get the ID for the render process host when there should only be one.
-bool GetRenderProcessHostId(base::ProcessId* id) {
- content::RenderProcessHost::iterator it(
- content::RenderProcessHost::AllHostsIterator());
- *id = it.GetCurrentValue()->GetProcess().Pid();
- EXPECT_NE(base::kNullProcessId, *id);
- if (*id == base::kNullProcessId)
- return false;
- it.Advance();
- EXPECT_TRUE(it.IsAtEnd());
- return it.IsAtEnd();
-}
-
// Get the expected AEC dump file name. The name will be
// <temporary path>.<render process id>.aec_dump.<consumer id>, for example
// "/tmp/.com.google.Chrome.Z6UC3P.12345.aec_dump.1".
@@ -104,10 +91,11 @@ class WebRtcAudioDebugRecordingsBrowserTest
~WebRtcAudioDebugRecordingsBrowserTest() override {}
};
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_LINUX)
// Renderer crashes under Android ASAN: https://crbug.com/408496.
// Renderer crashes under Android: https://crbug.com/820934.
// Failures on Android M. https://crbug.com/535728.
+// Flaky on Linux: https://crbug.com/871182
#define MAYBE_CallWithAudioDebugRecordings DISABLED_CallWithAudioDebugRecordings
#else
#define MAYBE_CallWithAudioDebugRecordings CallWithAudioDebugRecordings
@@ -182,8 +170,8 @@ IN_PROC_BROWSER_TEST_F(WebRtcAudioDebugRecordingsBrowserTest,
}
// Verify that the expected AEC dump file exists and contains some data.
- base::ProcessId render_process_id = base::kNullProcessId;
- EXPECT_TRUE(GetRenderProcessHostId(&render_process_id));
+ base::ProcessId render_process_id =
+ shell()->web_contents()->GetMainFrame()->GetProcess()->GetProcess().Pid();
base::FilePath file_path =
GetExpectedAecDumpFileName(base_file_path, render_process_id);
EXPECT_TRUE(base::PathExists(file_path));
@@ -252,19 +240,15 @@ IN_PROC_BROWSER_TEST_F(WebRtcAudioDebugRecordingsBrowserTest,
base::ThreadRestrictions::SetIOAllowed(prev_io_allowed);
}
-#if defined(OS_ANDROID)
+// Same test as CallWithAudioDebugRecordings, but does two parallel calls.
+// TODO(crbug.com/874378): Fix an re-enable test.
+// List of issues filed before this test was disabled for all platforms:
// Renderer crashes under Android ASAN: https://crbug.com/408496.
// Renderer crashes under Android: https://crbug.com/820934.
// Failures on Android M. https://crbug.com/535728.
-#define MAYBE_TwoCallsWithAudioDebugRecordings \
- DISABLED_TwoCallsWithAudioDebugRecordings
-#else
-#define MAYBE_TwoCallsWithAudioDebugRecordings TwoCallsWithAudioDebugRecordings
-#endif
-
-// Same test as CallWithAudioDebugRecordings, but does two parallel calls.
+// Flaky on Linux: https://crbug.com/871182
IN_PROC_BROWSER_TEST_F(WebRtcAudioDebugRecordingsBrowserTest,
- MAYBE_TwoCallsWithAudioDebugRecordings) {
+ DISABLED_TwoCallsWithAudioDebugRecordings) {
if (!HasAudioOutputDevices()) {
LOG(INFO) << "Missing output devices: skipping test...";
return;
diff --git a/chromium/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc b/chromium/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc
index 7b67681f34c..e68b81bb58a 100644
--- a/chromium/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc
+++ b/chromium/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc
@@ -7,6 +7,7 @@
#include "build/build_config.h"
#include "content/browser/webrtc/webrtc_content_browsertest_base.h"
#include "content/public/common/content_switches.h"
+#include "content/public/test/browser_test_utils.h"
#include "content/shell/common/shell_switches.h"
#include "media/base/media_switches.h"
#include "media/base/test_data_util.h"
@@ -108,8 +109,17 @@ IN_PROC_BROWSER_TEST_F(WebRtcCaptureFromElementBrowserTest,
MakeTypicalCall("testCanvasCapture(drawWebGL);", kCanvasCaptureTestHtmlFile);
}
+#if defined(OS_WIN)
+// https://crbug.com/869723
+// Flaky on Windows 10 with Viz (i.e. in viz_content_browsertests).
+#define MAYBE_VerifyCanvasCaptureOffscreenCanvasFrames \
+ DISABLED_VerifyCanvasCaptureOffscreenCanvasFrames
+#else
+#define MAYBE_VerifyCanvasCaptureOffscreenCanvasFrames \
+ VerifyCanvasCaptureOffscreenCanvasFrames
+#endif
IN_PROC_BROWSER_TEST_F(WebRtcCaptureFromElementBrowserTest,
- VerifyCanvasCaptureOffscreenCanvasFrames) {
+ MAYBE_VerifyCanvasCaptureOffscreenCanvasFrames) {
MakeTypicalCall("testCanvasCapture(drawOffscreenCanvas);",
kCanvasCaptureTestHtmlFile);
}
@@ -132,13 +142,10 @@ IN_PROC_BROWSER_TEST_P(WebRtcCaptureFromElementBrowserTest,
}
#endif
- MakeTypicalCall(
- base::StringPrintf("testCaptureFromMediaElement(\"%s\", %d, %d, %d);",
- GetParam().filename.c_str(),
- GetParam().has_video,
- GetParam().has_audio,
- GetParam().use_audio_tag),
- kVideoAudioHtmlFile);
+ MakeTypicalCall(JsReplace("testCaptureFromMediaElement($1, $2, $3, $4)",
+ GetParam().filename, GetParam().has_video,
+ GetParam().has_audio, GetParam().use_audio_tag),
+ kVideoAudioHtmlFile);
}
IN_PROC_BROWSER_TEST_F(WebRtcCaptureFromElementBrowserTest,
diff --git a/chromium/content/browser/webrtc/webrtc_internals.h b/chromium/content/browser/webrtc/webrtc_internals.h
index b8b0c6097c1..b2d75ad012a 100644
--- a/chromium/content/browser/webrtc/webrtc_internals.h
+++ b/chromium/content/browser/webrtc/webrtc_internals.h
@@ -187,7 +187,7 @@ class CONTENT_EXPORT WebRTCInternals : public RenderProcessHostObserver,
int lid,
size_t* index = nullptr);
- base::ObserverList<WebRTCInternalsUIObserver> observers_;
+ base::ObserverList<WebRTCInternalsUIObserver>::Unchecked observers_;
// |peer_connection_data_| is a list containing all the PeerConnection
// updates.
diff --git a/chromium/content/browser/webrtc/webrtc_video_capture_service_browsertest.cc b/chromium/content/browser/webrtc/webrtc_video_capture_service_browsertest.cc
index f632cd62a5f..032f909449b 100644
--- a/chromium/content/browser/webrtc/webrtc_video_capture_service_browsertest.cc
+++ b/chromium/content/browser/webrtc/webrtc_video_capture_service_browsertest.cc
@@ -6,7 +6,6 @@
#include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
-#include "components/viz/common/gl_helper.h"
#include "components/viz/common/gpu/context_provider.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_features.h"
@@ -46,7 +45,7 @@ namespace {
class InvokeClosureOnDelete
: public video_capture::mojom::ScopedAccessPermission {
public:
- InvokeClosureOnDelete(base::OnceClosure closure)
+ explicit InvokeClosureOnDelete(base::OnceClosure closure)
: closure_(std::move(closure)) {}
~InvokeClosureOnDelete() override { std::move(closure_).Run(); }
@@ -98,14 +97,12 @@ class TextureDeviceExerciser : public VirtualDeviceExerciser {
CHECK(context_provider_);
gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
CHECK(gl);
- auto gl_helper = std::make_unique<viz::GLHelper>(
- context_provider_->ContextGL(), context_provider_->ContextSupport());
const uint8_t kDarkFrameByteValue = 0;
const uint8_t kLightFrameByteValue = 200;
- CreateDummyRgbFrame(gl, gl_helper.get(), kDarkFrameByteValue,
+ CreateDummyRgbFrame(gl, kDarkFrameByteValue,
&dummy_frame_0_mailbox_holder_);
- CreateDummyRgbFrame(gl, gl_helper.get(), kLightFrameByteValue,
+ CreateDummyRgbFrame(gl, kLightFrameByteValue,
&dummy_frame_1_mailbox_holder_);
}
@@ -169,7 +166,6 @@ class TextureDeviceExerciser : public VirtualDeviceExerciser {
private:
void CreateDummyRgbFrame(gpu::gles2::GLES2Interface* gl,
- viz::GLHelper* gl_helper,
uint8_t value_for_all_rgb_bytes,
std::vector<gpu::MailboxHolder>* target) {
const int32_t kBytesPerRGBPixel = 3;
@@ -187,16 +183,25 @@ class TextureDeviceExerciser : public VirtualDeviceExerciser {
target->push_back(gpu::MailboxHolder());
continue;
}
- auto texture_id = gl_helper->CreateTexture();
- auto mailbox_holder =
- gl_helper->ProduceMailboxHolderFromTexture(texture_id);
+ GLuint texture_id = 0;
+ gl->GenTextures(1, &texture_id);
gl->BindTexture(GL_TEXTURE_2D, texture_id);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGB, kDummyFrameDimensions.width(),
kDummyFrameDimensions.height(), 0, GL_RGB,
GL_UNSIGNED_BYTE, dummy_frame_data.get());
gl->BindTexture(GL_TEXTURE_2D, 0);
- target->push_back(std::move(mailbox_holder));
+
+ gpu::Mailbox mailbox;
+ gl->ProduceTextureDirectCHROMIUM(texture_id, mailbox.name);
+ gpu::SyncToken sync_token;
+ gl->GenSyncTokenCHROMIUM(sync_token.GetData());
+
+ target->push_back(gpu::MailboxHolder(mailbox, sync_token, GL_TEXTURE_2D));
}
gl->ShallowFlushCHROMIUM();
CHECK_EQ(gl->GetError(), static_cast<GLenum>(GL_NO_ERROR));
diff --git a/chromium/content/browser/webui/content_web_ui_controller_factory.cc b/chromium/content/browser/webui/content_web_ui_controller_factory.cc
index 5fd3c07d4ef..23651bbbbe8 100644
--- a/chromium/content/browser/webui/content_web_ui_controller_factory.cc
+++ b/chromium/content/browser/webui/content_web_ui_controller_factory.cc
@@ -5,7 +5,6 @@
#include "content/browser/webui/content_web_ui_controller_factory.h"
#include "build/build_config.h"
-#include "content/browser/accessibility/accessibility_ui.h"
#include "content/browser/appcache/appcache_internals_ui.h"
#include "content/browser/gpu/gpu_internals_ui.h"
#include "content/browser/histograms_internals_ui.h"
@@ -38,7 +37,6 @@ WebUI::TypeID ContentWebUIControllerFactory::GetWebUIType(
url.host_piece() == kChromeUIIndexedDBInternalsHost ||
url.host_piece() == kChromeUIMediaInternalsHost ||
url.host_piece() == kChromeUIServiceWorkerInternalsHost ||
- url.host_piece() == kChromeUIAccessibilityHost ||
url.host_piece() == kChromeUIAppCacheInternalsHost ||
url.host_piece() == kChromeUINetworkErrorsListingHost ||
url.host_piece() == kChromeUIProcessInternalsHost) {
@@ -74,8 +72,6 @@ ContentWebUIControllerFactory::CreateWebUIControllerForURL(
return std::make_unique<IndexedDBInternalsUI>(web_ui);
if (url.host_piece() == kChromeUIMediaInternalsHost)
return std::make_unique<MediaInternalsUI>(web_ui);
- if (url.host_piece() == kChromeUIAccessibilityHost)
- return std::make_unique<AccessibilityUI>(web_ui);
if (url.host_piece() == kChromeUIServiceWorkerInternalsHost)
return std::make_unique<ServiceWorkerInternalsUI>(web_ui);
if (url.host_piece() == kChromeUINetworkErrorsListingHost)
diff --git a/chromium/content/browser/webui/url_data_manager.cc b/chromium/content/browser/webui/url_data_manager.cc
index ce87d5984c0..fca1d4aa616 100644
--- a/chromium/content/browser/webui/url_data_manager.cc
+++ b/chromium/content/browser/webui/url_data_manager.cc
@@ -6,6 +6,7 @@
#include <stddef.h>
+#include <utility>
#include <vector>
#include "base/bind.h"
@@ -128,9 +129,10 @@ void URLDataManager::DeleteDataSource(const URLDataSourceImpl* data_source) {
// static
void URLDataManager::AddDataSource(BrowserContext* browser_context,
- URLDataSource* source) {
- GetFromBrowserContext(browser_context)->
- AddDataSource(new URLDataSourceImpl(source->GetSource(), source));
+ std::unique_ptr<URLDataSource> source) {
+ std::string name = source->GetSource();
+ GetFromBrowserContext(browser_context)
+ ->AddDataSource(new URLDataSourceImpl(name, std::move(source)));
}
// static
diff --git a/chromium/content/browser/webui/url_data_manager.h b/chromium/content/browser/webui/url_data_manager.h
index 5ceb74d411f..95cff69e1b4 100644
--- a/chromium/content/browser/webui/url_data_manager.h
+++ b/chromium/content/browser/webui/url_data_manager.h
@@ -57,7 +57,7 @@ class CONTENT_EXPORT URLDataManager : public base::SupportsUserData::Data {
// |URLDataManager|. Creates a URLDataSourceImpl to wrap the given
// source.
static void AddDataSource(BrowserContext* browser_context,
- URLDataSource* source);
+ std::unique_ptr<URLDataSource> source);
// Adds a WebUI data source to |browser_context|'s |URLDataManager|.
static void AddWebUIDataSource(BrowserContext* browser_context,
diff --git a/chromium/content/browser/webui/url_data_manager_backend.cc b/chromium/content/browser/webui/url_data_manager_backend.cc
index 80f12df9d42..9a2cb49cf5a 100644
--- a/chromium/content/browser/webui/url_data_manager_backend.cc
+++ b/chromium/content/browser/webui/url_data_manager_backend.cc
@@ -8,12 +8,9 @@
#include <utility>
#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/compiler_specific.h"
-#include "base/debug/alias.h"
-#include "base/lazy_instance.h"
#include "base/location.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/ref_counted_memory.h"
#include "base/single_thread_task_runner.h"
@@ -21,7 +18,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "content/browser/blob_storage/chrome_blob_storage_context.h"
@@ -267,13 +264,24 @@ std::unique_ptr<net::SourceStream> URLRequestChromeJob::SetUpSourceStream() {
void URLRequestChromeJob::MimeTypeAvailable(const std::string& mime_type) {
mime_type_ = mime_type;
- NotifyHeadersComplete();
}
void URLRequestChromeJob::DataAvailable(base::RefCountedMemory* bytes) {
TRACE_EVENT_ASYNC_END0("browser", "DataManager:Request", this);
DCHECK(!data_);
+ if (bytes)
+ set_expected_content_size(bytes->size());
+
+ // We notify headers are complete unusually late for these jobs, because we
+ // need to have |bytes| first to report an accurate expected content size.
+ // Otherwise, we cannot support <video> streaming.
+ NotifyHeadersComplete();
+
+ // The job can be cancelled after sending the headers.
+ if (is_done())
+ return;
+
// All further requests will be satisfied from the passed-in data.
data_ = bytes;
if (!bytes)
@@ -416,9 +424,8 @@ class ChromeProtocolHandler
URLDataManagerBackend::URLDataManagerBackend()
: next_request_id_(0), weak_factory_(this) {
URLDataSource* shared_source = new SharedResourcesDataSource();
- URLDataSourceImpl* source_impl =
- new URLDataSourceImpl(shared_source->GetSource(), shared_source);
- AddDataSource(source_impl);
+ AddDataSource(new URLDataSourceImpl(shared_source->GetSource(),
+ base::WrapUnique(shared_source)));
}
URLDataManagerBackend::~URLDataManagerBackend() = default;
@@ -500,7 +507,6 @@ bool URLDataManagerBackend::StartRequest(const net::URLRequest* request,
if (mime_type == "text/html")
job->SetSource(source);
- // Also notifies that the headers are complete.
job->MimeTypeAvailable(mime_type);
// Look up additional request info to pass down.
@@ -589,8 +595,8 @@ scoped_refptr<net::HttpResponseHeaders> URLDataManagerBackend::GetHeaders(
// Set the headers so that requests serviced by ChromeURLDataManager return a
// status code of 200. Without this they return a 0, which makes the status
// indistiguishable from other error types. Instant relies on getting a 200.
- scoped_refptr<net::HttpResponseHeaders> headers(
- new net::HttpResponseHeaders("HTTP/1.1 200 OK"));
+ auto headers =
+ base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK");
if (!source_impl)
return headers;
diff --git a/chromium/content/browser/webui/url_data_source_impl.cc b/chromium/content/browser/webui/url_data_source_impl.cc
index 47c2ae68868..1a38e0b9c1d 100644
--- a/chromium/content/browser/webui/url_data_source_impl.cc
+++ b/chromium/content/browser/webui/url_data_source_impl.cc
@@ -16,8 +16,8 @@
namespace content {
URLDataSourceImpl::URLDataSourceImpl(const std::string& source_name,
- URLDataSource* source)
- : source_name_(source_name), backend_(nullptr), source_(source) {}
+ std::unique_ptr<URLDataSource> source)
+ : source_name_(source_name), source_(std::move(source)) {}
URLDataSourceImpl::~URLDataSourceImpl() {
}
diff --git a/chromium/content/browser/webui/url_data_source_impl.h b/chromium/content/browser/webui/url_data_source_impl.h
index 62cbd439883..56f0aea4546 100644
--- a/chromium/content/browser/webui/url_data_source_impl.h
+++ b/chromium/content/browser/webui/url_data_source_impl.h
@@ -52,10 +52,9 @@ struct DeleteURLDataSource {
class URLDataSourceImpl : public base::RefCountedThreadSafe<
URLDataSourceImpl, DeleteURLDataSource> {
public:
- // See source_name_ below for docs on that parameter. Takes ownership of
- // |source|.
+ // See |source_name_| below for docs on that parameter.
URLDataSourceImpl(const std::string& source_name,
- URLDataSource* source);
+ std::unique_ptr<URLDataSource> source);
// Report that a request has resulted in the data |bytes|.
// If the request can't be satisfied, pass NULL for |bytes| to indicate
diff --git a/chromium/content/browser/webui/web_ui_data_source_impl.cc b/chromium/content/browser/webui/web_ui_data_source_impl.cc
index 5dad37af6f2..46f56be78db 100644
--- a/chromium/content/browser/webui/web_ui_data_source_impl.cc
+++ b/chromium/content/browser/webui/web_ui_data_source_impl.cc
@@ -8,6 +8,8 @@
#include <stdint.h>
#include <string>
+#include <utility>
+#include <vector>
#include "base/bind.h"
#include "base/logging.h"
@@ -105,7 +107,8 @@ class WebUIDataSourceImpl::InternalDataSource : public URLDataSource {
};
WebUIDataSourceImpl::WebUIDataSourceImpl(const std::string& source_name)
- : URLDataSourceImpl(source_name, new InternalDataSource(this)),
+ : URLDataSourceImpl(source_name,
+ std::make_unique<InternalDataSource>(this)),
source_name_(source_name),
default_resource_(-1),
add_csp_(true),
diff --git a/chromium/content/browser/webui/web_ui_mojo_browsertest.cc b/chromium/content/browser/webui/web_ui_mojo_browsertest.cc
index d8ab9ec2be1..3f4031598fa 100644
--- a/chromium/content/browser/webui/web_ui_mojo_browsertest.cc
+++ b/chromium/content/browser/webui/web_ui_mojo_browsertest.cc
@@ -45,7 +45,7 @@ namespace {
bool g_got_message = false;
base::FilePath GetFilePathForJSResource(const std::string& path) {
- base::ThreadRestrictions::ScopedAllowIO allow_io_from_test_callbacks;
+ base::ScopedAllowBlockingForTesting allow_blocking;
std::string binding_path = "gen/" + path;
#if defined(OS_WIN)
@@ -60,7 +60,7 @@ base::FilePath GetFilePathForJSResource(const std::string& path) {
// up the generated file from disk and returns it.
bool GetResource(const std::string& id,
const WebUIDataSource::GotDataCallback& callback) {
- base::ThreadRestrictions::ScopedAllowIO allow_io_from_test_callbacks;
+ base::ScopedAllowBlockingForTesting allow_blocking;
std::string contents;
if (base::EndsWith(id, ".mojom.js", base::CompareCase::SENSITIVE)) {
@@ -274,7 +274,7 @@ bool IsGeneratedResourceAvailable(const std::string& resource_path) {
// files. If the bindings file doesn't exist assume we're on such a bot and
// pass.
// TODO(sky): remove this conditional when isolates support copying from gen.
- base::ThreadRestrictions::ScopedAllowIO allow_io_for_file_existence_check;
+ base::ScopedAllowBlockingForTesting allow_blocking;
const base::FilePath test_file_path(GetFilePathForJSResource(resource_path));
if (base::PathExists(test_file_path))
return true;
diff --git a/chromium/content/browser/webui/web_ui_url_loader_factory.cc b/chromium/content/browser/webui/web_ui_url_loader_factory.cc
index 653e22e0ee5..a0e39809838 100644
--- a/chromium/content/browser/webui/web_ui_url_loader_factory.cc
+++ b/chromium/content/browser/webui/web_ui_url_loader_factory.cc
@@ -13,7 +13,7 @@
#include "base/memory/ref_counted_memory.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_piece.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "content/browser/bad_message.h"
#include "content/browser/blob_storage/blob_internals_url_loader.h"
#include "content/browser/blob_storage/chrome_blob_storage_context.h"
diff --git a/chromium/content/browser/zoom_browsertest.cc b/chromium/content/browser/zoom_browsertest.cc
index 6c653819f2c..7d776641853 100644
--- a/chromium/content/browser/zoom_browsertest.cc
+++ b/chromium/content/browser/zoom_browsertest.cc
@@ -95,13 +95,12 @@ double GetMainframeWindowBorder(const ToRenderFrameHost& adapter) {
}
double GetMainFrameZoomFactor(const ToRenderFrameHost& adapter, double border) {
- const char kGetMainFrameZoomLevel[] =
- "window.domAutomationController.send("
- "(window.outerWidth - %f)/window.innerWidth"
- ");";
double zoom_factor;
EXPECT_TRUE(ExecuteScriptAndExtractDouble(
- adapter, base::StringPrintf(kGetMainFrameZoomLevel, border),
+ adapter,
+ JsReplace("window.domAutomationController.send("
+ " (window.outerWidth - $1) / window.innerWidth);",
+ border),
&zoom_factor));
return zoom_factor;
}